SELinux(Security Enhanced Linux) 是在进行进程、文件等细部权限设定依据的一个核心模块, 由于启动网 络服务的也是进程,因此也能够控制网络服务能否存取系统资源。
SELinux 是透过 MAC 的方式来控管进程,他控制的主体是进程, 而目标则 是该进程能否读取的文件资源。MAC(委任式访问控制)可以针对特定的进程与特定的文件资源来进行权限的控管。 即使你是 root ,那么在使用不同的进程时,你所能取得的权限并不一定是 root , 而得要 看当时该进程的设定而定。主要名词和含义如下:
图片解释:
- 主体进程必须要通过 SELinux 政策内的规则放行后,就可以与目标资源进行安全性本文的比对
- 若比对失败 则无法存取目标,若比对成功则可以开始存取目标问题是
- 最终能否存取目标还是与文件系统的 rwx 权限设定有关
CentOS 7.x 的 target 政策已经帮我们制订好非常多的规则了,因此你只要知道如何开启/关闭某项规则的放行与否即可。 但可能需要自行配置文件的安全性本文, 安全性文本类似文件系统的 rwx 的设定。安全性本文存在于主体进程中与目标文件资源中。安全性本文是放置到文件的 inode 内。
因此主体进程想要读取目标文件资源时,同样需要读取 inode。
使用 ls -Z fileordic
观察安全性文本:
[root@study ~]# ls -Z
-rw-------. root root system_u:object_r:admin_home_t:s0 anaconda-ks.cfg
-rw-r--r--. root root system_u:object_r:admin_home_t:s0 initial-setup-ks.cfg
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 regular_express.txt
安全性本文主要用冒号分为三个字段,这三个字段的意义为: Identify:role:type (身份识别:角色:类型)。
查看进程的 SELinux 相关信息:
[root@study ~]# ps -eZ
LABEL PID TTY TIME CMD
system_u:system_r:init_t:s0 1 ? 00:00:03 systemd
system_u:system_r:kernel_t:s0 2 ? 00:00:00 kthreadd
system_u:system_r:kernel_t:s0 3 ? 00:00:00 ksoftirqd/0 .....(中间省略).....
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 31513 ? 00:00:00 sshd
基本上进程主要就分为两大类,一种是系统有受限的 system_u:system_r,另一种则可能是用户自己的比较不受限的进程 (通常是本机用户自己执行的程序),亦即是 unconfined_u:unconfined_r 这两种。
预设的 target 政策下,其实最重要的字段是类型字段 (type), 主体与目标之间是 否具有可以读写的权限,与进程的 domain 及文件的 type 有关,以 crond 以及他的配置文件来说明: /usr/sbin/crond, /etc/crontab, /etc/cron.d 等文件来说明。
# 1. 先看看 crond 这个『进程』的安全本文内容:
[root@study ~]# ps -eZ | grep cron
system_u:system_r:crond_t:s0-s0:c0.c1023 1338 ? 00:00:01 crond
system_u:system_r:crond_t:s0-s0:c0.c1023 1340 ? 00:00:00 atd # 这个安全本文的类型名称为 crond_t 格式!
# 2. 再来瞧瞧执行档、配置文件等等的安全本文内容为何!
[root@study ~]# ll -Zd /usr/sbin/crond /etc/crontab /etc/cron.d
drwxr-xr-x. root root system_u:object_r:system_cron_spool_t:s0 /etc/cron.d
-rw-r--r--. root root system_u:object_r:system_cron_spool_t:s0 /etc/crontab
-rwxr-xr-x. root root system_u:object_r:crond_exec_t:s0 /usr/sbin/crond
执行 /usr/sbin/crond 之后,这个程序变成的进程的 domain 类型会是 crond_t,而这个 crond_t 能够读取的配置文件则 只能 为 system_cron_spool_t 这种的类型。因此不论 /etc/crontab, /etc/cron.d 以及 /var/spool/cron 都会是相关的 SELinux 类型 (/var/spool/cron 为 user_cron_spool_t)。
范例:
# 1. 先假设你因为不熟的缘故,因此是在『root 家目录』建立一个如下的 cron 设定:
[root@study ~]# vim checktime
10 * * * * root sleep 60s
# 2. 检查后才发现文件放错目录了,又不想要保留副本,因此使用 mv 移动到正确目录:
[root@study ~]# mv checktime /etc/cron.d
[root@study ~]# ll /etc/cron.d/checktime
-rw-r--r--. 1 root root 27 Aug 7 18:41 /etc/cron.d/checktime
# 仔细看喔,权限是 644 ,确定没有问题!任何进程都能够读取喔!
# 3. 强制重新启动 crond ,然后偷看一下登录档,看看有没有问题发生!
[root@study ~]# systemctl restart crond
[root@study ~]# tail /var/log/cron
Aug 7 18:46:01 study crond[28174]: ((null)) Unauthorized SELinux context=system_u:system_r:
739
system_cronjob_t:s0-s0:c0.c1023 file_context=unconfined_u:object_r:admin_home_t:s0
(/etc/cron.d/checktime)
Aug 7 18:46:01 study crond[28174]: (root) FAILED (loading cron table)
# 上面的意思是,有错误!因为原本的安全本文与文件的实际安全本文无法搭配的缘故
SELinux 依据启动与否,共有三种模式:
如图所示:
相关解释:
- 首先并不是所有的进程都会被 SELinux 所管制,因此最左边会出现 一个的『有受限的进程主体』,那如何观察有没有受限 (confined )呢? 通过 ps -eZ 去查看,如果显示type/domain 为 unconfined_t 则其不受限,否则则受限
- 如果是 Disabled 的模式,那么 SELinux 将不会运作,受限的进程也不会经过 SELinux ,也是直接去判断 rwx
- 如果是宽容 (permissive) 模式,这种模式也是不会将主体进程抵挡 (所以图中箭头是可以直接穿透的),如果没有通过政策规则,或者是安全本文的比对时,那么该读写动作将会被纪录起来 (log),可作为未来检查问题的判断依据
- Enforcing 模式,就是实际将受限主体进入规则比对、安全本文比对的流程,若失败,就直接抵挡主体进程的读写行为,并且将他记录下来。 如果没问题,才进入到 rwx 权限的判断
通过 getenforce
查看 SELinux 的模式,通过 sestatus
查看 SELinux的政策:
[root@centos764 ~]# getenforce
Enforcing # 显示出目前的模式为 Enforcing
[root@centos764 ~]# sestatus [-vb]
# 选项与参数:
# -v :检查列于 /etc/sestatus.conf 内的文件与进程的安全性本文内容;
# -b :将目前政策的规则布尔值列出,亦即某些规则 (rule) 是否要启动 (0/1) 之意;
[root@centos764 ~]# sestatus
SELinux status: enabled # <==是否启动 SELinux
SELinuxfs mount: /sys/fs/selinux # <==SELinux 的相关文件数据挂载点
SELinux root directory: /etc/selinux # <==SELinux 的根目录所在
Loaded policy name: targeted # <==目前的政策
Current mode: enforcing
Mode from config file: enforcing # <==目前的模式
Policy MLS status: enabled # <==是否含有 MLS 的模式机制
Policy deny_unknown status: allowed # <==是否预设抵挡未知的主体进程
Max kernel policy version: 31
SELinux 的配置文件是 /etc/selinux/config。
改变了政策需要重新启动;如果模式由 enforcing 或 permissive 改成 disabled ,或由 disabled 改成其他两个,那也必须要重新启动。如果从 disable 转到启动 SELinux 的模式时, 由于系统必须要针对文件写入安全性本文的信息,因此开机过程会花费不少时间在等待重新写入 SELinux 安全性本文 (有时也称为 SELinux Label) ,而且在写完之后还得要再次的重新启动一次。
如果已经在 Enforcing 的模式,但是可能由于一些设定的问题导致 SELinux 让某些服务无法正常的运作, 此时你可以将 Enforcing 的模式改为宽容 (permissive) 的模式,让 SELinux 只会警告无法顺利联机的讯息, 而不是直接抵挡主体进程的读取权限。让 SELinux 模式在 enforcing 与 permissive 之间切换的方法为:
[root@centos764 ~]# setenforce [0|1]
选项与参数:
0 :转成 permissive 宽容模式;
1 :转成 Enforcing 强制模式
# 将 SELinux 在 Enforcing 与 permissive 之间切换与观察
[root@centos764 ~]# setenforce 0
[root@centos764 ~]# getenforce
Permissive
[root@centos764 ~]# setenforce 1
[root@centos764 ~]# getenforce
Enforcing
setenforce
无法在 Disabled 的模式底下进行模式的切换。
在某些特殊的情况底下,从 Disabled 切换成 Enforcing 之后,有一堆服务无法
顺利启动,都会跟你说在 /lib/xxx 里面的数据没有权限读取,所以启动失败。这大多是由于在重新写入 SELinux type (Relabel) 出错,使用 Permissive 就没有这个错误。那如何处理呢?最简单的方法就是在 Permissive 的状态下, 使用restorecon -Rv /
重新还原所有 SELinux 的类型,就能够处理这个错误。
SELinux 的三种模式是会影响到主体进程的放行与否。 如果是进入 Enforcing 模式,那么接着下来会影响到主体进程的是target 政策内的各项规则 (rules),使用 getsebool
查看当前政策内的规则。
查询系统上面全部规则的启动与否 (on/off,亦即布尔值),通过 setastus -b 或 getsebool -a 均可:
[root@study ~]# getsebool [-a] [规则的名称]
选项与参数:
-a :列出目前系统上面的所有 SELinux 规则的布尔值为开启或关闭值
# 查询本系统内所有的布尔值设定状况
[root@study ~]# getsebool -a
abrt_anon_write --> off
abrt_handle_event --> off
....(中间省略)....
cron_can_relabel --> off # 这个跟 cornd 比较有关
cron_userdomain_transition --> on
....(中间省略)....
httpd_enable_homedirs --> off # 这当然就是跟网页,亦即 http 有关
....(底下省略)....
使用 seinfo
等命令查看 SELinux内的规则限制的内容(默认不安装,使用命令 yum install setools
安装)。命令格式:
[root@study ~]# seinfo [-Atrub]
选项与参数:
-A :列出 SELinux 的状态、规则布尔值、身份识别、角色、类别等所有信息
-u :列出 SELinux 的所有身份识别 (user) 种类
-r :列出 SELinux 的所有角色 (role) 种类
-t :列出 SELinux 的所有类别 (type) 种
我们知道 crond 这个进程的 type 是 crond_t (通过 ps -eZ | grep crond
得到), 查找 crond_t 能够读取的文件 SELinux type :
[root@study ~]# sesearch [-A] [-s 主体类别] [-t 目标类别] [-b 布尔值]
选项与参数:
-A :列出后面数据中,允许『读取或放行』的相关数据
-t :后面还要接类别,例如 -t httpd_t
-b :后面还要接 SELinux 的规则,例如 -b httpd_enable_ftp_server
# 找出 crond_t 这个主体进程能够读取的文件 SELinux type
[root@study ~]# sesearch -A -s crond_t | grep spool
allow crond_t system_cron_spool_t : file { ioctl read write create getattr ..
allow crond_t system_cron_spool_t : dir { ioctl read getattr lock search op..
allow crond_t user_cron_spool_t : file { ioctl read write create getattr se..
allow crond_t user_cron_spool_t : dir { ioctl read write getattr lock add_n..
allow crond_t user_cron_spool_t : lnk_file { read getattr } ;
# allow 后面接主体进程以及文件的 SELinux type,上面的数据是撷取出来的,
# 意思是说,crond_t 可以读取 system_cron_spool_t 的文件/目录类型~等等!
# 找出 crond_t 是否能够读取 /etc/cron.d/checktime 这个我们自定义的配置文件
[root@study ~]# ll -Z /etc/cron.d/checktime
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 /etc/cron.d/checktime
# 两个重点,一个是 SELinux type 为 admin_home_t,一个是文件 (file)
[root@study ~]# sesearch -A -s crond_t | grep admin_home_t
allow domain admin_home_t : dir { getattr search open } ;
allow domain admin_home_t : lnk_file { read getattr } ;
allow crond_t admin_home_t : dir { ioctl read getattr lock search open } ;
allow crond_t admin_home_t : lnk_file { read getattr } ;
# 仔细看!看仔细~虽然有 crond_t admin_home_t 存在,但是这是总体的信息,
# 并没有针对某些规则的寻找~所以还是不确定 checktime 能否被读取。但是,基本上就是 SELinux
# type 出问题~因此才会无法读取的
查看规则的状态和其作用使用命令 semanage boolean -l | grep 规则
,比如查看 httpd_enable_homedirs规则:
[root@study ~]# semanage boolean -l | grep httpd_enable_homedirs
SELinux boolean State Default Description
httpd_enable_homedirs (off , off) Allow httpd to enable homedirs
# httpd_enable_homedirs 的功能是允许 httpd 进程去读取用户家目录的意思
查询到某个 SELinux rule,使用 sesearch
知道该规则的用途后,关闭或启动他的命令如下:
[root@study ~]# setsebool [-P] 『规则名称』 [0|1]
选项与参数:
-P :直接将设定值写入配置文件,该设定数据未来会生效的!
# 查询 httpd_enable_homedirs 这个规则的状态,并且修改这个规则成为不同的布尔值
[root@study ~]# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> off <==结果是 off
[root@study ~]# setsebool -P httpd_enable_homedirs 1 # 会跑很久很久
[root@study ~]# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> on
命令格式如下:
[root@study ~]# chcon [-R] [-t type] [-u user] [-r role] 文件
[root@study ~]# chcon [-R] --reference=范例文件 文件
选项与参数:
-R :连同该目录下的次目录也同时修改;
-t :后面接安全性本文的类型字段!例如 httpd_sys_content_t ;
-u :后面接身份识别,例如 system_u; (不重要)
-r :后面街角色,例如 system_r; (不重要)
-v :若有变化成功,请将变动的结果列出来 --reference=范例文件:拿某个文件当范例来修改后续接的文件的类型!
# 查询 /etc/hosts 的 SELinux type,并将该类型套用到 /etc/cron.d/checktime 上
[root@study ~]# ll -Z /etc/hosts
-rw-r--r--. root root system_u:object_r:net_conf_t:s0 /etc/hosts
[root@study ~]# chcon -v -t net_conf_t /etc/cron.d/checktime
changing security context of ‘/etc/cron.d/checktime’
[root@study ~]# ll -Z /etc/cron.d/checktime
-rw-r--r--. root root unconfined_u:object_r:net_conf_t:s0 /etc/cron.d/checktime
# 直接以 /etc/shadow SELinux type 套用到 /etc/cron.d/checktime 上!
[root@study ~]# chcon -v --reference=/etc/shadow /etc/cron.d/checktime
[root@study ~]# ll -Z /etc/shadow /etc/cron.d/checktime
-rw-r--r--. root root system_u:object_r:shadow_t:s0 /etc/cron.d/checktime
----------. root root system_u:object_r:shadow_t:s0 /etc/shadow
restorecon
命令让SELinux 自己解决默认目录下的 SELinux type,命令格式如下:
[root@study ~]# restorecon [-Rv] 文件或目录
选项与参数:
-R :连同次目录一起修改;
-v :将过程显示到屏幕上
# 将 /etc/cron.d/ 底下的文件通通恢复成预设的 SELinux type
[root@study ~]# restorecon -Rv /etc/cron.d
restorecon reset /etc/cron.d/checktime context system_u:object_r:shadow_t:s0->system_u:object_r:system_cron_spool_t:s0
# 表示将 checktime 由 shadow_t 改为 system_cron_spool_t
# 重新启动 crond 看看有没有正确启动 checktime
[root@study ~]# systemctl restart crond
[root@study ~]# tail /var/log/cron # 再去瞧瞧这个 /var/log/cron 的内容,应该就没有错误讯息了
存在文件纪录着每个文件/目录的 SELinux 默认类型,所以restorecon
可以恢复原本的 SELinux type。用 semanage
命令查看修改默认设置。命令格式:
[root@study ~]# semanage {login|user|port|interface|fcontext|translation} -l
[root@study ~]# semanage fcontext -{a|d|m} [-frst] file_spec
选项与参数:
fcontext :主要用在安全性本文方面的用途,
-l 为查询的意思;
-a :增加的意思,你可以增加一些目录的默认安全性本文类型设定;
-m :修改的意思;
-d :删除的意思。
# 查询一下 /etc /etc/cron.d 的预设 SELinux type
[root@study ~]# semanage fcontext -l | grep -E '^/etc |^/etc/cron'
SELinux fcontext type Context
/etc all files system_u:object_r:etc_t:s0
/etc/cron\.d(/.*)? all files system_u:object_r:system_cron_spool_t:s0
# 将 mycron 默认值改为 system_cron_spool_t
[root@study ~]# semanage fcontext -a -t system_cron_spool_t "/srv/mycron(/.*)?"
[root@study ~]# semanage fcontext -l | grep '^/srv/mycron'
SELinux fcontext type Context
748
/srv/mycron(/.*)? all files system_u:object_r:system_cron_spool_t:s0
# 恢复 /srv/mycron 以及子目录相关的 SELinux type
[root@study ~]# restorecon -Rv /srv/mycron
[root@study ~]# ll -dZ /srv/mycron /srv/mycron/*
drwxr-xr-x. root root unconfined_u:object_r:system_cron_spool_t:s0 /srv/mycron
-rw-r--r--. root root unconfined_u:object_r:system_cron_spool_t:s0 /srv/mycron/checktime
# 有了默认值,未来就不会不小心被乱改了
原文地址:SELinux 初探