92·安全加固高级

AppArmor 应用防护

apparmorsecurity

第92课 - AppArmor 应用防护

难度:advanced
所属模块:安全加固
标签:apparmor, security
上一课:SELinux 安全增强
下一课:fail2ban 防暴力破解


1. 学习目标

完成本课学习后,你将能够:

  1. 理解 AppArmor 的核心思想及其与 SELinux 的主要区别
  2. 掌握 AppArmor 的基本操作,包括查看状态、切换模式、管理配置文件
  3. 学会编写简单的 AppArmor 配置文件,实现应用的基本访问控制
  4. 理解配置文件的结构与语法,能够阅读和调试现有配置
  5. 能够为常见服务(如 Nginx、自定义程序)部署 AppArmor 防护

2. 核心概念

什么是 AppArmor?

AppArmor(Application Armor)是 Linux 系统中的一种强制访问控制(MAC)安全模块。它通过 为每个程序定义独立的配置文件,限制程序可以访问的文件、网络资源等系统能力。

AppArmor vs SELinux

特性AppArmorSELinux
配置方式基于路径(容易理解)基于标签(更灵活复杂)
学习曲线较平缓较陡峭
默认使用Ubuntu、SUSERHEL、CentOS
粒度应用程序级别系统全局级别
调试难度相对简单较复杂

两种模式

  1. Enforce(强制模式):实际阻止违规行为
  2. 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 基础操作

要求

  1. 检查系统中已加载的 AppArmor 配置文件数量
  2. /usr/sbin/dhclient 配置文件临时切换为投诉模式
  3. 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:综合应用

要求

  1. 为 Nginx 创建一个新的配置文件,只允许访问 /var/www/html/var/www/static
  2. 限制 Nginx 不能访问 /etc/shadow(即使以 root 运行)
  3. 先在投诉模式下测试,确认无误后切换到强制模式
  4. 编写一个测试 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. 小结

关键要点回顾:

  1. AppArmor 的核心优势

    • 基于路径的策略,比 SELinux 更易理解和调试
    • 每个应用程序独立的配置文件,管理清晰
    • 提供投诉模式,便于安全地测试新配置
  2. 与 SELinux 的互补选择

    • Ubuntu/SUSE 系统默认使用 AppArmor
    • RHEL/CentOS 系统默认使用 SELinux
    • 两者不能同时使用,选择取决于发行版和个人偏好
  3. 基本操作命令

    sudo aa-status              # 查看状态
    sudo aa-complain /path      # 切换投诉模式
    sudo aa-enforce /path       # 切换强制模式
    sudo apparmor_parser -r /path # 重新加载配置
    sudo aa-genprof /path       # 自动生成配置文件
    
  4. 配置文件编写要点

    • 从模板开始,逐步细化
    • 遵循最小权限原则
    • 使用 #include 引入标准抽象
    • 修改后必须重新加载
  5. 最佳实践

    • 新程序先在投诉模式下运行和测试
    • 定期审查和更新配置文件
    • 监控 AppArmor 日志:/var/log/syslogjournalctl -k
    • 保持配置文件在版本控制中管理

下一步学习建议:

  • 学习 aa-logprofaa-autodep 的高级用法
  • 了解如何创建自定义的 AppArmor 抽象(abstractions)
  • 实践为容器化应用配置 AppArmor
  • 学习如何与 Docker/Kubernetes 集成 AppArmor

课后思考:如果你的服务器运行着一个需要读取敏感配置文件(如数据库密码)的 Web 应用,你会如何设计 AppArmor 配置文件来平衡安全性和功能性?

练习编辑器

rust
Loading...

继续学习

完成本课后,建议继续学习下一课「fail2ban 防暴力破解」 以巩固所学知识。