目录
[二、DAC vs MAC:两种安全模型](#二、DAC vs MAC:两种安全模型)
[2.1 DAC:用户自主决定](#2.1 DAC:用户自主决定)
[2.2 MAC:管理员统一控制](#2.2 MAC:管理员统一控制)
[2.3 类比理解](#2.3 类比理解)
[3.1 SELinux的核心概念](#3.1 SELinux的核心概念)
[3.2 SELinux的三种模式](#3.2 SELinux的三种模式)
[4.1 经典场景:Nginx无法访问网站文件](#4.1 经典场景:Nginx无法访问网站文件)
[4.2 audit2why:从审计日志中解读原因](#4.2 audit2why:从审计日志中解读原因)
[4.3 正确修复方式](#4.3 正确修复方式)
五、AppArmor:Ubuntu/Debian的强制访问控制
[5.1 AppArmor与SELinux的对比](#5.1 AppArmor与SELinux的对比)
[5.2 AppArmor的四种模式](#5.2 AppArmor的四种模式)
[5.3 AppArmor故障排查实战](#5.3 AppArmor故障排查实战)
[6.1 三个运行级别](#6.1 三个运行级别)
[6.2 使用原则](#6.2 使用原则)
一、引言:rwx权限为什么不够用?
在第8篇和第9篇中,我们花了大量篇幅学习Linux的DAC(Discretionary Access Control,自主访问控制)权限体系------r、w、x、chmod 755、chown。这套体系的核心逻辑是:文件的拥有者自主决定谁能访问它。
但在现代服务器环境中,DAC有一个致命盲区:它只根据"谁在操作"来判断,完全不关心"通过什么程序来操作"。
考虑一个场景:Web应用(运行在Nginx/PHP下)存在一个文件上传漏洞。攻击者上传了一个恶意PHP脚本,然后通过浏览器访问它。从rwx权限的角度看:
-
脚本被写入了
/var/www/uploads/目录------Nginx用户www-data对此目录有写权限 -
恶意脚本执行时,它继承了
www-data用户的全部权限 -
它可以读取
/etc/passwd(这个文件对所有用户可读) -
它可以读取数据库配置文件
/var/www/config/database.php
rwx权限体系对这一切都不会阻止------因为恶意脚本的操作都在www-data用户的合法权限范围内。它充其量只能限制www-data用户能访问哪些文件 ,但控制不了以什么方式访问、通过什么程序访问。
SELinux和AppArmor正是为填补这个盲区而设计的------它们不是取代rwx,而是在其之上增加了一层额外控制。
二、DAC vs MAC:两种安全模型
2.1 DAC:用户自主决定
DAC(自主访问控制)是我们熟悉的rwx权限模型。它的特征是:
-
文件所有者可以随意改变文件的权限(
chmod 777) -
进程以用户的身份运行,拥有该用户的全部权限
-
如果一个进程被入侵,攻击者就获得了该用户的所有权限
2.2 MAC:管理员统一控制
MAC(Mandatory Access Control,强制访问控制)中,访问决策不是由文件所有者决定,而是由系统管理员预先设定的全局安全策略强制控制。
特征是:
-
即使你是root,也不能绕过MAC的限制
-
即使chmod设成了777,MAC也可以阻止访问
-
可以为每个进程独立设置权限边界(Nginx只能访问Web目录,SSH守护进程只能访问密钥文件等)
2.3 类比理解
| 模型 | 类比 | 决策者 |
|---|---|---|
| DAC(rwx) | 每个房间的主人自己决定配几把钥匙,给谁钥匙 | 文件所有者 |
| MAC(SELinux/AppArmor) | 大楼安保中心统一规定:清洁工只能进打扫间,访客只能进大厅,IT人员才能进机房。即使主人说"我请他进来",规则也不允许 | 系统安全管理员 |
两者叠加生效:DAC和MAC必须同时允许,操作才能执行。任何一层的拒绝都会导致"Permission denied"。
三、SELinux:基于标签的强制访问控制
3.1 SELinux的核心概念
SELinux(Security-Enhanced Linux)由美国国家安全局(NSA)开发,它给系统中的每个文件、进程、端口、设备都打上了一个安全标签(Security Context)。访问是否被允许,取决于标签之间的匹配规则,而不是用户身份。
每个对象都有标签:
bash
# 查看文件的安全上下文
ls -Z /var/www/html/index.html
# -rw-r--r--. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html
# 查看进程的安全上下文
ps -eZ | grep nginx
# system_u:system_r:httpd_t:s0 12345 ? nginx: worker process
标签由四个部分组成:用户:角色:类型:敏感度
其中最重要的是第三部分------类型 。SELinux的大多数访问控制规则是基于类型的:什么类型的进程(httpd_t)可以访问什么类型的文件(httpd_sys_content_t)。
3.2 SELinux的三种模式
bash
# 查看当前模式
getenforce
# 查看配置文件中的模式
cat /etc/selinux/config
| 模式 | 命令 | 行为 |
|---|---|---|
| Enforcing(强制) | setenforce 1 |
严格执行策略,违规操作被拒绝并记录日志 |
| Permissive(宽容) | setenforce 0 |
不拒绝违规操作,但记录日志(调试用) |
| Disabled(禁用) | 修改配置文件后重启 | 完全关闭SELinux |
重要 :setenforce 0只是临时切换到Permissive模式,重启后恢复。要永久禁用,需要修改/etc/selinux/config中的SELINUX=disabled并重启。
四、audit2why:找到SELinux拒绝的真正原因
4.1 经典场景:Nginx无法访问网站文件
你部署了一个网站:
bash
sudo mv ~/mywebsite /var/www/
sudo chown -R www-data:www-data /var/www/mywebsite
sudo chmod -R 755 /var/www/mywebsite
rwx权限全部正确,但Nginx仍然返回403 Forbidden。用tail /var/log/nginx/error.log看到:
text
Permission denied) while reading upstream
/var/log/audit/audit.log中也有SELinux的访问被拒记录。大多数运维的第一反应是setenforce 0------SELinux禁掉了,问题解决。
但这种做法等于抛弃了整套强制访问控制体系,只因为一个文件标签不对。正确的做法是用工具找出原因并修正。
4.2 audit2why:从审计日志中解读原因
bash
# 搜索SELinux拒绝记录并给出人类可读的解释(CentOS/RHEL)
sudo grep AVC /var/log/audit/audit.log | audit2why
# 如果audit.log中没有,检查SELinux的错误日志(Ubuntu)
sudo grep AVC /var/log/syslog | audit2why
输出会明确指出原因和修复建议:
text
type=AVC msg=audit(1234567890.123:4567): avc: denied { read } for
pid=12345 comm="nginx" name="index.html" dev="sda1" ino=56789
scontext=system_u:system_r:httpd_t:s0
tcontext=unconfined_u:object_r:default_t:s0
Was caused by:
文件标签错误 - 文件 /var/www/mywebsite/index.html 的标签是 default_t,但应该
是 httpd_sys_content_t。用 restorecon 修复。
问题的本质 :文件是用mv ~/mywebsite /var/www/移动过来的,它继承了原来家目录下的SELinux标签(default_t),而不是Web目录应有的httpd_sys_content_t。Nginx进程(httpd_t类型)被SELinux禁止读取default_t类型的文件。
4.3 正确修复方式
bash
# 方法一:恢复目录的默认SELinux标签(推荐)
sudo restorecon -Rv /var/www/mywebsite
# 方法二:临时调整标签(用于测试)
sudo chcon -R -t httpd_sys_content_t /var/www/mywebsite
# 验证修复
ls -Z /var/www/mywebsite/index.html
# 应该看到 httpd_sys_content_t 标签
修复后,Nginx立即可以正常访问------SELinux全程保持Enforcing模式,安全没有被削弱。
五、AppArmor:Ubuntu/Debian的强制访问控制
5.1 AppArmor与SELinux的对比
Ubuntu和Debian默认使用AppArmor作为强制访问控制系统(大部分SELinux命令在这些系统上不可用)。两者的设计理念截然不同:
| 对比维度 | SELinux | AppArmor |
|---|---|---|
| 标识方式 | 文件系统的扩展属性中保存标签 | 文件路径匹配规则 |
| 策略粒度 | 极其灵活(一切皆标签) | 相对粗(路径+程序名) |
| 配置文件 | 二进制策略模块 | /etc/apparmor.d/下的纯文本 |
| 学习曲线 | 陡(标签体系庞大) | 平缓(路径匹配很直观) |
| 发行版 | RHEL/CentOS/Fedora | Ubuntu/Debian/openSUSE |
一句话概括:SELinux控制"什么类型的进程能访问什么标签的文件",AppArmor控制"这个程序能访问哪些路径"。
5.2 AppArmor的四种模式
bash
# 查看所有配置文件的状态
sudo aa-status
| 模式 | 含义 | 特点 |
|---|---|---|
| Enforce | 强制模式 | 违反规则被拒绝并记录 |
| Complain | 抱怨模式 | 违反规则只记录,不拒绝(调试用) |
| Unconfined | 无限制 | 进程不受AppArmor控制 |
| Disabled | 已禁用 | 配置文件存在但不生效 |
5.3 AppArmor故障排查实战
场景:MySQL安装后无法启动
bash
sudo systemctl status mysql
# (code=exited, status=1/FAILURE)
# 检查AppArmor状态
sudo aa-status | grep mysql
# mysql: enforce ← MySQL正处于强制模式
# 查看AppArmor拒绝日志
sudo grep apparmor /var/log/syslog | grep DENIED
# 临时切换到complain模式,确认是AppArmor导致
sudo aa-complain /etc/apparmor.d/usr.sbin.mysql
sudo systemctl restart mysql # 此时应该能启动
# 如果确认是AppArmor配置问题,更新配置文件
sudo aa-logprof # 分析日志并交互式更新AppArmor配置
# 更新后调回强制模式
sudo aa-enforce /etc/apparmor.d/usr.sbin.mysql
sudo systemctl restart mysql
aa-logprof会读取AppArmor的拒绝日志,询问你是否将这些被拒绝的操作加入允许规则,然后自动生成更新后的配置文件。这是一个互动式的"学习模式"------让AppArmor从实际运行中学习进程需要什么权限。
关键差异 :如果你用的是Debian/Ubuntu系统,SELinux相关命令(getenforce、restorecon、audit2why)可能完全不存在。这些系统使用AppArmor命令:aa-status(查看状态)、aa-complain(切换抱怨模式)、aa-enforce(切换强制模式)、aa-logprof(日志分析和配置更新)。
六、SELinux/AppArmor的选择策略
6.1 三个运行级别
| 运行模式 | 命令 | 风险 | 适用场景 |
|---|---|---|---|
| 无MAC | SELinux Disabled / AppArmor全Unconfined | 高 | 开发环境、性能测试 |
| Permissive/Complain | setenforce 0 / aa-complain |
中 | 短期调试、定位问题时临时使用 |
| Enforcing/Enforce | setenforce 1 / aa-enforce |
低 | 生产环境标准运行模式 |
6.2 使用原则
永远不要"第一反应关SELinux"。当遇到权限问题时:
-
先用
audit2why(SELinux)或grep apparmor /var/log/syslog(AppArmor)找出拒绝原因 -
如果是配置错误(标签/路径不对),修正它
-
如果确实是策略不匹配,定制一条具体的放行规则
-
只有在你完全确认是MAC导致了无法修复的问题时,才考虑对特定服务切换到Permissive/Complain模式
-
修改后记得切回Enforcing/Enforce
一个新服务上线时,MAC策略可能需要适配。这不是MAC的"bug",而是你的新服务还不符合安全策略的定义。修正策略配置是正常的运维操作,就像为新服务配置防火墙规则一样。
七、故障场景速查
| 现象 | 可能原因 | 诊断命令 | 解决方案 |
|---|---|---|---|
| Nginx 403 | SELinux标签错误 | audit2why < /var/log/audit/audit.log |
restorecon -Rv /var/www/ |
| 服务无法启动 | AppArmor策略阻断 | grep apparmor /var/log/syslog |
aa-logprof |
| 自定义端口无法监听 | SELinux端口类型不对 | `semanage port -l | grep http` |
| 文件移动后权限异常 | 标签随文件移动 | ls -Z 文件路径 |
restorecon -v 文件路径 |
八、本篇小结
DAC vs MAC:
-
DAC(rwx):你决定你自己的文件谁能访问
-
MAC(SELinux/AppArmor):管理员统一规定每个程序能干什么
SELinux三要素:
-
标签(Security Context)→ 规则(Policy)→ 审计日志(audit.log)
-
核心工具:
ls -Z、ps -eZ、restorecon、audit2why
AppArmor三要素:
-
路径(Path)→ 配置文件 → 系统日志(syslog)
-
核心工具:
aa-status、aa-complain、aa-logprof
黄金法则:
遇到权限问题,先用诊断工具找出原因,再精准修正。不要闭着眼睛
setenforce 0。
动手练习
bash
# 1. 确认你的系统用的是SELinux还是AppArmor
which getenforce 2>/dev/null && echo "SELinux" || echo "AppArmor(或未启用MAC)"
# SELinux系统:
# 2. 查看模式和关键文件标签
getenforce
ls -Z /var/www/html 2>/dev/null || echo "目录不存在"
# 3. 查看最近的SELinux拒绝记录
sudo grep AVC /var/log/audit/audit.log | tail -5
# 4. 如果上面的命令有输出,解读原因
sudo grep AVC /var/log/audit/audit.log | audit2why | tail -20
# AppArmor系统:
# 2. 查看AppArmor状态
sudo aa-status | head -10
# 3. 查看最近的AppArmor拒绝记录
sudo grep apparmor /var/log/syslog | grep DENIED | tail -5
九、下篇预告
SELinux通过审计日志告诉我们"谁被拒绝了"------但所有分析都是事后的、被动的。在下一篇文章中,我们将进入主动、实时的内核观测领域。
《SystemTap与eBPF------内核观测的显微镜》将带你学习动态追踪技术------在不修改内核源码、不重启系统的情况下,精确观测内核函数的执行细节、统计特定事件的发生频率。BCC工具集的execsnoop、opensnoop将作为入门实战,你会看到"谁在偷偷创建进程、谁在默默打开敏感文件"------这些实时观测能力将把你从"查日志"提升到"看内核"。
延伸思考 :为什么各大Linux发行版不约而同地引入了强制访问控制?因为传统的Unix权限模型(rwx)诞生于20世纪70年代,当时的安全威胁主要是多用户主机上用户之间互相偷看文件。而在互联网时代,主要威胁变成了服务程序被远程攻击者利用------攻击者拿到了www-data用户的权限,就能在www-data被允许的范围内为所欲为。MAC正是为了应对这种"合法用户的非法操作"场景而生的------它不是增加新锁,而是限定每个程序只能拿有限的钥匙。