【Linux从入门到精通】第46篇:SELinux与AppArmor——Linux的安全增强模块

目录

一、引言:rwx权限为什么不够用?

[二、DAC vs MAC:两种安全模型](#二、DAC vs MAC:两种安全模型)

[2.1 DAC:用户自主决定](#2.1 DAC:用户自主决定)

[2.2 MAC:管理员统一控制](#2.2 MAC:管理员统一控制)

[2.3 类比理解](#2.3 类比理解)

三、SELinux:基于标签的强制访问控制

[3.1 SELinux的核心概念](#3.1 SELinux的核心概念)

[3.2 SELinux的三种模式](#3.2 SELinux的三种模式)

四、audit2why:找到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故障排查实战)

六、SELinux/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相关命令(getenforcerestoreconaudit2why)可能完全不存在。这些系统使用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"。当遇到权限问题时:

  1. 先用audit2why(SELinux)或grep apparmor /var/log/syslog(AppArmor)找出拒绝原因

  2. 如果是配置错误(标签/路径不对),修正它

  3. 如果确实是策略不匹配,定制一条具体的放行规则

  4. 只有在你完全确认是MAC导致了无法修复的问题时,才考虑对特定服务切换到Permissive/Complain模式

  5. 修改后记得切回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 -Zps -eZrestoreconaudit2why

AppArmor三要素

  • 路径(Path)→ 配置文件 → 系统日志(syslog)

  • 核心工具:aa-statusaa-complainaa-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工具集的execsnoopopensnoop将作为入门实战,你会看到"谁在偷偷创建进程、谁在默默打开敏感文件"------这些实时观测能力将把你从"查日志"提升到"看内核"。


延伸思考 :为什么各大Linux发行版不约而同地引入了强制访问控制?因为传统的Unix权限模型(rwx)诞生于20世纪70年代,当时的安全威胁主要是多用户主机上用户之间互相偷看文件。而在互联网时代,主要威胁变成了服务程序被远程攻击者利用------攻击者拿到了www-data用户的权限,就能在www-data被允许的范围内为所欲为。MAC正是为了应对这种"合法用户的非法操作"场景而生的------它不是增加新锁,而是限定每个程序只能拿有限的钥匙。

相关推荐
云天AI实战派7 小时前
ChatGPT/AI 智能体功能异常排查指南:账号安全、权限灰度到审批流卡点的全流程解决方案
人工智能·安全·chatgpt
都在酒里7 小时前
在公共服务器上构建 RK3588 SDK 的纯净 Docker 方案
运维·服务器·docker
m0_738120727 小时前
后渗透维权提权基础——CTF模拟红队进行权限维持(二)
前端·网络·windows·python·安全·php
落羽的落羽7 小时前
【网络】计算机网络世界的基础概念
linux·服务器·网络·c++·人工智能·计算机网络·机器学习
TBrL7UtdTELTTdut4BAL7 小时前
F7015TV3 光猫 Telnet 命令配置 DHCP 服务器
运维·服务器·网络
海兰7 小时前
将 Cursor 连接到生产日志:通过 Elastic MCP 服务器
运维·服务器·elasticsearch
计算机安禾7 小时前
【Linux从入门到精通】第41篇:Linux内核编译初体验——裁剪属于你自己的内核
linux·运维·服务器
Elastic 中国社区官方博客7 小时前
2026 年金融服务可观测性现状:从实施到业务影响
大数据·运维·人工智能·elasticsearch·搜索引擎·金融·自动化
木木_王8 小时前
嵌入式Linux学习 | 数据结构 (Day03)顺序表与单链表 超详细解析(含 C 语言实现 + 作业 + 避坑指南)
linux·c语言·数据结构·学习