安全增强型 Linux(SELinux)是一种采用安全架构的Linux系统,它能够让管理员更好地管控哪些人可以访问系统。它最初是作为Linux内核的一系列补丁,由美国国家安全局(NSA)利用Linux安全模块(LSM)开发而成。

自主访问控制与强制访问控制

自主访问控制(DAC:Discretionary Access Control)

系统会识别用户,然后根据被操作对象(Subject)的权限控制列表(ACL: Access Control List)或者权限控制矩阵(ACL: Access Control Matrix)的信息来决定用户的是否能对其进行哪些操作,例如读取或修改。而拥有对象权限的用户,又可以将该对象的权限分配给其他用户,所以称之为“自主(Discretionary)”控制。这种设计最常见的应用就是文件系统的权限设计,如微软的NTFS。DAC最大缺陷就是对权限控制比较分散,不便于管理,比如无法简单地将一组文件设置统一的权限开放给指定的一群用户。

自主访问控制的缺点

  • root拥有最高权限:如果某进程被黑客获取,且该进程拥有root权限,那么便可以在系统上对任意文件进行读取。
  • 使用者可以取得程序来变更文件的权限:如果你不小心将某个目录的权限设定为777,由于对任何人的权限会变成rwx ,因此该目录就会被任何人所任意存取!

强制访问控制(MAC:Mandatory Access Control)

MAC是为了弥补DAC权限控制过于分散的问题而诞生的。在MAC的设计中,每一个对象都都有一些权限标识,每个用户同样也会有一些权限标识,而用户能否对该对象进行操作取决于双方的权限标识的关系,这个限制判断通常是由系统硬性限制的。比如在影视作品中我们经常能看到特工在查询机密文件时,屏幕提示需要“无法访问,需要一级安全许可”,这个例子中,文件上就有“一级安全许可”的权限标识,而用户并不具有。
MAC又细分为了两种方式,一种叫类别安全(MCS)模式,另一种叫多级安全(MLS)模式,下文中使用的均为MCS模式

  • 以Apache服务为例,可以看到,在DAC模式下,只要相应目录有相应用户的权限,就可以被访问。而在MAC模式下,还要受进程允许访问目录范围的限制。

DAC&MAC

简单来说。DAC的访问控制主体为用户,客体为文件;MAC主体为进程,客体为文件。


SELinux的工作原理

SELinux定义了每个人对系统上的应用、进程和文件的访问权限。它利用安全策略(一组告知 SELinux 哪些能访问,哪些不能访问的规则)来强制执行策略所允许的访问。

  • 主体(Subject):
    SELinux主要想要管理的就是程序,访问控制主体为进程;
  • 目标(Object):
    主体程序能否存取的“目标资源”一般就是文件系统,访问控制客体为文件;
  • 策略(Policy):
    由于程序与文件数量庞大,因此SELinux会依据某些服务来制订基本的存储安全性策略。这些策略内还会有详细的规则(rule) 来指定不同的服务开放某些资源的存取与否。在目前的CentOS 7.x 里面仅有提供三个主要的策略,分别是:
    • targeted:针对网路服务限制较多,针对本机限制较少,是预设的策略;
    • minimum:由target 修订而来,仅针对选择的程序来保护;
    • mls:完整的SELinux限制,限制方面较为严格,配置难度也非常大;一般不用,除非对安全性有极高的要求。建议使用预设的targeted 策略即可。
  • 安全性本文(security context):
    我们刚刚谈到了主体、目标与策略,但是主体能不能存取目标除了策略指定之外,主体与目标的安全性本文必须一致才能够顺利存取。 这个安全性本文(security context) 有点类似文件系统的rwx啦!安全性本文的内容与设定是非常重要的!如果设定错误,你的某些服务(主体程序)就无法存取文件系统(目标资源),当然就会一直出现“权限不符”的错误讯息了!

安全性文本的结构与含义

  • 安全性文本有四个字段,以“:”隔开,如system_u:object_r:admin_home_t:s0
  • 身份识别(Identify),主要为两类:

    • unconfined_u:不受限的用户,也就是说,该文件来自于不受限的程序所产生的!一般来说,我们使用可登录帐号来取得bash之后,预设的bash环境是不受SELinux管制的~因为bash并不是什么特别的网路服务!因此,在这个不受SELinux所限制的bash程序所产生的文件,其身份识别大多就是unconfined_u这个『不受限』用户啰!
    • system_u:系统用户,大部分就是系统自己产生的文件。
  • 角色(Role)

    • object_r:代表的是文件或目录等资源,这应该是最常见的;
    • system_r:代表的就是程序啦!不过,一般使用者也会被指定成为system_r喔!
      结尾的r就是角色的意思。
  • 类型(Type),最重要:
    在预设的targeted策略中,Identify与Role基本上是不重要的!重要的在于这个类型(type)!基本上,一个主体程序能不能读取到这个文件资源,与类型有关!而类型在文件与程序的定义不太相同,分别是:

    • type:在文件资源(Object)上面称为类型(Type);
    • domain:在主体程序(Subject)则称为领域(domain)了!
      domain需要与type搭配,则该程序才能够顺利的读取文件资源啦!
  • 级别(Level)
    MLS安全级别,仅在MLS模式下有效


SElinux工作模式

Selinux有三种工作模式:

  • enforcing(强制模式):代表SELinux运作中,且已经正确的开始限制domain/type了
  • permissive(宽容模式):代表SELinux运作中,不过仅会有警告讯息并不会实际限制domain/type的,但会进行日志记录。这种模式可以运来作为SELinux的debug之用;
  • disabled:关闭模式。

所有主体(即程序)先匹配selinux策略(MAC),然后在匹配文件读写权限(RWX,DAC),最后再执行,过程如下图:
selinux工作模式

在targeted策略下,只有第三个字段type(类型)实际有效


SElinux配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
more /etc/selinux/config 

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=enforcing # 当前工作模式
# SELINUXTYPE= can take one of three values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted # 当前策略类型

注意,encforing或permissive模式可在线切换,关闭或开启selinux需要重新启动操作系统


selinux相关命令

selinux模式切换

1
2
3
setenforce [0|1]
#0:转成permissive宽容模式;
#1:转成Enforcing强制模式

查看selinux状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
getenforce # 查看当前selinux处于何种工作模式
sestatus # 查看当前selinux服务状态
sestatus -v # 检查列于/etc/sestatus.conf内的文件与程序的安全性本文内容;
sestatus -b # 将目前策略的规则布林值列出,亦即某些规则(rule)是否要启动(0/1)之意;
getsebool -a # 查看所有selinux规则状态,同sestatus -b

# 需要安装setools-console-*,执行命令yum install settools-console-*
seinfo [-trub]
# --all:列出SELinux的状态、规则布林值、身份识别、角色、类别等所有资讯
# -u:列出SELinux的所有身份识别(user)种类
# -r:列出SELinux的所有角色(role)种类
# -t:列出SELinux的所有类别(type)种类
# -b:列出所有规则的种类(布林值)

sesearch [-A] [-s 主体类别] [-t 目标类别] [-b 布林值]
# -A:列出后面资料中,允许『读取或放行』的相关资料
# -t:后面还要接类别,例如-t httpd_t
# -b:后面还要接SELinux的规则,例如-b httpd_enable_ftp_server

查看安全标记,Z

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 查看文件
ls -lZ /etc/passwd /etc/shadow /home/git/test /root/test
-rw-r--r--. root root system_u:object_r:passwd_file_t:s0 /etc/passwd
----------. root root system_u:object_r:shadow_t:s0 /etc/shadow
-rw-rw-r--. git git unconfined_u:object_r:user_home_t:s0 /home/git/test
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 /root/test

# 查看服务
netstat -nltpZ
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name Security Context
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 5243/nginx: master system_u:system_r:httpd_t:s0
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1045/sshd system_u:system_r:sshd_t:s0-s0:c0.c1023
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 5243/nginx: master system_u:system_r:httpd_t:s0
tcp6 0 0 :::2222 :::* LISTEN 1457/docker-proxy system_u:system_r:unconfined_service_t:s0
tcp6 0 0 :::81 :::* LISTEN 1589/docker-proxy system_u:system_r:unconfined_service_t:s0

# 查看程序
ps -eZ
LABEL PID TTY TIME CMD
system_u:system_r:init_t:s0 1 ? 00:00:17 systemd
system_u:system_r:kernel_t:s0 2 ? 00:00:00 kthreadd
system_u:system_r:syslogd_t:s0 359 ? 00:00:04 systemd-journal
system_u:system_r:udev_t:s0-s0:c0.c1023 394 ? 00:00:00 systemd-udevd
system_u:system_r:kernel_t:s0 485 ? 00:00:00 nfit
system_u:system_r:auditd_t:s0 511 ? 00:00:00 auditd
system_u:system_r:systemd_logind_t:s0 533 ? 00:00:04 systemd-logind
system_u:system_r:unconfined_service_t:s0 534 ? 00:00:00 CmsGoAgent.linu
system_u:system_r:policykit_t:s0 535 ? 00:00:02 polkitd
system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 536 ? 00:00:07 dbus-daemon
system_u:system_r:unconfined_service_t:s0 542 ? 00:01:43 assist_daemon
system_u:system_r:unconfined_service_t:s0 577 ? 00:25:45 exe
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 735 ? 00:00:00 sshd
system_u:system_r:unconfined_service_t:s0 1040 ? 00:09:31 aliyun-service
system_u:system_r:unconfined_service_t:s0 1041 ? 00:41:38 dockerd
system_u:system_r:syslogd_t:s0 1043 ? 00:00:29 rsyslogd
system_u:system_r:sshd_t:s0-s0:c0.c1023 1045 ? 00:00:00 sshd
system_u:system_r:crond_t:s0-s0:c0.c1023 1063 ? 00:00:00 atd
system_u:system_r:crond_t:s0-s0:c0.c1023 1072 ? 00:00:01 crond
system_u:system_r:getty_t:s0-s0:c0.c1023 1079 tty1 00:00:00 agetty
system_u:system_r:unconfined_service_t:s0 1094 ? 00:32:59 docker-containe
system_u:system_r:getty_t:s0-s0:c0.c1023 1381 ttyS0 00:00:00 agetty
system_u:system_r:kernel_t:s0 2190 ? 00:00:00 dio/vda1
system_u:system_r:kernel_t:s0 2315 ? 00:00:00 kworker/1:0
system_u:system_r:kernel_t:s0 2318 ? 00:00:00 kworker/0:1
system_u:system_r:httpd_t:s0 5243 ? 00:00:00 nginx
...

selinux设置命令

selinux相关命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
setsebool [-P] 『规则名称』 [0|1]
#-P:直接将设定值写入配置文件,该设定资料未来会生效的!

#手动修改SELinux type
chcon [-R] [-t type] [-u user] [-r role] 文件
chcon [-R] --reference=范例文件
#-R:连同该目录下的次目录也同时修改;
#-t:后面接安全性本文的类型栏位!例如httpd_sys_content_t;
#-u:后面接身份识别,例如system_u;(不重要)
#-r:后面接角色,例如system_r;(不重要)
#-v:若有变化成功,请将变动的结果列出来
#--reference=范例:拿某个文件当范例来修改后续接的文件的类型!

#使用restorecon让文件恢复正确的SELinux type
restorecon [-Rv] 文件或目录
#-R:连同次目录一起修改;
#-v:将过程显示到屏幕上

semanage

安装semanage工具
1
yum -y install policycoreutils-python
1
2
3
4
5
6
7
8
9
10
# semanage预设目录的安全性本文查询与修改
semanage {login|user|port|interface|fcontext|translation} -l
semanage fcontext -{a|d|m} [-frst] file_spec
# fcontext:主要用在安全性本文方面的用途,-l为查询的意思;
# -a:增加的意思,你可以增加一些目录的预设安全性本文类型设定;
# -m:修改的意思;
# -d:删除的意思。
# -t:添加类型
# -p: 指定添加的端口是tcp或udp协议的,port子命令下使用
# -e: 目标路径参考原路径的上下文类型,fcontext子命令下使用
示例
1
2
3
4
5
6
7
8
9
10
11
12
13
# 列出所有端口
semanage port -l
# 查看自定义的端口
semanage port -lC
# 创建端口
semanage port -a -t ssh_port_t -p tcp 2222
semanage port -a -t http_port_t -p tcp 8888
semanage port -a -t http_port_t -p tcp 11180-11188
# 删除端口
semanage port -d -t ssh_port_t -p tcp 2222
semanage port -d -t http_port_t -p tcp 11180-11188
# 修改文件夹预设值
semanage fcontext -a -t system_cron_spool_t "/srv/mycron(/.*)?"

selinux实例

在自己设备上开启selinux,nginx服务down机,查找相关日志如下,因为密钥放在家目录下,nginx服务无法读取

1
Feb 17 15:10:44 yuanlichenai nginx: nginx: [emerg] cannot load certificate "/home/cert/jumpserver.yuanlichenai.cn.crt": BIO_new_file() failed (SSL: error:0200100D:system library:fopen:Permission denied:fopen('/home/cert/jumpserver.yuanlichenai.cn.crt','r') error:2006D002:BIO routines:BIO_new_file:system lib)

迁移文件并通过restorecon命令重设权限后nginx正常运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ll -Z /home/ssl /etc/nginx/ssl/
/etc/nginx/ssl/:
-rw-r--r--. root root unconfined_u:object_r:httpd_config_t:s0 jms.yuanlichenai.cn.crt
-rw-r--r--. root root unconfined_u:object_r:httpd_config_t:s0 jms.yuanlichenai.cn.key
-rw-r--r--. root root unconfined_u:object_r:httpd_config_t:s0 mellow.yuanlichenai.cn.crt
-rw-r--r--. root root unconfined_u:object_r:httpd_config_t:s0 mellow.yuanlichenai.cn.key
-rw-r--r--. root root unconfined_u:object_r:httpd_config_t:s0 yuanlichenai.cn.crt
-rw-r--r--. root root unconfined_u:object_r:httpd_config_t:s0 yuanlichenai.cn.key

/home/ssl:
-rw-r--r--. root root unconfined_u:object_r:user_home_t:s0 jms.yuanlichenai.cn.crt
-rw-r--r--. root root unconfined_u:object_r:user_home_t:s0 jms.yuanlichenai.cn.key
-rw-r--r--. root root unconfined_u:object_r:user_home_t:s0 mellow.yuanlichenai.cn.crt
-rw-r--r--. root root unconfined_u:object_r:user_home_t:s0 mellow.yuanlichenai.cn.key
-rw-r--r--. root root unconfined_u:object_r:user_home_t:s0 yuanlichenai.cn.crt
-rw-r--r--. root root unconfined_u:object_r:user_home_t:s0 yuanlichenai.cn.key


参考:

第十六章、程序管理與 SELinux 初探
selinux是什么
权限系统设计模型分析(DAC,MAC,RBAC,ABAC)