一、SELinux介绍
传统Linux,一切接文件,由用户,组,权限控制访问
在Selinux中,一切皆对象(object),由存放在inode的扩展属性域的安全元素所控制其访问。
DAC:自由访问控制
MAC: 强制访问控制
DAC环境下进程是无束缚的
MAC环境下策略的规则决定控制的严格程度
MAC环境下进程可以被限制
策略被用来定义被限制的进程能够使用哪些资源(文件和端口)
默认情况下,没有被明确允许的行为将被拒绝
二、SELinux安全上下文查看方法
SELinux 管理过程中,进程是否可以正确地访问文件资源,取决于它们的安全上下文。进程和文件都有自己的安全上下文,SELinux 会为进程和文件添加安全信息标签,比如 SELinux 用户、角色、类型、类别等,当运行 SELinux 后,所有这些信息都将作为访问控制的依据。
首先,通过一个实例看看如何查看文件和目录的安全上下文,执行命令如下:
[root@localhost ~]# ls -Z
#使用选项-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 install.log
-rw-r--r--.root root system_u:object_r:admin_home_t:s0 install.log.syslog
可以看到,查看文件的安全上下文非常简单,就是使用“ls -Z”命令。而在此基础上,如果想要查看目录的安全上下文,需要添加“-d”选项,代表查看目录本身,而非目录下的子文件。举个例子:
[root@localhost ~]# ls -Zd /var/www/html/
drwxr-xr-x.root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html/
那么,该如何查看进程的安全上下文呢?只需使用 ps 命令即可。命令如下:
[root@localhost ~]# service httpd start
#启动apache服务
[root@localhost ~]# ps auxZ | grep httpd
unconfined_u:system_r:httpd_t:s0 root 25620 0.0 0.5 11188 3304 ? Ss
03:44 0:02 /usr/sbin/httpd
…省略部分输出…
也就是说,只要进程和文件的安全上下文匹配,该进程就可以访问该文件资源。在上面的命令输出中,我们加粗的就是安全上下文。
如果一个进程的安全上下文不允许它访问某个文件的安全上下文,SELinux 会阻止访问并在审计日志(可以通过ausearch或auditd工具查看)中记录相关事件。
安全上下文看起来比较复杂,它使用“:”分隔为 4 个字段,其实共有 5 个字段,只是最后一个“类别”字段是可选的,例如:
system_u:object_r:httpd_sys_content_t:s0:[类别]
#身份字段:角色:类型:灵敏度:[类别]
下面对这 5 个字段的作用进行说明。
(1).身份字段(user)
用于标识该数据被哪个身份所拥有,相当于权限中的用户身份。这个字段并没有特别的作用,知道就好。常见的身份类型有以下 3 种:
1.- root:表示安全上下文的身份是 root。
2.- system_u:表示系统用户身份,其中“_u”代表 user。
3.- user_u:表示与一般用户账号相关的身份,其中“_u”代表 user。
user 字段只用于标识数据或进程被哪个身份所拥有,一般系统数据的 user 字段就是 system_u,而用户数据的 user 字段就是 user_u。
那么,SELinux 中到底可以识别多少用户身份字段呢?我们可以使用 seinfo 命令来进行查询。SELinux 的相关命令一般都是以“se”开头的,所以也较为好记。
seinfo 命令格式如下:
[root@localhost ~]# seinfo [选项]
选项:
-u: 列出SELinux中所有的身份(user);
-r: 列出SELinux中所有的角色(role);
-t: 列出SELinux中所有的类型(type);
-b: 列出所有的布尔值(也就是策略中的具体规则名称);
-x: 显示更多的信息;
seinfo 命令的功能较多,我们在这里只想查询 SELinux 中的身份,那么只需执行如下命令:
[root@localhost ~]# seinfo -u
Users:9
sysadm_u
system_u
xguest_u
root
guest_u
staff_u
user_u
unconfined_u
git_shell_u
就可以看到 SELinux 中能够识别的 user 身份共有 9 种。不过这个字段在实际使用中并没有太多的作用,了解一下即可。
(2).角色(role)
主要用来表示此数据是进程还是文件或目录。这个字段在实际使用中也不需要修改,所以了解就好。
常见的角色有以下两种:
1.- object_r:代表该数据是文件或目录,这里的“_r”代表 role。
2.- system_r:代表该数据是进程,这里的“_r”代表 role。
那么,SELinux 中到底有多少种角色呢?使用 seinfo 命令也可以查询,命令如下:
[root@localhost ~]# seinfo -r
Roles:12
guest_r
staff_r
user_r
git_shell_r
logadm_r
object_r
sysadm_r
system_r
webadm_r
xguest_r
nx_server_r
unconfined_r
(3).类型(type)
类型字段是安全上下文中最重要的字段,进程是否可以访问文件,主要就是看进程的安全上下文类型字段是否和文件的安全上下文类型字段相匹配,如果匹配则可以访问。
注意,类型字段在文件或目录的安全上下文中被称作类型(type),但是在进程的安全上下文中被称作域(domain)。也就是说,在主体(Subject)的安全上下文中,这个字段被称为域;在目标(Object)的安全上下文中,这个字段被称为类型。域和类型需要匹配(进程的类型要和文件的类型相匹配),才能正确访问。
SELinux 中到底有多少类型也是通过 seinfo 命令查询的,命令如下:
[root@localhost ~]# seinfo -t | more
Types:3488
#共有3488个类型
bluetooth_conf_t
cmirrord_exec_t
foghorn_exec_t
jacorb_port_t
sosreport_t
etc_runtime_t
…省略部分输出…
我们知道了类型的作用,可是我们怎么知道进程的域和文件的类型是否匹配呢?这就要查询具体的策略规则了,我们在后面再进行介绍。
不过,我们已知 apache 进程可以访问 /var/www/html/(此目录为 RPM 包安装的 apache 的默认网页主目录)目录中的网页文件,所以 apache 进程的域和 /var/www/html/ 目录的类型应该是匹配的,我们查询一下,命令如下:
[root@localhost ~]# ps auxZ | grep httpd
unconfined_u:system_r:httpd_t:s0 root 25620 0.0 0.5 11188 3304 ? Ss
03:44 0:02 /usr/sbin/httpd
#apache进程的域是httpd_t
[root@localhost ~]# ls -dZ /var/www/html/
drwxr-xr-x.root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html/
#/var/www/html/目录的类型是httpd_sys_content_t
apache 进程的域是 httpd_t,/var/www/html/ 目录的类型是 httpd_sys_content_t,这个主体的安全上下文类型经过策略规则的比对,是和目标的安全上下文类型匹配的,所以 apache 进程可以访问 /var/www/html/ 目录。
我们在 SELinux 中最常遇到的问题就是进程的域和文件的类型不匹配,所以我们一定要掌握如何修改类型字段。
(4).灵敏度
灵敏度一般是用 s0、s1、s2 来命名的,数字代表灵敏度的分级。数值越大,代表灵敏度越高。
(5).类别
类别字段不是必须有的,所以我们使用 ls 和 ps 命令查询的时候并没有看到类别字段。但是我们可以通过 seinfo 命令来查询,命令如下:
[root@localhost ~]# seinfo -u -x
#查询所有的user字段,并查看详细信息
system_u
#user字段名
default level:s0
#默认灵敏度
range:s0 - s0:c0.c1023
#灵敏度可以识别的类别
roles:
#该user能够匹配的role(角色)
object_r
system_r
unconfined_r
三、SELinux安全上下文的修改和设置(chcon和restorecon命令)
安全上下文的修改是我们必须掌握的,其实也并不难,主要是通过两个命令来实现的。
chcon 命令格式如下:
[root@localhost ~]# chcon [选项] 文件或目录
选项:
-R: 递归,当前目录和目录下的所有子文件同时设置;
-t: 修改安全上下文的类型字段,最常用;
-u: 修改安全上下文的身份字段;
-r: 修改安全上下文的角色字段;
举个例子:
[root@localhost ~]# echo'test page!!!' >> /var/www/html/index.html
#建立一个网页文件,并写入“test page!!!”
我们可以通过浏览器查看这个网页,只需在浏览器的 URL 中输入“http://ip”即可。
[root@localhost ~]# ls -Z /var/www/html/index.html
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html
#这个网页文件的模式类别是httpd_sys_content_t
[root@localhost ~]# seinfo -t I grep var_t
#查询SELinun中所有的类型、发现有一个类型叫var_t
[root@localhost ~]# chcon -t var_t /var/www/html/index.html
#把网页文件的类型修改为var_t类型
[root@localhost ~]# ls -Z /var/www/html/index.html
-rw-r--r--. toot root unconfined_u:object_r:var_t:s0 /var/www/html/index.html
#这个网页的类型已经被修改了
我们把网页文件的类型修改了,这样 apache 进程的安全上下文一定不能匹配网页的安全上下文,就会出现拒绝访问的情况。
这时网页就会提示权限拒绝,这里我们已经知道是安全上下文不匹配惹的祸!当然,我们可以通过 chcon 命令修改回来就可以修复。不过,我们还有一个命令 restorecon,这个命令的作用就是把文件的安全上下文恢复成默认的安全上下文。SELinux 的安全上下文设定非常完善,所以使用 restorecon 命令就可以修复安全上下文不匹配所引起的问题。
restorecon 命令格式如下:
[root@localhost ~] # restorecon [选项】 文件或目录
选项:
-R:递归.当前目录和目录下所有的子文件同时恢复;
-V:把恢复过程显示到屏幕上;
例如:
[root@1ocalhost ~]# restorecon -Rv /var/www/html/index.html
restorecon reset /var/www/html/index.html context
unconfined_u:object_r:var_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
#这里已经提示了安全上下文从var_t恢复成了httpd_sys_content_t
[root@1ocalhost ~]# ls -Z /var/www/html/index.html
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html
#查看一下,安全上下文已经恢复正常了.网页的访问也已经恢复正常了
四、SELinux默认安全上下文的查询和修改(semanage命令)
前面讲到,restorecon 命令可以将文件或目录恢复成默认的安全上下文,这就说明每个文件和目录都有自己的默认安全上下文,事实也是如此,为了管理的便捷,系统给所有的系统默认文件和目录都定义了默认的安全上下文。
那么,默认安全上下文该如何查询和修改呢?这就要使用 semanage 命令了。该命令的基本格式如下:
[root@localhost ~]# semanage [login|user|port|interface|fcontext|translation] -l
[root@localhost ~]# semanage fcontext [选项] [-first] file_spec
其中,fcontext 主要用于安全上下文方面,-l 是查询的意思。除此之外,此命令常用的一些选项及含义,如下表所示。
选项 | 含义 |
---|---|
-a | 添加默认安全上下文配置 |
-d | 删除指定的默认安全上下文 |
-m | 修改指定的默认安全上下文 |
-t | 设定默认安全上下文的类型 |
[root@localhost ~]# semanage fcontext -l
#查询所有的默认安全上下文
…省略部分输出…
/var/www(/.*)? all files
system_u:object_r:httpd_sys_content_t:s0
…省略部分输出…
#能够看到/var/www/目录下所有内容的默认安全上下文都是httpd_sys_content_t
所以,一旦对 /var/www/ 目录下文件的安全上下文进行了修改,就可以使用 restorecon 命令进行恢复,因为默认安全上下文已经明确定义了。
【例 2】修改默认安全上下文。
那么,可以修改目录的默认安全上下文吗?当然可以,举个例子:
[root@localhost ~]# mkdir /www
#新建/www/目录,打算用这个目录作为apache的网页主目录,而不再使用/var/www/html/目录
[root@localhost ~]# ls -Zd /www/
drwxr-xr-x.root root unconfined_u:object_r:default_t:s0 /www/
#而这个目录的安全上下文类型是default_t,那么apache进程当然就不能访问和使用/www/目录了
这时我们可以直接设置 /www/ 目录的安全上下文类型为 httpd_sys_content_t,但是为了以后管理方便,我打算修改 /www/ 目录的默认安全上下文类型。先查询一下 /www/ 目录的默认安全上下文类型,命令如下:
[root@localhost ~]# semanage fcontext -l | grep "/www"
#查询/www/目录的默认安全上下文
查询出了一堆结果,但是并没有 /www/ 目录的默认安全上下文,因为这个目录是手工建立的,并不是系统默认目录,所以并没有默认安全上下文,需要我们手工设定。命令如下:
[root@localhost ~]# semanage fcontext -a -t httpd_sys_content_t "/www(/.*)?"
#这条命令会给/www/目录及目录下的所有内容设定默认安全上下文类型是httpd_sys_content_t
[root@localhost ~# semanage fcontext -l | grep "/www"
…省略部分输出…
/www(/.*)? all files system_u:object_r:httpd_sys_content_t:s0
#/www/目录的默认安全上下文出现了
这时已经设定好了 /www/ 目录的默认安全上下文。
[root@localhost ~]# ls -Zd /www/
drwxr-xr-x.root root unconfined_u:object_r:default_t:s0 /www/
#但是查询发现/www/目录的安全上下文并没有进行修改,那是因为我们只修改了默认安全上下文,而没有修改目录的当前安全上下文
[root@localhost ~]# restorecon -Rv /www/
restorecon reset /www context
unconfined_u:object_r:default_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
#恢复一下/www/目录的默认安全上下文,发现类型已经被修改为httpd_sys_content_t
五、编写自定义 SELinux 策略模块
1.环境准备
首先,需要安装相关的开发工具。在 CentOS 或 RHEL 系统中,要安装policycoreutils -devel包,这个包提供了编写和编译 SELinux 策略模块所需的工具,如checkmodule和semodule_package。
2.策略模块文件结构和基本语法
(1).模块声明(Module Declaration)
一个 SELinux 策略模块以module关键字开始,后面跟着模块名称和版本号。例如:
module my_custom_policy 1.0;
- 这里my_custom_policy是模块名称,1.0是版本号。
(2).类型声明(Type Declarations)
- 需要声明主体(如进程)类型和客体(如文件、目录)类型。例如:
type my_process_t;
type my_file_t;
- 上面分别声明了一个代表进程的类型my_process_t和一个代表文件的类型my_file_t。
(3).接口声明(Interface Declarations)
- 接口用于定义模块提供给其他模块的功能。例如:
interface(`my_policy_api',`
gen_require(`
type my_file_t;
')
)
- 这个接口my_policy_api声明了对类型my_file_t的需求。
(4).规则定义(Rule Definitions)
- 最重要的部分是定义主体对客体的访问规则。例如,允许my_process_t类型的进程读取my_file_t类型的文件:
allow my_process_t my_file_t:file read;
- 规则格式通常是allow|deny [主体类型] [客体类型]:[客体类别] [访问权限];,其中allow表示允许访问,deny表示禁止访问,file是客体类别(可以是file、dir、socket等多种类别),read是访问权限(还可以有write、execute等多种权限)。
(5).编写一个简单的示例策略模块
假设我们要编写一个策略模块,允许一个自定义的进程(myapp_process_t)读取和写入一个自定义的配置文件(myapp_config_t)。
策略模块文件(myapp_policy.te)内容如下:
module myapp_policy 1.0;
type myapp_process_t;
type myapp_config_t;
interface(`myapp_policy_api',`
gen_require(`
type myapp_config_t;
')
)
allow myapp_process_t myapp_config_t:file {read, write};
(6).编译和加载策略模块
一、编译模块
- 使用checkmodule -M -m -o myapp_policy.mod myapp_policy.te命令。其中checkmodule是编译工具,-M选项表示创建一个模块,-m选项用于指定模块文件(.te文件),-o选项指定输出的编译后的模块文件(.mod文件)。
二、打包模块 - 使用semodule_package -o myapp_policy.pp -m myapp_policy.mod命令。semodule_package工具将编译后的模块打包成一个可加载的策略包(.pp文件)。
三、加载模块 - 使用semodule -i myapp_policy.pp命令来加载这个自定义策略模块。加载后,SELinux 就会按照这个模块中定义的规则来控制访问。
(7).调试和测试策略模块
1.查看审计日志(Audit Logs)
- 当 SELinux 阻止或允许访问操作时,相关信息会记录在审计日志中。可以使用ausearch -m avc -ts recent命令来查看最近的 SELinux 访问向量缓存(AVC)消息。这些消息可以帮助判断策略模块是否按预期工作。
2.调整和优化策略
- 根据审计日志和实际应用程序的运行情况,可能需要对策略模块进行调整。例如,如果发现应用程序还需要执行文件的权限,就需要在策略模块中添加allow myapp_process_t myapp_config_t:file execute;这样的规则。同时,要注意避免过度授权,以确保系统安全。
3.相关策略文件的存储位置
(1).SELinux 策略文件存储位置
- 在大多数 Linux 系统中,SELinux 策略文件通常存储在/etc/selinux目录下。这个目录包含了 SELinux 策略相关的配置文件。
- 例如,对于targeted策略(这是很多系统默认的策略类型),策略文件的二进制表示形式可能存储在/etc/selinux/targeted/policy目录中。这些文件是经过编译后的策略模块,系统通过加载这些文件来实施 SELinux 策略。
(2).自定义策略模块存储位置
- 当你编写自定义的 SELinux 策略模块时,在编译和打包后(通常生成.pp文件),可以将这些文件存储在本地目录用于测试。
- 不过,如果要让系统在启动时自动加载自定义策略模块,一个比较合适的位置是/etc/selinux/targeted/modules/active/modules目录(对于targeted策略而言)。你可以使用semodule -i命令将自定义策略模块(.pp文件)安装到这个位置,这样系统在下次启动时会加载这些自定义策略规则。
(3).SELinux 策略源文件(用于开发)
- 对于开发自定义策略,源文件(如.te、.fc、.if等文件)可以存储在本地开发目录。这些文件包含了类型声明、规则定义等内容,用于构建自定义策略模块。
- 例如,你可以在自己的用户目录下创建一个专门用于开发 SELinux 策略的文件夹,如~/selinux_policy_dev,在这个文件夹中编写和编辑策略源文件,然后在需要时将其编译、打包并安装到系统的策略目录中。