前言

SELinux的全称是Security Enhanced Linux,就是安全加强的liunx。在SELinux之前,root账号能够任意的访问所有文档和服务;如果某个文件设为777,那么任何用户都可以访问甚至删除;这种方式成为DAC(主动访问机制),很不安全。
DAC自主访问控制:用户根据自己的文件权限来决定对文件的操作,也就是依据文件的own,group,other/r,w,x权限进行限制。Root有最高权限无法限制。r,w,x权限划分太粗糙。无法针对不同的进程实现限制。
SELinux则是基于MAC强制访问机制。简单地说,就是程序和访问对象上都有一个安全标签(即SELinux上下文)进行区分,只有对应的标签才能允许访问。否则即使权限是777,也是不能访问的。
在SELinux中,访问控制属性叫做安全上下文。所有客体(文件、进程间通讯通道、套接字、网络主机等)和主体(进程)都有与其关联的安全上下文,一个安全上下文由三部分组成:用户(u)、角色(r)和类型(t)标识符。但我们最关注的是第三个部分:类型标识符。
程序访问资源时,主体程序必须要通过SELinux策略内的规则放行后,才可以与目标资源进行安全上下文的对比:对比失败则无法存取目标;对比成功则可以开始存取目标。最终能否存取目标还与文件系统的r/w/x权限的设定有关。所以启用了SELinux后出现权限不符的情况时,得一步步分析可能的问题。

SELinux的状态查看与配置

SELinux的配置文件位置:

[shane@homeserver ~]$ locate selinux/config
/etc/selinux/config

它还有个链接在/etc/sysconfig/selinux:

[shane@homeserver ~]$ ll /etc/sysconfig/selinux 
lrwxrwxrwx. 1 root root 17 3月   8 2020 /etc/sysconfig/selinux -> ../selinux/config

通过修改config文件的方式来配置selinux状态属于永久修改,需重启系统后生效。

[shane@homeserver ~]$ cat /etc/sysconfig/selinux 

# 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=permissive
# SELINUXTYPE= can take one of these three values:
#     targeted - Targeted processes are protected,
#     minimum - Modification of targeted policy. Only selected processes are protected. 
#     mls - Multi Level Security protection.

SELINUX=
enforcing强制模式,系统受到selinux保护。只要违反了策略,就无法继续操作
permissive提示模式,系统不会受到selinux保护,只是收到警告消息。permissive表示selinux有效,但是即使用户违反了策略,也可以继续操作,selinux仅仅是将违反的操作都记录下来并打印警告信息。
disabled禁用selinux。
SELINUXTYPE=
targeted对所有目标进程进行保护。
minimum仅对少数进程进行保护。
mls多层安全级别保护。
以上策略配置都放置在/etc/selinux目录中,目录和策略名称相同:

[shane@homeserver ~]$ ll /etc/selinux/
总用量 8
-rw-r--r--. 1 root root  547 3月   8 2020 config
-rw-r--r--. 1 root root 2425 7月  22 02:44 semanage.conf
drwxr-xr-x. 5 root root  133 10月 28 09:10 targeted

使用SELinux的相关命令查看和修改状态

sestatus查询selinux工作状态

[root@homeserver nginx]# sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing
Mode from config file:          permissive
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Memory protection checking:     actual (secure)
Max kernel policy version:      32

selinuxenabled检查selinux是否开启,配合echo$?回传的值是0则为开启,1为关闭。

[shane@homeserver ~]$ selinuxenabled
[shane@homeserver ~]$ echo $?
0

getenforce查看selinux的状态

[shane@homeserver ~]$ getenforce
Enforcing

setenforce设定selinux运行状态,1为主动开启(Enforcing),0为仅警告(Permissive)

[shane@homeserver ~]$ sudo setenforce 1
[sudo] shane 的密码:
[shane@homeserver ~]$ getenforce
Enforcing

查看安全上下文相关命令

查看文件上下文

[shane@homeserver ~]$ ls -lZ /home
总用量 4
drwxr-xr-x.  5 shane     shane      unconfined_u:object_r:user_home_dir_t:s0   45 9月  20 10:55 backup
drwxr-xr-x.  6 shane     shane      system_u:object_r:user_home_dir_t:s0       59 10月 29 20:20 halo
drwxr-xr-x.  5 shane     shane      unconfined_u:object_r:user_home_dir_t:s0   52 3月   8 2020 jellyfin
drwx------.  5 shane     shane      unconfined_u:object_r:user_home_dir_t:s0   76 3月   8 2020 seafile
drwx------.  2 sftpadmin sftp-users system_u:object_r:user_home_dir_t:s0       62 4月   5 2020 sftpadmin
drwx------. 21 shane     shane      unconfined_u:object_r:user_home_dir_t:s0 4096 11月  5 14:16 shane

查看进程上下文

[shane@homeserver ~]$ ps -auxZ | grep httpd
system_u:system_r:httpd_t:s0    root        1229  0.0  0.0 111724  2740 ?        Ss   09:55   0:00 nginx: master process /usr/sbin/nginx
system_u:system_r:httpd_t:s0    nginx       1230  0.0  0.0 130520 10624 ?        S    09:55   0:00 nginx: worker process
system_u:system_r:httpd_t:s0    nginx       1231  0.0  0.0 130520 10560 ?        S    09:55   0:00 nginx: worker process
system_u:system_r:httpd_t:s0    nginx       1232  0.0  0.0 130800 12368 ?        S    09:55   0:00 nginx: worker process
system_u:system_r:httpd_t:s0    nginx       1233  0.0  0.0 130520 11964 ?        S    09:55   0:00 nginx: worker process
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 shane 75593 0.0  0.0 12324 1036 pts/0 S+ 15:37   0:00 grep --color=auto http

查看用户上下文

[shane@homeserver ~]$ id -Z
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

复制和移动文件时安全上下文的变化

以httpd为例,这个httpd的进程可以访问/var/www/html下的文档对象在一个直接创建的网站的根目录下,另一个创建在root下,然后用mv命令移动到www目录

[root@homeserver ~]# echo "lalala" > /var/www/html/lala.html
[root@homeserver ~]# echo "hahaha" > /root/haha.html
[root@homeserver ~]# mv /root/haha.html /var/www/html/

查看html目录下文件的安全上下文

[root@homeserver html]# ls -lZ
总用量 8
-rw-r--r--. 1 root root unconfined_u:object_r:admin_home_t:s0        7 11月  8 12:08 haha.html
-rw-r--r--. 1 root root unconfined_u:object_r:httpd_sys_content_t:s0 7 11月  8 12:09 lala.html

通过上图可以看到剪切操作时文件的上下文没有发生改变,仍然是原上下文,而复制操作时文件的上文继承了目标目录的上下文。通过浏览器访问这两个网页文件

image.png

可以看到lala.html页面能访问而haha.html却被拒绝访问
查看权限发现apache用户对这两个文件都具有r权限,但haha.html文件却拒绝访问。

[shane@homeserver html]$ ll
总用量 8
-rw-r--r--. 1 root root 7 11月  8 12:08 haha.html
-rw-r--r--. 1 root root 7 11月  8 12:09 lala.html

原因就是因为httpd进程不能访问域类型标签是admin_home_t的资源,被selinux将访问拒绝了。
查看日志/var/log/audit/audit.log 通过日志记录也能看到haha.html文件拒绝httpd进程访问。
image.png

由于此文件记录的信息很多不宜直接查看,可以借助audit2why和audit2allow

#audit2why /var/log/audit/audit.log

image.png

查看系统是否提供audit2why和audit2allow工具软件包

image.png
收集Selinux产生的日志,另一个工具是setroubleshoot,对应的软件包为

image.png

Settroubleshoot将错误信息写入/var/log/messages中

#tail /var/log/messages | grep settroubleshoot

image.png

上面的错误信息大概说的是“selinux阻止httpd访问这个文件,要查看完整的信息,请执行sealert命令”

image.png

可以用sesearch [--allow][-s 主体类别][-t 目标类别][-b] 查询详细规则
sesearch命令由下列软件包提供

image.png

找出目标资源类别为httpd_sys_content_t的相关信息

image.png

image.png

从上图显示信息标识[allow 主题程序安全上下文类别 目标资源安全上下文类别],说明这个资源类别可以被哪个主题程序类别所读取。
找出主体程序为httpd_t相关的所有信息

image.png

从上面的数据就可以看出程序httpd_t为各类别可以访问的哪些资源类别。

selinux上下文设置

如何解决上述问题呢?解决方法就是更改文件的上下文。有两种方式,一种是通过restorerecon(restore context)修复继承当前目录默认的上下文;一种是通过chcon(change context)修改当前的上下文。

使用restorerecon修复继承当前目录默认的上下文

首先为 /var/www/html 这个目录下的所有文件添加默认的标签类型

semanagefcontext  -a  -t httpd_sys_content_t  '/var/www/html(/.*)?'

因为html目录的默认标签类型就是httpd_sys_content_t,所以此步可以省略
然后用新的标签类型标注已有文件:

restorecon -Rv /var/www/html/

之后httpd就可以访问该目录下的文件了。

image.png

image.png

semanage和restorerecon命令是由下列软件包提供的

image.png

使用chcon修改当前的上下文

image.png

chcon意思是change context

参数
-t		type 类型
-R		recursive 递归(适用于改变某个目录下所有文件的context)
-u		user 用户
-r		role 角色
--reference	使用参考文件的上下文修改当前文件的上下文

image.png

selinux的布尔值

最后再看一个概念,selinux的布尔值。这个布尔值类似一个开关,打开的话,他对应的一些服务就允许执行,否则拒绝执行。

image.png

image.png

也可用semanage命令#semanageboolean -l
知道了布尔值的名字,可以通过 sesearch 来确认他关联了哪些服务的域,比如httpd_enable_homedir允许下列规则,如果设置为off的话,那么他们都是无法访问的。

image.png

image.png

设置boolean值,-P为设置永久生效。
下面看一个与布尔值有关的例子。
先确认已经启用了selinux、启动FTP:

image.png

在匿名访问目录下创建2个文件进行测试,一个是在该目录下手动创建,这样该文件会自动继承 /var/ftp/pub 下的目录上下文的值,一个用 mv 命令从 root 目录下移动过来,这样的文件会保留 root 目录下的安全上下文,如下

image.png

使用匿名登录测试:

image.png

发现这里看不到 haha 文件。已知系统启动了 selinux,先查看系统日志,有两个工具可以收集到 selinux 产生的日志,一个是 setroubleshoot,一个是 audit,先使用 audit 工具。
系统中提供了 audit 相关的命令,常用的有 audit2why 和 audit2allow。audit 产生的日志放在 /var/log/audit,由于此文件记录的信息比较繁杂不适合直接查看,可以借助 audit2why 命令,首先启动 audit,在客户端登录FTP服务器时会触发 audit deamon 产生日志:

image.png

image.png

image.png

AVC是 access vector cache 的缩写,目的是记录所有与 selinux 有关的存取统计资料。
验证布尔值中有关FTP的定义:

image.png

发现 ftp_home_dir --> off,文件 root.txt 的类型刚好是 root:object_r:user_home_t:s0,所以更改此 bool 值就可以

image.png

image.png

image.png

(-P是把该修改写到文件,下次启动仍然有效)
客户端登录测试,发现haha文件就可以访问了。

总结

如果搭建了某个服务器,然后客户端无法正常访问,应该按照下面的顺序进行排错:
1.该服务的配置文件中是否开启了相关的权限 ,比如是否允许匿名用户写入等等;
2.文件系统的权限,比如是否需要使用chmod修改权限;
3.SELinux的上下文和布尔值。

参考

https://blog.51cto.com/mpflinux/1926700