SELinux
概述
SELinux (Security Enhanced Linux)
是 强制存取系统 (Mandatory Access Control)
的一种。SELinux 具有以下特点:
通过对文件、进程、套接字等系统资源打标签管理用户或进程的权限
文件路径变化而权限不会改变(与 Apparmor 相反)
开启 SELinux 会对性能造成一定损失
进程的权限则取决于其安全上下文。而进程的安全上下文则主要取决于用户的 身份 (Identity)
。
如图:[1]
一个 Unix 用户 只能有一个 SELinux 身份
一个 SELinux 身份可以属于多个角色
一个角色只能属于一个
域 (domin)
SELinux 的权限表现为域的权限
域在内部实际上被称为 |
当一个用户登陆时,SELinux 将会根据用户的角色来为其分配安全上下文。这些安全上下文构成了用户的域,然后,所有由用户运行的进程都将会继承用户域。
每次用户登录时,都会为其分配一个 SELinux 身份。而身份又定义了他们将能够认可的角色。这两个映射(从用户到身份,从此身份到角色)可以使用 semanage 命令进行配置。
一些重要的程序在自己专有的域中运行。为此,它们的可执行文件被标记为专有类型(比如 ssh 被标记为 ssh_exec_t ),它们会在启动后自动切换到其专有域,而不是继承用户的域。
在启用了 SELinux 的系统上,对 ls、ps、id 等命令添加了 -Z 选项,分别用来查看文件、进程、用户的 SELinux 信息。
例如:
查看进程的安全上下文:
# ps -AZ | head -n5 LABEL PID TTY TIME CMD system_u:system_r:init_t:s0 1 ? 00:00:02 systemd system_u:system_r:kernel_t:s0 2 ? 00:00:00 kthreadd system_u:system_r:kernel_t:s0 3 ? 00:00:00 rcu_gp system_u:system_r:kernel_t:s0 4 ? 00:00:00 rcu_par_gp
从左到右依次为:SELinux 身份、角色、域和
MCS (Multi-Category Security)
等级。用户的安全上下文:
# id -Z unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
查看文件的安全上下文:
# ls -lhZ -rw-r--r--. 1 root root system_u:object_r:selinux_config_t:s0 548 8月 26 11:07 config -rw-r--r--. 1 root root system_u:object_r:selinux_config_t:s0 2.4K 1月 29 2020 semanage.conf drwxr-xr-x. 5 root root system_u:object_r:selinux_config_t:s0 133 8月 27 13:17 targeted
分配给文件的身份和角色没有用。之所以分配,只是为了统一外观。 |
可以看到,SELinux 通过一系列标签来标记资源(文件、进程、目录、套接字等),域的权限表现为对这些标签的一系列 Allow/DisAllow 操作。这些操作被称为 规则
。
为了方便使用,SELinux 开发人员将域的规则打包成模块,再将模块打包成 策略 (Policy)
。用户可以通过安装开发人员打包好的策略来快速、方便地使用 SELinux,而不是从头定义权限。
SELinux 的工作流程如下:
: 主体; : SELinux; repeat : 检查安全上下文; backward: 检查策略; repeat while(检查标签) if(安全上下文是否满足?) then(是) : SELinux 授予访问权限; else(否) : AVC 写入日志; : 拒绝访问; endif : AVC;
Linux 内核在执行每个系统调用之前查询 SELinux |
管理 SELinux
有多种工具可供 SELinux 的用户使用,比如策略、模块、布尔值、日志审计系统、troubleshoot 工具等。这些工具在一定程度上降低了 SELinux 的管理门。学习这些工具的使用可以大大简化我们的工作流程。
对于 SELinux 来说,一共有三种状态:disable, permissive, enforcing。
disabled | 关闭 SELinux |
permissive | 校验权限,但是不会限制权限。主要用于调试 |
enforcing | 校验并限制主体权限 |
permissive 模式下 SELinux 会将主体的不合法行为写入日志,但是并不会阻止主体的不合法行为
要更改 SELinux 在重启后的行为,你需要修改 /etc/selinux/confg
中的 SELINUX
字段并重启。
你可以通过 |
管理 SELinux 策略
对于 Fedora 来说,开发人员一共为我们提供了三种策略:minimum, targeted, mls。策略以文件夹的形式被包含在 /etc/selinux/
下,比如 targeted 策略的位置为 /etc/selinux/targeted
。
尽管 Fedora 的开发人员提供了三种策略,但是默认只安装了 targeted,剩余的 minnimum, mls 可以分别通过安装 selinux-policy-minimum 和 selinux-policy-mls 来获得。 其中:
Fedora 的策略开发人员地址为: fedora-selinux/selinux-policy |
尽管系统提供了多个策略,但是我们在同一时间内只能使用一个策略包。
要查看当前系统使用的策略,可以使用
sestatus
来查看当前 SELinux 加载的策略# sestatus SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SELinux root directory: /etc/selinux Loaded policy name: targeted # 当前加载的策略为 targeted Current mode: enforcing Mode from config file: enforcing Policy MLS status: enabled Policy deny_unknown status: allowed Memory protection checking: actual (secure) Max kernel policy version: 32
要切换系统使用的策略,你需要修改
/etc/selinux/config
的SELINUXTYPE
字段并重启。
查询策略信息
seinfo
定义了一组操作用于查看当前所加载策略的信息。
最简单的用法就是直接在 shell 中输入 seinfo
,这将会输出当前策略的统计信息,比如所定义的身份、角色等:
# seinfo Statistics for policy file: /sys/fs/selinux/policy Policy Version: 33 (MLS enabled) Target Policy: selinux Handle unknown classes: allow Classes: 134 Permissions: 456 Sensitivities: 1 Categories: 1024 Types: 5009 Attributes: 254 Users: 8 Roles: 14 Booleans: 348 Cond. Expr.: 382 Allow: 63564 Neverallow: 0 Auditallow: 166 Dontaudit: 8453 Type_trans: 256701 Type_change: 87 Type_member: 35 Range_trans: 6044 Role allow: 37 Role_trans: 425 Constraints: 72 Validatetrans: 0 MLS Constrain: 72 MLS Val. Tran: 0 Permissives: 0 Polcap: 5 Defaults: 7 Typebounds: 0 Allowxperm: 0 Neverallowxperm: 0 Auditallowxperm: 0 Dontauditxperm: 0 Ibendportcon: 0 Ibpkeycon: 0 Initial SIDs: 27 Fs_use: 33 Genfscon: 105 Portcon: 652 Netifcon: 0 Nodecon: 0
seinfo 常用的参数如下:
参数 | 含义 |
a | 查询类型属性 |
b | 查询布尔值 |
c | 查询对象类 |
u | 查询策略定义的所有身份 |
r | 查询策略定义的所有角色 |
t | 查询策略定义的所有类型 |
从策略中搜索规则
sesearch(1)
布尔值
SELinux 模块将一部分开关导出到布尔值中,对于常用的操作,可以通过布尔值实现开关。 当 SELinux 发出警报时,最先想到的方式应当是布尔值。
布尔值只有两种使用方式: getsebool
和 setsebool
例如:
查看 Samba 的布尔值:
# getsebool -a | grep samba samba_create_home_dirs --> off samba_domain_controller --> off samba_enable_home_dirs --> off samba_export_all_ro --> off samba_export_all_rw --> off samba_load_libgfapi --> off samba_portmapper --> off samba_run_unconfined --> off samba_share_fusefs --> off samba_share_nfs --> off sanlock_use_samba --> off tmpreaper_use_samba --> off use_samba_home_dirs --> off virt_use_samba --> off
可以看到,所有 Samba 相关的布尔值都是关闭的。下面我们开放一些常用的布尔值
setsebool -P samba_export_all_ro 1 setsebool -P samba_enable_home_dirs 1
setsebool 存在三个参数:
参数 | 含义 |
P | 设置的布尔值将会被永久保留(默认是保留到重启) |
N | 磁盘中的规则暂时不会加载到内核 |
V | 规则中的错误信息可以被 |
|
booleans(9)
togglesebool(8)
getsebool(8)
setsebool(8)
文件安全上下文
通过编写模块可以自定义自己的安全上下文,但是需要注意的是:定义的文件上下文仅在 文件打标签时 才会被应用,文件打标签一般发生在创建文件时,但我们可以通过一系列工具手动来给存在的文件打/修改标签。
使用
semanage fcontext
查询文件上下文使用
restorecon
给已经存在的文件打标签。restorecon (Restore Context)
用来恢复文件的默认标签。在我们给文件新定义了标签后,我们可以使用此命令给自定的文件/目录 打标签。其使用方式如下:restorecon -FR /
如果文件没有标签,则为文件打上默认标签,否则只会修改类型字段,使用
-F
可以强制替换所有字段。使用
chcon (Change Contetx)
改变文件上下文
策略管理工具
SELinux 提供了一个综合性的工具用来集中管理这些资源,通过 semanage
(及其子命令)我们可以修改用户身份、文件上下文和网络端口。
semange 常用的子命令如下:
子命令 | 说明 |
login | 管理 Linux 用户和受 SELinux 限制的用户间的登录映射 |
user | 管理受 SELinux 限制的用户(一个 SELinux 用户的角色和级别) |
port | 管理网络端口类型定义 |
fcontext | 管理文件上下文映射定义 |
例如:
为 Nginx 开放自定义端口[2]
执行下列命令:
semanage port -a -t http_port_t -p tcp 8088
每个子命令都有其单独的手册页,比如:
|
模块
系统提供的模块被储存到 /usr/share/selinux/
的子目录下,例如默认提供的模块位于 targeted 策略的模块被储存到 /usr/share/selinux/targeted
目录下。
可以通过 semodule
来操纵模块,常使用的参数如下:
参数 | 操作 |
l | 列出已经安装的模块 |
i | 安装模块包 |
r | 按所需的优先级删除现有模块(默认为 -X 400) |
e | 启用模块 |
d | 禁用模块 |
R | 重新加载策略 |
checkmodule(8)
semodule_package(8)
自定义模块
当系统提供的模块已经无法满足你的需求的时候,可以通过自定义模块来增强 SELinux 的功能。
自定义模块应当遵循一下几个原则:[3]
不得创建不兼容的模块。不兼容的模块之间是互斥的,不能同时生效
不得允许对最终用户策略进行自定义
不得恐吓违反政策的用户
不得添加后门程序
要自定义模块,对于 Fedora 来说,需要分别安装 selinux-policy-devel
和 selinux-policy-doc
两个包。selinux-policy-doc
提供了可作为模板的文件。
M4宏语言 可以简化流程。 |
首先拷贝模板文件到当前目录:
cp /usr/share/doc/selinux-policy/example.* .
这个操作一共拷贝了三个文件:example.fc, example.if, example.te * te 文件是最重要的,它定义了规则 * fc 文件定义了
文件上下文 (File Contexts)
。在文件打标签时需要用到该文件。 * te 文件定义了一系列模块接口,以便其他模块与你的模块进行交互,它是接口文件 (Interface File)
编写 fc 文件。
fc 文件通过一系列正则表达式来为多个文件(甚至整个目录)分配文件上下文。
# myapp 将会拥有: # 标签:system_u:object_r:myapp_exec_t # MLS 灵敏度:s0 # MCS 类别: <none> /usr/sbin/myapp -- gen_context(system_u:object_r:myapp_exec_t,s0)
编写 if 文件。
if 文件是文件接口文件,其通过一系列
interface
来定义“谁可以执行”、“将会拥有哪些权限”的问题。例如:interface(`myapp_domtrans',` gen_require(` type myapp_t, myapp_exec_t; ') domtrans_pattern($1,myapp_exec_t,myapp_t) ') interface(`myapp_read_log',` gen_require(` type myapp_log_t; ') logging_search_logs($1) allow $1 myapp_log_t:file read_file_perms; ')
第一个接口 myapp_domtrans 定义了谁可以运行这个模块,第二个接口 myapp_read_log 赋予了对日志文件的读权限。
在编写 fc 文件时: * 你应当使用
gen_require
宏导出所有你定义的类型 * 你可以使用其他模块提供的接口。编写 te 文件。
policy_module(myapp,1.0.0) ######################################## # # Declarations # type myapp_t; type myapp_exec_t; domain_type(myapp_t) domain_entry_file(myapp_t, myapp_exec_t) type myapp_log_t; logging_log_file(myapp_log_t) type myapp_tmp_t; files_tmp_file(myapp_tmp_t) ######################################## # # Myapp local policy # allow myapp_t myapp_log_t:file { read_file_perms append_file_perms }; allow myapp_t myapp_tmp_t:file manage_file_perms; files_tmp_filetrans(myapp_t,myapp_tmp_t,file)
行 1 :模块必须通过其名称和版本号来标识。这个指令是必需的。
行 8 :如果模块引入了新的类型,必须使用这样的指令来声明它们。可以根据需要创建尽可能多的类型,但不要授予太多无用的权限。
行 11:此接口定义了一个 myapp_t 的过程域,所有被 myapp_exec_t 标记的可执行文件都可以运行它。这将隐式地在这些对象上添加*exec_type* 类型属性,从而允许其他模块授予权限来执行这些程序。比如 userdomain 允许 user_t, staff_t , sysadm_t 类型的对象运行它。
行 14:logging_log_file 是由参考政策(Reference Policy)提供的接口,它表明标记为给定类型的文件是日志文件以便一些应用程序从中获益(比如 logrotate 可以操纵它)。
行 24:allow 是标准的授权指令,第一个参数是允许执行操作的过程域,第二个参数定义了上一个参数可以操纵的对象,其形式是
type:class
type 代表 SELinux 定义的类型, class 定义了该类型的实体类型(file, directory, socket, fifo, 等),最后一个参数描述了允许的权限,其形式为{ 操作1, 操作2 }
,但是你也可以通过一系列有用的宏来代表这些操纵,这些宏在/usr/share/selinux/devel/include/support/obj_perm_sets.spt
被列出。
编译文件
完成这三个文件(example.if, example.fc, and example.te)后,将文件重命名为 myapp.extension 并运行 make NAME=devel 生成后缀名为 pp 的模块文件,然后使用 semodule 加载模块
https://selinuxproject.org/page/ObjectClassesPerms[ObjectClassesPerms
SELinux Wiki]
日志审计系统
日志审计系统 (Audit)
用来收集系统上安全相关的事件的信息,在 SELinux 拒绝进程访问文件后,会在 Audit 中产出拒绝信息。
根据 Audit 守护进程运行与否,Audit 日志会出现下列三种情况:
若 auditd 守护进程正在运行,则拒绝消息将被记录与
/var/log/audit/audit.log
中若 auditd 守护进程没有运行,但 rsyslogd 守护进程正在运行,则拒绝消息会记录到
/var/log/messages
中。如果 auditd 和 rsyslogd 都在运行,那么拒绝消息将发送到 audit.log 和 messages 日志文件中。
auditd 的日志文件并没有加入日志轮转计划(logrotate )中,这意味着 auditd 的日志文件会不断增长。 |
aureport
aureport
可以用来查看对审计日志的摘要:
# aureport -e -i --summary #分类统计事件数量 Event Summary Report ====================== total type ====================== 2434 SYSCALL 816 USER_START 816 USER_ACCT 814 CRED_ACQ 810 LOGIN 806 CRED_DISP 779 USER_END 99 CONFIG_CHANGE 52 USER_LOGIN aureport -e -i --summary | mkbar events #分类统计事件数量,并画出图表。
ausearch
ausearch
可以用来对日志进行过滤:
# ausearch - option -if myfile
它可以指定特定的日志文件进行分析, 通过加上 "-i" 可以将数据转化成可读的形式,一般有以下参数:[#cnblogs]
m | 按消息类型 |
ul | 按登陆 ID |
ua | 按 uid 和 euid |
ui | 按 uid |
ue | 按 euid |
ga | 按 gid 和 egid |
gi | 按 gid |
ge | 按 egid |
c | 按 cmd |
x | 按 exe |
sc | 按 syscall |
p | 按 pid |
sv | 按 syscall 的返回值 |
f | 按文件名 |
tm | 按连接终端 |
hn | 按主机名 |
k | 按特定的key值 |
w | 按在 audit rule 设定的字符串 |
audit2why
audit2why 命令用来分析 audit.log 日志文件,并分析 SELinux 为什么会拒绝服务。有三种使用方式
audit2why -i audit.log
cat audit.log | audit2why
audit2why < audit.log
例如:
# cat /var/log/audit/audit.log | audit2why type=AVC msg=audit(1626855919.807:979): avc: denied { prog_run } for pid=3802 comm="runc" scontext=system_u:system_r:container_runtime_t:s0 tcontext=system_u:system_r:init_t:s0 tclass=bpf permissive=1 Was caused by: Missing type enforcement (TE) allow rule. You can use audit2allow to generate a loadable module to allow this access. type=AVC msg=audit(1626855920.120:998): avc: denied { prog_run } for pid=3905 comm="runc" scontext=system_u:system_r:container_runtime_t:s0 tcontext=system_u:system_r:init_t:s0 tclass=bpf permissive=1 Was caused by: Missing type enforcement (TE) allow rule. You can use audit2allow to generate a loadable module to allow this access.
audit2allow
audit2allow 可以通过分析审计日志为解决问题产出可行的模块包
例如:
# cat /var/log/audit/audit.log | audit2allow -M docker
将会在当前路径先产出一个后缀名为 pp 的模块包,随后可以通过 semanage 加载此模块包。
autrace
autrace
可以用来跟踪设置的规则是否生效:
# auditctl -D No rules autrace /usr/bin/less Waiting to execute: /usr/bin/less Cleaning up... No rules Trace complete. You can locate the records with 'ausearch -i -p 7642'
sealert
sealert 是一个具有 GUI 界面的、为用户提供建议的系统,在 用户 模式下使用 sealert -b
可以启用其 GUI 界面。