第92课 - AppArmor 应用防护
难度:advanced
所属模块:安全加固
标签:apparmor, security
上一课:SELinux 安全增强
下一课:fail2ban 防暴力破解
1. 学习目标
完成本课学习后,你将能够:
- 理解 AppArmor 的核心思想及其与 SELinux 的主要区别
- 掌握 AppArmor 的基本操作,包括查看状态、切换模式、管理配置文件
- 学会编写简单的 AppArmor 配置文件,实现应用的基本访问控制
- 理解配置文件的结构与语法,能够阅读和调试现有配置
- 能够为常见服务(如 Nginx、自定义程序)部署 AppArmor 防护
2. 核心概念
什么是 AppArmor?
AppArmor(Application Armor)是 Linux 系统中的一种强制访问控制(MAC)安全模块。它通过 为每个程序定义独立的配置文件,限制程序可以访问的文件、网络资源等系统能力。
AppArmor vs SELinux
| 特性 | AppArmor | SELinux |
|---|---|---|
| 配置方式 | 基于路径(容易理解) | 基于标签(更灵活复杂) |
| 学习曲线 | 较平缓 | 较陡峭 |
| 默认使用 | Ubuntu、SUSE | RHEL、CentOS |
| 粒度 | 应用程序级别 | 系统全局级别 |
| 调试难度 | 相对简单 | 较复杂 |
两种模式
- Enforce(强制模式):实际阻止违规行为
- Complain(投诉模式):只记录违规,不阻止(用于调试)
配置文件结构
一个典型的 AppArmor 配置文件(通常位于 /etc/apparmor.d/)包含:
# 头部信息(程序路径和元数据)
/usr/sbin/nginx {
# 能力声明(capabilities)
# 文件访问规则(r, w, x等)
# 网络访问规则
# #include 指令
}
3. 代码示例
3.1 查看 AppArmor 状态
# 检查 AppArmor 是否已安装并启用
sudo aa-status
# 输出示例:
# apparmor module is loaded.
# 11 profiles are loaded.
# 11 profiles are in enforce mode.
# /sbin/dhclient
# ...
# 0 profiles are in complain mode.
# 4 processes have profiles defined.
3.2 切换模式(以某个配置文件为例)
# 列出所有配置文件
sudo aa-status | head -20
# 将 Nginx 配置文件切换为投诉模式(调试用)
sudo aa-complain /etc/apparmor.d/usr.sbin.nginx
# 切换回强制模式
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx
# 批量将所有配置文件设为强制模式
sudo aa-enforce /etc/apparmor.d/*
3.3 为自定义程序创建简单配置文件
假设我们有一个简单的 Python Web 服务器 /opt/myapp/server.py:
# 1. 首先创建程序的配置文件(模板)
sudo aa-genprof /opt/myapp/server.py
# 2. 运行程序并让 AppArmor 学习其行为
sudo /opt/myapp/server.py &
# 3. 在另一个终端,与程序交互(访问网页、读写文件等)
# 4. 回到 aa-genprof 终端,按 S 扫描日志,按 A 允许所需访问
# 5. 完成后按 F 完成配置文件生成
# 6. 生成的配置文件位于 /etc/apparmor.d/opt.myapp.server.py
cat /etc/apparmor.d/opt.myapp.server.py
3.4 手动编写简单配置文件
为 Nginx 创建一个基础配置文件(简化版):
# /etc/apparmor.d/usr.sbin.nginx.sample
#include <tunables/global>
/usr/sbin/nginx {
# 允许访问标准库文件
#include <abstractions/base>
#include <abstractions/nameservice>
#include <abstractions/openssl>
# 允许访问 Nginx 配置文件
/etc/nginx/** r,
# 允许读取网页根目录
/var/www/** r,
# 允许写入日志文件
/var/log/nginx/*.log w,
# 允许绑定网络端口
network inet stream,
network inet6 stream,
# 允许管理进程(worker)
signal (send) set=(child) peer=/usr/sbin/nginx,
# 允许使用 /tmp(注意安全性)
/tmp/nginx* rw,
}
3.5 重新加载 AppArmor 配置
# 修改配置文件后,重新加载
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx
# 验证新配置是否已加载
sudo aa-status | grep nginx
4. 实践练习
练习 1:AppArmor 基础操作
要求:
- 检查系统中已加载的 AppArmor 配置文件数量
- 将
/usr/sbin/dhclient配置文件临时切换为投诉模式 - 30 秒后自动切回强制模式(提示:使用 sleep 命令)
预期输出:
$ sudo aa-status | grep -c "profiles are loaded"
11
$ sudo aa-complain /etc/apparmor.d/sbin.dhclient
Setting /etc/apparmor.d/sbin.dhclient to complain mode.
$ sleep 30 && sudo aa-enforce /etc/apparmor.d/sbin.dhclient &
[1] 12345
# 30秒后显示:
Setting /etc/apparmor.d/sbin.dhclient to enforce mode.
练习 2:编写基本配置文件
要求:为以下 Python 脚本编写 AppArmor 配置文件:
#!/usr/bin/env python3
# /opt/app/app.py
import os
# 读取配置文件
with open('/etc/myapp/config.json', 'r') as f:
config = f.read()
# 写入日志
with open('/var/log/myapp/app.log', 'a') as f:
f.write(f"App started: {os.getpid()}\n")
# 临时文件操作
with open('/tmp/myapp_temp.txt', 'w') as f:
f.write("temp data")
预期配置文件内容(至少包含):
/opt/app/app.py {
#include <abstractions/base>
/etc/myapp/config.json r,
/var/log/myapp/app.log w,
/tmp/myapp_temp.txt rw,
}
练习 3:综合应用
要求:
- 为 Nginx 创建一个新的配置文件,只允许访问
/var/www/html和/var/www/static - 限制 Nginx 不能访问
/etc/shadow(即使以 root 运行) - 先在投诉模式下测试,确认无误后切换到强制模式
- 编写一个测试 HTML 页面,验证 Nginx 能正常提供服务
预期验证步骤:
# 1. 创建新配置文件
sudo vim /etc/apparmor.d/usr.sbin.nginx.custom
# 2. 加载并测试
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx.custom
sudo aa-complain /etc/apparmor.d/usr.sbin.nginx.custom
# 3. 重启 Nginx 并测试
sudo systemctl restart nginx
curl http://localhost/test.html
# 4. 切换到强制模式
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx.custom
5. 常见错误
错误 1:语法错误导致配置文件无法加载
# 错误示例:缺少逗号
/usr/sbin/nginx {
/etc/nginx/** r # 错误:缺少逗号
/var/www/** r,
}
# 正确:
/usr/sbin/nginx {
/etc/nginx/** r, # 注意逗号
/var/www/** r,
}
调试方法:
# 检查语法
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx
# 如果语法错误,会明确提示哪一行有问题
# 或使用 aa-logprof 工具分析
sudo aa-logprof
错误 2:忘记重新加载配置文件
# 修改配置文件后,必须重新加载
# 错误做法:只修改文件,不重新加载
sudo vim /etc/apparmor.d/usr.sbin.nginx
# 忘记执行重新加载命令
# 正确做法:
sudo vim /etc/apparmor.d/usr.sbin.nginx
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx
错误 3:路径权限规则不完整
# 错误:只允许读取目录,但不允许列出目录内容
/var/www/html/ r, # 只能读取目录 inode
/var/www/html/** r, # 可以读取文件内容
# 正确:同时允许读取目录和文件
/var/www/html/ r,
/var/www/html/** r,
错误 4:过度宽松的规则
# 危险规则:允许访问所有文件
/** rw, # 绝对不要这样写!
# 应该具体到需要的路径
/etc/nginx/** r,
/var/log/nginx/** w,
错误 5:能力(capabilities)使用不当
# 错误:不必要的 capabilities
capability net_bind_service, # 如果服务不绑定 <1024 端口则不需要
capability sys_admin, # 极其危险,几乎从不需要
# 正确:只添加必要的 capabilities
capability dac_override, # 如果需要绕过文件权限检查
capability setuid, # 如果需要切换用户
6. 小结
关键要点回顾:
-
AppArmor 的核心优势:
- 基于路径的策略,比 SELinux 更易理解和调试
- 每个应用程序独立的配置文件,管理清晰
- 提供投诉模式,便于安全地测试新配置
-
与 SELinux 的互补选择:
- Ubuntu/SUSE 系统默认使用 AppArmor
- RHEL/CentOS 系统默认使用 SELinux
- 两者不能同时使用,选择取决于发行版和个人偏好
-
基本操作命令:
sudo aa-status # 查看状态 sudo aa-complain /path # 切换投诉模式 sudo aa-enforce /path # 切换强制模式 sudo apparmor_parser -r /path # 重新加载配置 sudo aa-genprof /path # 自动生成配置文件 -
配置文件编写要点:
- 从模板开始,逐步细化
- 遵循最小权限原则
- 使用
#include引入标准抽象 - 修改后必须重新加载
-
最佳实践:
- 新程序先在投诉模式下运行和测试
- 定期审查和更新配置文件
- 监控 AppArmor 日志:
/var/log/syslog或journalctl -k - 保持配置文件在版本控制中管理
下一步学习建议:
- 学习
aa-logprof和aa-autodep的高级用法 - 了解如何创建自定义的 AppArmor 抽象(abstractions)
- 实践为容器化应用配置 AppArmor
- 学习如何与 Docker/Kubernetes 集成 AppArmor
课后思考:如果你的服务器运行着一个需要读取敏感配置文件(如数据库密码)的 Web 应用,你会如何设计 AppArmor 配置文件来平衡安全性和功能性?
练习编辑器
rust
Loading...