SELinux 初探

SELinux(Security Enhanced Linux) 是在进行进程、文件等细部权限设定依据的一个核心模块, 由于启动网 络服务的也是进程,因此也能够控制网络服务能否存取系统资源。

SELinux 的运作模式


SELinux 是透过 MAC 的方式来控管进程,他控制的主体是进程, 而目标则 是该进程能否读取的文件资源。MAC(委任式访问控制)可以针对特定的进程与特定的文件资源来进行权限的控管。 即使你是 root ,那么在使用不同的进程时,你所能取得的权限并不一定是 root , 而得要 看当时该进程的设定而定。主要名词和含义如下:

  • 主体 (Subject): SELinux 主要想要管理的就是进程,可以将主体与process 划上等号
  • 目标 (Object): 主体进程能否存取的目标资源一般就是文件系统。因此这个目标可以与文件系统划上等号
  • 政策 (Policy): 由于进程与文件数量庞大,因此 SELinux 会依据某些服务来制订基本的存取安全性政策。这些政策内还会有详细的规则 (rule) 来指定不同的服务开放某些资源的存取与否。在目前的 CentOS 7.x 里面仅有提供三个主要的政策,分别是:
    • targeted:针对网络服务限制较多,针对本机限制较少,是预设的政策
    • minimum:由 target 修订而来,仅针对选择的进程来保护
    • mls:完整的 SELinux 限制,限制方面较为严格
  • 安全性本文 (security context): 主体能不能存取目标除了政策指定之外,主体与目标的安全性本文必须一致才能够顺利存取。 这个安全性本文 (security context) 有点类似文件系统的 rwx ,安全性本 文的内容与设定是非常重要的! 如果设定错误,某些服务(主体进程)就无法存取文件系统(目标资源), 当然就会一直出现权限不符的错误讯息了。
    SELinux 运作的各组件之相关性

图片解释:

  1. 主体进程必须要通过 SELinux 政策内的规则放行后,就可以与目标资源进行安全性本文的比对
  2. 若比对失败 则无法存取目标,若比对成功则可以开始存取目标问题是
  3. 最终能否存取目标还是与文件系统的 rwx 权限设定有关

安全性本文 (Security Context)


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 (身份识别:角色:类型)。

  • 身份识别 (Identify):相当于账号方面的身份识别!主要的身份识别常见有底下几种常见的类型:
    • unconfined_u:不受限的用户,该文件来自于不受限的进程所产生,一般来说,使用可登 入账号来取得 bash 之后, 预设的 bash 环境是不受 SELinux 管制的,因为 bash 并不是什么特别的网络服务,因此,在这个不受 SELinux 所限制的 bash 进程所产生的文件, 其身份识别大多就是 unconfined_u 不受限用户
    • system_u:系统用户,大部分就是系统自己产生的文件。基本上:系统或软件本身所提供的文件,大多就是 system_u 这个身份名称,用户透过 bash 自己建立的文件,大多是不受限的 unconfined_u 身份。如果是网络服务 所产生的文件,或者是系统服务运作过程产生的文件,则大部分的识别就会是 system_u。
  • 角色 (Role):通过角色字段,可以知道这个资料是属于进程、文件资源还是代表使用者。一般的角色有:
    • object_r:代表的是文件或目录等文件资源,最常见
    • system_r:代表的就是进程,不过,一般使用者也会被指定成为 system_r
  • 类型 (Type) :在预设的 targeted 政策中, Identify 与 Role 字段基本上是不重要的,重要的在于这个类型 (type) 字段! 基本上,一个主体进程能不能读取到这个文件资源,与类型字段有关!而类型字 段在文件与进程的定义不太相同,分别是:
    • type:在文件资源 (Object) 上面称为类型 (Type)
    • domain:在主体进程 (Subject) 则称为领域 (domain)
    • domain 需要与 type 搭配,则该进程才能够顺利的读取文件资源

进程与文件 SELinux 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 依据启动与否,共有三种模式:

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

如图所示:

SELinux 的三种类型与实际运作流程图
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。

SELinux 的启动与关闭


改变了政策需要重新启动;如果模式由 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 政策内的规则管理


SELinux 的三种模式是会影响到主体进程的放行与否。 如果是进入 Enforcing 模式,那么接着下来会影响到主体进程的是target 政策内的各项规则 (rules),使用 getsebool 查看当前政策内的规则。

SELinux 各个规则的布尔值查询 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 有关
....(底下省略).... 

SELinux 各个规则规范的主体进程能够读取的文件 SELinux type 查询 seinfo, sesearch


使用 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 规则的布尔值 setsebool


查询到某个 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 

SELinux 安全本文的修改


使用 chcon 手动修改文件的 SELinux type


命令格式如下:

[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 type


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 的内容,应该就没有错误讯息了 

semanage 默认目录的安全性本文查询与修改


存在文件纪录着每个文件/目录的 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 
# 有了默认值,未来就不会不小心被乱改了  



发表评论

评论列表,共 0 条评论

    暂无评论