AppArmor

Linux AppArmor 深度解析:从原理到实战的完整指南

目录

  1. 概述:什么是 AppArmor
  2. 历史背景与设计哲学
  3. 核心架构与工作原理
  4. 配置文件(Profile)语法详解
  5. 两种运行模式:Enforce vs Complain
  6. 工具链与实战
  7. AppArmor 与 Docker 容器安全
  8. AppArmor 与 Kubernetes
  9. AppArmor vs SELinux:选型指南
  10. 安全加固最佳实践
  11. 常见问题排查
  12. 总结

1. 概述:什么是 AppArmor

AppArmor(Application Armor,应用程序盔甲)是 Linux 内核的强制访问控制(MAC,Mandatory Access Control)安全模块。它允许系统管理员为每个应用程序定义安全配置文件(Profile),精确控制程序能访问哪些文件、使用哪些 Linux Capabilities、建立哪些网络连接等。

核心特性

特性 说明
基于路径 策略基于文件路径而非 inode/标签,直观易懂
以程序为中心 每个可执行文件绑定一个 Profile,非白名单程序不受限制
默认放行 未配置 Profile 的程序不受任何限制(与 SELinux 的默认拒绝相反)
渐进式部署 支持 Complain(仅记录)和 Enforce(强制拦截)两种模式
内核级执行 策略在内核中执行,被限制的应用无法绕过或修改策略
与 LSM 集成 作为 Linux Security Module 框架的一部分,与内核深度整合

AppArmor 在安全架构中的位置

┌─────────────────────────────────────────────────┐
│                   用户空间                        │
│  ┌──────────┐  ┌──────────┐  ┌───────────────┐  │
│  │ 应用程序  │  │aa-genprof│  │apparmor_parser│  │
│  │ (受限)   │  │(策略生成) │  │ (策略加载)     │  │
│  └────┬─────┘  └──────────┘  └───────┬───────┘  │
│       │                              │          │
├───────┼──────────────────────────────┼──────────┤
│       │        内核空间               │          │
│       ▼                              ▼          │
│  ┌─────────────────────────────────────────┐    │
│  │           LSM Hooks (安全钩子)           │    │
│  │  ┌─────────────────────────────────┐    │    │
│  │  │     AppArmor LSM Module         │    │    │
│  │  │  ┌──────────┐ ┌───────────────┐ │    │    │
│  │  │  │ 策略缓存  │ │  DFA 匹配引擎 │ │    │    │
│  │  │  │ (Policy   │ │  (确定性有限  │ │    │    │
│  │  │  │  Cache)   │ │   自动机)     │ │    │    │
│  │  │  └──────────┘ └───────────────┘ │    │    │
│  │  └─────────────────────────────────┘    │    │
│  └─────────────────────────────────────────┘    │
│                                                  │
│  文件系统  │  网络栈  │  Capabilities  │  IPC     │
└─────────────────────────────────────────────────┘

2. 历史背景与设计哲学

发展时间线

时间 里程碑
1998 Immunix 公司开始开发 AppArmor 的前身 SubDomain
2005 Novell 收购 Immunix,将 SubDomain 重命名为 AppArmor
2006 AppArmor 首次以补丁形式发布(Linux 2.6.15+)
2007 Novell 将 AppArmor 开源(GPL)
2009 AppArmor 2.3 发布,网络规则、DBus 规则引入
2010 Linux 2.6.36:AppArmor 合入主线内核
2014 AppArmor 3.0:DFA 策略编译引擎、细粒度网络控制
2019+ 成为 Ubuntu、SUSE 的默认 MAC 系统;深度集成 Docker/K8s
2024+ 策略缓存优化、用户空间通知增强、io_uring 控制支持

设计哲学:与 SELinux 的根本差异

AppArmor 的设计遵循 KISS(Keep It Simple, Stupid) 原则:

设计维度 AppArmor SELinux
标识方式 文件路径(/usr/bin/nginx 安全标签(system_u:object_r:httpd_exec_t:s0
默认行为 未配置 = 不受限 未配置 = 全部拒绝
策略粒度 程序级别 进程/文件/端口/用户全维度
学习曲线 低(数小时即可上手) 高(需要系统学习)
适用场景 单应用隔离、容器安全 多级安全(MLS)、军事/政府系统

哲学核心:AppArmor 认为,安全策略应该与用户日常使用的应用程序名称和路径直接对应,而非依赖抽象的安全标签系统。


3. 核心架构与工作原理

3.1 LSM 框架集成

AppArmor 作为 Linux Security Module(LSM)框架的一部分,通过在内核关键路径上注册 钩子函数(Hooks) 实现访问控制。

内核编译配置:

# 启用 AppArmor
CONFIG_SECURITY=y
CONFIG_SECURITY_APPARMOR=y

# 设置为默认 LSM(可与其他 LSM 共存)
CONFIG_LSM="apparmor,selinux"

# 内核启动参数
# 禁用 AppArmor:apparmor=0
# 指定 LSM 顺序:lsm=apparmor,selinux

主要 LSM 钩子位置:

系统调用入口
    │
    ▼
open("/etc/shadow", O_RDONLY)
    │
    ▼
security_file_open()          ← AppArmor LSM Hook
    │
    ├─ 检查当前任务的 Profile
    ├─ DFA 匹配:/etc/shadow 是否在允许列表中?
    │
    ├─ 允许 → 继续执行
    └─ 拒绝 → 返回 -EACCES + 审计日志

3.2 基于路径的访问控制

AppArmor 的核心特征是基于路径(Path-Based)的访问控制,而非 SELinux 的基于标签(Label-Based)

路径解析过程:

// 内核中 AppArmor 的路径解析(简化版)
// 源码:security/apparmor/file.c

当进程尝试访问 /var/www/html/index.html 时:

1. 获取当前任务的 Profile(如 /usr/sbin/nginx
2. 将目标路径规范化为绝对路径
3.  Profile 的规则集中匹配:
   - /var/www/html/index.html
   - /var/www/html/**
   - /var/www/**
   - /var/**
   - /**
4. 找到第一条匹配规则,应用其权限

优点:

  • 策略直观,直接使用文件路径,无需理解标签系统
  • 文件移动/重命名后策略自动适用(如果通配符规则正确)
  • 排查方便:dmesg 中直接显示被拒绝的文件路径

局限:

  • 硬链接可能绕过路径检查(因为 AppArmor 基于路径而非 inode)
  • 需要确保文件系统路径不被篡改

3.3 策略编译与 DFA 引擎

AppArmor 策略在内核中使用 确定性有限自动机(DFA,Deterministic Finite Automaton) 进行高效匹配。

策略加载流程:

文本 Profile ──► apparmor_parser ──► 二进制策略 ──► 内核 DFA 引擎
  (/etc/         (用户空间)          (编译后的       (内核空间
   apparmor.d/)                      策略缓存)        高效匹配)
# 编译并加载 Profile
sudo apparmor_parser -r /etc/apparmor.d/usr.bin.nginx

# 查看已加载的策略
sudo aa-status

# 预编译策略(加速启动)
sudo apparmor_parser -Q /etc/apparmor.d/usr.bin.nginx

4. 配置文件(Profile)语法详解

4.1 配置文件结构

AppArmor Profile 文件存储在 /etc/apparmor.d/,文件命名通常将路径中的 / 替换为 .

/etc/apparmor.d/
├── abstractions/          # 抽象层(可复用的规则片段)
│   ├── base
│   ├── nameservice
│   └── python
├── tunables/              # 全局变量
│   ├── global
│   └── home
├── local/                 # 本地自定义
├── usr.bin.nginx          # Nginx 的 Profile
├── usr.sbin.mysqld        # MySQL 的 Profile
└── usr.bin.evince         # Evince 文档查看器的 Profile

Profile 基本结构:

# 头部:定义 Profile 名称和标志
#include <tunables/global>

profile myapp /usr/bin/myapp flags=(complain) {
  # 包含抽象层
  #include <abstractions/base>

  # 能力规则
  capability net_bind_service,

  # 网络规则
  network inet tcp,

  # 文件规则
  /usr/bin/myapp          mr,
  /etc/myapp/**           r,
  /var/log/myapp.log      rw,
  /tmp/myapp-*            rwl,

  # 拒绝规则(在允许规则之后)
  deny /etc/shadow        r,
}

4.2 文件路径规则与权限

权限字母

权限 含义 说明
r Read(读) 读取文件内容
w Write(写) 写入/截断/创建文件
a Append(追加) 仅追加模式写入
m Memory map(内存映射) mmap() 可执行映射
l Link(链接) 创建硬链接
k Lock(锁定) 文件锁 flock()
x Execute(执行) 执行程序(需配合执行模式)

通配符语法

通配符 含义 示例
* 匹配任意字符(不含 / /tmp/*/tmp/a, /tmp/abc
** 匹配任意字符(含 / /var/**/var/a/b/c
? 匹配单个字符 /tmp/file?/tmp/file1
[abc] 匹配字符集中一个 /tmp/file[123]/tmp/file1
{a,b} 匹配备选项之一 /var/{log,run}/**

规则示例

# 只读访问配置文件目录
/etc/nginx/** r,

# 读写访问日志文件
/var/log/nginx/*.log rw,

# 可读写并可锁定
/var/lib/nginx/** rwk,

# 允许执行脚本(仅读取+映射执行)
/usr/share/nginx/** mr,

# 允许读写 + 创建链接
/tmp/nginx-* rwl,

# 所有者只写(@{OWNER} 变量匹配文件所有者)
@{HOME}/.nginx-tmp rw,

# 明确拒绝(deny 规则优先级高于 allow)
deny /etc/shadow r,
deny /root/** rwx,

4.3 执行模式控制

AppArmor 对子进程的执行提供了精细的模式控制:

模式 语法 行为
ix(inherit) /bin/sh ix, 子进程继承当前 Profile
Px(profile) /bin/sh Px, 子进程切换到自己的 Profile
Cx(child) /bin/sh Cx, 切换到子 Profile(Hat)
Ux(unconfined) /bin/sh Ux, 子进程不受限制
px(profile-clean) /bin/sh px, 切换 Profile 并清理环境
Pix(混合) /bin/sh Pix, 优先 Px,Profile 不存在则 ix
# 示例:Apache 的 Profile
/usr/sbin/apache2 {
    # Apache 主进程
    /usr/sbin/apache2       mr,

    # CGI 脚本:切换到各自的 Profile(如果存在)
    /usr/lib/cgi-bin/**     Px,

    # 系统 shell:受限制的子 Profile
    /bin/dash               Cx -> apache2-dash,

    # 辅助工具:继承 Apache 的限制
    /usr/bin/rotatelogs     ix,
}

# 子 Profile(Hat)
profile apache2-dash {
    #include <abstractions/base>
    /bin/dash               mr,
    /usr/bin/id             ix,
    /bin/ls                 ix,
}

4.4 能力(Capability)规则

AppArmor 可以精确控制进程能使用哪些 Linux Capabilities:

# 允许绑定低端口(<1024)
capability net_bind_service,

# 允许修改系统时间
capability sys_time,

# 允许发送信号给其他进程
capability kill,

# 允许使用 chroot
capability sys_chroot,

# 允许修改文件所有者
capability chown,

# 允许绕过文件权限检查
capability dac_override,

# 允许设置 UID/GID
capability setuid,
capability setgid,

# 拒绝特定能力
deny capability sys_admin,
deny capability sys_module,

常用 Capabilities 速查:

Capability 用途
net_bind_service 绑定 1024 以下的端口
net_raw 使用 RAW 和 PACKET 套接字
sys_admin 系统管理操作(mount 等)
sys_ptrace 跟踪其他进程
sys_module 加载/卸载内核模块
sys_time 修改系统时钟

4.5 网络规则

# 网络域类型
network inet,       # IPv4
network inet6,      # IPv6
network netlink,    # Netlink 套接字

# 协议类型
network tcp,        # TCP
network udp,        # UDP
network icmp,       # ICMP
network raw,        # RAW 套接字

# 组合使用
network inet tcp,           # IPv4 TCP
network inet6 udp,          # IPv6 UDP
network inet stream,        # IPv4 TCP 流套接字
network inet dgram,         # IPv4 UDP 数据报套接字

# 创建套接字
network create inet,

# 拒绝
deny network raw,
deny network packet,

4.6 其他资源控制

# 挂载控制
mount,                                    # 允许所有挂载
mount /dev/sda1 -> /mnt/data/,           # 允许特定挂载
deny mount /dev/sda1 -> /mnt/secret/,    # 拒绝特定挂载
umount,                                   # 允许卸载

# 信号控制
signal (send) peer=nginx,                 # 允许向 nginx 发送信号
signal (receive) peer=unconfined,         # 允许接收非受限进程的信号

# Ptrace 控制
ptrace peer=@{profile_name},             # 允许跟踪同 Profile 的进程
deny ptrace,                              # 拒绝跟踪

# D-Bus 控制
dbus bind bus=session,                   # 绑定 Session Bus
dbus (send) bus=system path=/org/freedesktop/*,

# Unix 域套接字
unix (create),
unix (send receive) type=stream,

4.7 变量、别名与抽象层

变量定义

# 在 Profile 文件开头定义
@{APP_HOME}=/opt/myapp
@{LOG_DIR}=/var/log/myapp

profile myapp /opt/myapp/bin/myapp {
    @{APP_HOME}/bin/**      mr,
    @{APP_HOME}/etc/**      r,
    @{LOG_DIR}/**           rw,
}

# 预定义变量(在 tunables/global 中)
@{HOME}         # 用户主目录
@{HOSTNAME}     # 主机名
@{pid}          # 进程 PID
@{PROC}         # /proc

别名

# 为路径定义别名
alias /usr/sbin/nginx -> /usr/bin/nginx,

抽象层(Abstractions)

抽象层是可复用的规则片段,减少重复代码:

#include <abstractions/base>           # 基础系统访问(推荐始终包含)
#include <abstractions/nameservice>    # DNS 解析
#include <abstractions/python>         # Python 运行时
#include <abstractions/perl>           # Perl 运行时
#include <abstractions/ssl_certs>      # SSL 证书访问
#include <abstractions/private-files>  # 排除用户私有文件

常用的 abstractions/base 包含内容:

# 基础文件系统访问
/proc/*/mounts r,
/sys/kernel/security/apparmor/** r,

# 动态链接器
/lib/ld-*.so* mr,
/lib{,32,64}/ld-*.so mr,

# 基本库
/lib/**.so* mr,
/usr/lib/**.so* mr,

4.8 子配置文件与 Hat

Hat(子配置文件)允许为同一程序的不同执行上下文定义不同的安全域:

/usr/sbin/httpd {
    # Apache 主进程规则
    /usr/sbin/httpd mr,

    # 定义 Hat
    ^handlers {
        # CGI 处理器的安全上下文
        /usr/lib/cgi-bin/** Px,
    }

    ^default {
        # 默认上下文
        /var/www/** r,
    }

    # 切换到 Hat
    change_profile -> **,
}

5. 两种运行模式:Enforce vs Complain

Enforce 模式(强制模式)

  • 行为:违规操作被阻止并记录日志
  • 用途:生产环境的安全执行
  • 特点:这是默认模式
# 设置为 enforce 模式
sudo aa-enforce /etc/apparmor.d/usr.bin.nginx

# 在 Profile 中声明
profile myapp /usr/bin/myapp flags=(enforce) { ... }

Complain 模式(投诉/学习模式)

  • 行为:违规操作被允许,但记录到日志
  • 用途:开发新 Profile、调试现有策略
  • 特点:不影响应用正常运行
# 设置为 complain 模式
sudo aa-complain /etc/apparmor.d/usr.bin.nginx

# 在 Profile 中声明
profile myapp /usr/bin/myapp flags=(complain) { ... }

模式切换流程图

        新应用需要 AppArmor 保护
                 │
                 ▼
    ┌──────────────────────────┐
    │  1. 设为 complain 模式   │
    │     运行应用,收集日志    │
    └──────────┬───────────────┘
               │
               ▼
    ┌──────────────────────────┐
    │  2. aa-logprof 分析日志  │
    │     生成/更新规则         │
    └──────────┬───────────────┘
               │
               ▼
    ┌──────────────────────────┐
    │  3. 测试规则是否完整     │
    │     (保持 complain)     │
    └──────────┬───────────────┘
               │ 无异常
               ▼
    ┌──────────────────────────┐
    │  4. 切换到 enforce 模式  │
    │     (生产就绪)          │
    └──────────────────────────┘

6. 工具链与实战

6.1 命令行工具速查

命令 功能
aa-status 查看 AppArmor 状态和已加载的 Profile
aa-enforce <profile> 将 Profile 设为强制模式
aa-complain <profile> 将 Profile 设为投诉模式
aa-genprof <program> 交互式生成新 Profile
aa-logprof 从日志中更新已有 Profile
aa-autodep <program> 创建最小骨架 Profile
aa-unconfined 列出不受 AppArmor 限制的进程
apparmor_parser -r <file> 加载/替换 Profile
apparmor_parser -R <file> 卸载 Profile
apparmor_parser -Q <file> 预编译 Profile(不加载)
apparmor_status 查看 AppArmor 状态(同 aa-status)

6.2 手动编写配置文件

为 Nginx 编写自定义 Profile

# 1. 创建 Profile 文件
sudo vim /etc/apparmor.d/usr.sbin.nginx
#include <tunables/global>

/usr/sbin/nginx {
    #include <abstractions/base>
    #include <abstractions/nameservice>
    #include <abstractions/ssl_certs>

    # 能力控制
    capability net_bind_service,
    capability setuid,
    capability setgid,
    capability dac_override,
    deny capability sys_admin,
    deny capability sys_module,

    # 网络控制
    network inet tcp,
    network inet6 tcp,
    deny network raw,

    # 二进制文件
    /usr/sbin/nginx          mr,

    # 配置文件(只读)
    /etc/nginx/**            r,
    /etc/ssl/**              r,

    # 日志文件(读写)
    /var/log/nginx/*.log     rw,

    # 网站内容(只读)
    /var/www/**              r,

    # PID 文件
    /var/run/nginx.pid       rw,

    # 临时文件
    /tmp/nginx-*             rw,

    # 明确拒绝敏感路径
    deny /etc/shadow         r,
    deny /root/**            rwx,
    deny /etc/ssh/**         r,
}
# 2. 加载 Profile
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx

# 3. 设为 enforce 模式
sudo aa-enforce /usr/sbin/nginx

# 4. 重启 Nginx 验证
sudo systemctl restart nginx

6.3 使用 aa-genprof 交互式生成配置

aa-genprof 是最常用的 Profile 生成工具,通过分析应用行为日志自动生成规则:

# 1. 启动交互式生成
sudo aa-genprof /usr/bin/myapp
# 输出示例:
# Updating AppArmor profiles in /etc/apparmor.d.
# Writing updated profile for /usr/bin/myapp.
# Setting /usr/bin/myapp to complain mode.
#
# Before you begin, you may wish to check if a
# default profile exists for the application.
#
# Please start the application to be profiled in
# another window and exercise its functionality now.
#
# Once completed, select the "Scan" option below.

# 2. 在另一个终端运行应用
sudo /usr/bin/myapp --do-stuff

# 3. 回到 aa-genprof 终端,按 S 扫描日志
# Profile:  /usr/bin/myapp
# Path:     /etc/myapp/config.yml
# New Mode: owner r
# Severity: 4
#
#  [1 - /etc/myapp/config.yml]
# (A)llow / [(D)eny] / (I)gnore / Audi(t) / Abo(r)t / (F)inish

# 4. 为每个事件选择操作
# A - 允许
# D - 拒绝
# I - 忽略(跳过此规则)
# F - 完成

# 5. 保存:按 S 保存 Profile

6.4 使用 aa-logprof 更新已有配置

当应用行为变化时,使用 aa-logprof 更新已有 Profile:

# 分析审计日志,更新 Profile
sudo aa-logprof

# 交互式选择:
# Profile:  /usr/bin/myapp
# Path:     /var/log/myapp/new-feature.log
# New Mode: owner rw
# Severity: 4
#
# (A)llow / (D)eny / (I)gnore / (G)lob / Glob w/Ext / Abo(r)t / (F)inish
#
# G - 使用通配符(如 /var/log/myapp/*.log)
# Glob w/Ext - 保留扩展名的通配符

6.5 调试与排错

查看拒绝日志

# 实时查看 AppArmor 审计日志
sudo dmesg -w | grep -i apparmor

# 输出示例:
# audit: type=1400 audit(1453830992.845:37): apparmor="DENIED"
#   operation="open" profile="/usr/bin/myapp" name="/etc/shadow"
#   pid=1234 comm="myapp" requested_mask="r" denied_mask="r"

# 使用 journalctl(systemd 系统)
sudo journalctl -k | grep -i apparmor
sudo journalctl -f -k | grep -i apparmor

分析拒绝日志

# 日志关键字段解读
# operation="open"      ← 操作类型
# profile="/usr/bin/myapp" ← 受限的 Profile
# name="/etc/shadow"    ← 被拒绝访问的资源
# requested_mask="r"    ← 请求的权限
# denied_mask="r"       ← 被拒绝的权限
# comm="myapp"          ← 进程命令名
# pid=1234              ← 进程 PID

常见调试流程

# 1. 将 Profile 设为 complain 模式
sudo aa-complain /usr/bin/myapp

# 2. 重新运行应用(执行所有功能)
sudo /usr/bin/myapp

# 3. 用 aa-logprof 从日志生成规则
sudo aa-logprof

# 4. 检查生成的规则是否合理
cat /etc/apparmor.d/usr.bin.myapp

# 5. 切换回 enforce 模式
sudo aa-enforce /usr/bin/myapp

# 6. 验证无异常
sudo dmesg -c > /dev/null  # 清空日志
sudo /usr/bin/myapp
sudo dmesg | grep -i apparmor

7. AppArmor 与 Docker 容器安全

7.1 Docker 默认 AppArmor 配置

Docker 自动为每个容器生成并加载名为 docker-default 的 Profile:

# 查看 Docker 是否使用了 AppArmor
docker info | grep -i apparmor

# 查看容器的安全选项
docker inspect <container> | jq '.[0].HostConfig.SecurityOpt'

# 查看容器进程的 AppArmor 状态
cat /proc/$(docker inspect -f '{{.State.Pid}}' <container>)/attr/current
# 输出:docker-default (enforce)

docker-default 模板源码位置:

https://github.com/moby/moby/blob/master/profiles/apparmor/template.go

7.2 为容器编写自定义配置

# 1. 创建自定义 Profile
sudo vim /etc/apparmor.d/containers.d/docker-nginx
#include <tunables/global>

profile docker-nginx flags=(attach_disconnected,mediate_deleted) {
    #include <abstractions/base>

    # 网络
    network inet tcp,
    network inet udp,
    network inet icmp,
    deny network raw,

    file,
    umount,

    # 拒绝写入系统关键目录
    deny /bin/** wl,
    deny /boot/** wl,
    deny /dev/** wl,
    deny /etc/** wl,
    deny /lib/** wl,
    deny /lib64/** wl,
    deny /proc/** wl,
    deny /root/** wl,
    deny /sbin/** wl,
    deny /sys/** wl,
    deny /usr/** wl,

    # 审计写操作
    audit /** w,

    # Nginx 特定
    /var/run/nginx.pid      w,
    /usr/sbin/nginx         ix,
    /var/www/**             r,

    # 禁止执行 shell
    deny /bin/dash          mrwklx,
    deny /bin/sh            mrwklx,

    # 必要能力
    capability chown,
    capability dac_override,
    capability setuid,
    capability setgid,
    capability net_bind_service,

    deny mount,
}
# 2. 加载 Profile
sudo apparmor_parser -r -W /etc/apparmor.d/containers.d/docker-nginx

# 3. 使用自定义 Profile 运行容器
docker run --security-opt "apparmor=docker-nginx" \
    -p 80:80 -d --name secure-nginx nginx

# 4. 验证
docker exec secure-nginx cat /proc/1/attr/current
# 输出:docker-nginx (enforce)

7.3 使用 bane 简化容器配置生成

bane 是一个用 TOML 语法生成 AppArmor Profile 的工具,专为 Docker 容器设计:

# 安装
sudo apt install bane

# 编写简化的 TOML 配置
cat > nginx.toml << 'EOF'
Name = "docker-nginx"

[Filesystem]
  # 只读路径
  ReadOnlyPaths = [
    "/bin/**", "/boot/**", "/dev/**", "/etc/**",
    "/lib/**", "/lib64/**", "/proc/**",
    "/sbin/**", "/sys/**", "/usr/**"
  ]
  # 允许执行
  AllowExec = ["/usr/sbin/nginx"]
  # 允许写入
  AllowWrite = ["/var/run/nginx.pid", "/var/log/nginx/**"]

[Network]
  # 允许的 TCP 端口
  TCP = ["80", "443"]

[Capability]
  # 允许的能力
  Allow = ["chown", "dac_override", "setuid", "setgid", "net_bind_service"]
EOF

# 生成 AppArmor Profile
bane nginx.toml > /etc/apparmor.d/containers.d/docker-nginx

8. AppArmor 与 Kubernetes

Kubernetes 从 v1.4 开始支持 AppArmor(Beta),v1.30 起达到 GA:

apiVersion: v1
kind: Pod
metadata:
  name: apparmor-pod
  annotations:
    # 为容器指定 AppArmor Profile
    container.apparmor.security.beta.kubernetes.io/nginx: localhost/docker-nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
  nodeSelector:
    # AppArmor 仅在特定节点上可用
    kubernetes.io/os: linux

Kubernetes AppArmor 注解格式:

container.apparmor.security.beta.kubernetes.io/<container_name>:
    <profile_ref>
Profile 引用 含义
runtime/default 使用容器运行时的默认 Profile
localhost/<name> 使用节点上预加载的 Profile
unconfined 不使用 AppArmor

9. AppArmor vs SELinux:选型指南

对比维度 AppArmor SELinux
设计理念 基于路径,程序为中心 基于标签,全局策略
默认发行版 Ubuntu, SUSE, Debian RHEL, CentOS, Fedora
策略语法 简洁(类似配置文件) 复杂(需要理解 TE/RBAC/MLS)
学习曲线 1-3 天可上手 1-3 周基础掌握
默认行为 未配置 = 不受限 未配置 = 全部拒绝
文件系统 路径匹配(可能被硬链接绕过) inode 标签(不受路径变化影响)
多级安全(MLS) 不支持 完整支持
容器生态 Docker/Podman 原生支持 需要配置和标签管理
策略调试 complain 模式 + aa-logprof permissive 域 + audit2allow
适用场景 中小型部署、单应用隔离、容器 大型企业、政府/军事、多级安全

选型建议

需要多级安全(MLS)?
  ├─ 是 → SELinux
  └─ 否 → 继续

使用 RHEL/CentOS 生态?
  ├─ 是 → SELinux(系统默认)
  └─ 否 → 继续

使用 Ubuntu/SUSE/Debian 生态?
  ├─ 是 → AppArmor(系统默认)
  └─ 否 → 继续

团队安全经验有限,需要快速部署?
  ├─ 是 → AppArmor(简单易用)
  └─ 否 → 继续

需要容器级别的安全隔离?
  ├─ 是 → AppArmor(Docker/K8s 原生集成更好)
  └─ 否 → 根据发行版选择

需要最高安全级别和精细控制?
  ├─ 是 → SELinux
  └─ 否 → AppArmor

10. 安全加固最佳实践

10.1 Profile 编写原则

# ✅ 好:最小权限原则
profile secure-app /opt/app/bin/secure-app {
    #include <abstractions/base>

    # 只允许必需的路径
    /opt/app/bin/secure-app   mr,
    /opt/app/etc/config.yml   r,
    /opt/app/logs/*.log       rw,

    # 只允许必需的 capability
    capability net_bind_service,

    # 明确拒绝敏感操作
    deny capability sys_admin,
    deny capability sys_module,
    deny /etc/shadow r,
    deny /root/** rwx,
}

# ❌ 坏:过度宽松
profile loose-app /opt/app/bin/loose-app {
    #include <abstractions/base>
    capability,              # 允许所有 capability!
    /** rw,                  # 允许读写整个文件系统!
    network,                 # 允许所有网络!
}

10.2 生产环境 Checklist

项目 状态 说明
所有关键服务有 Profile Nginx/Apache/MySQL/Redis 等
Profile 处于 enforce 模式 aa-status 确认
使用最小权限原则 仅允许必需的路径和能力
明确 deny 敏感路径 /etc/shadow, /root/**
定期审计日志 dmesg 检查 DENIED 记录
容器使用自定义 Profile 而非 docker-default
CI/CD 集成 Profile 验证 部署前测试 Profile
备份 Profile 文件 /etc/apparmor.d/ 纳入版本控制

10.3 多层防护组合

# 完整的容器安全配置
docker run -d \
  --name ultra-secure-app \
  --security-opt apparmor=custom-profile \     # AppArmor 文件访问控制
  --security-opt seccomp=strict.json \         # Seccomp 系统调用过滤
  --security-opt no-new-privileges:true \      # 禁止提权
  --cap-drop=ALL \                             # 移除所有 Capabilities
  --cap-add=NET_BIND_SERVICE \                 # 只加回必需的
  --read-only \                                # 根文件系统只读
  --tmpfs /tmp:noexec,nosuid \                 # tmpfs 限制
  myapp:latest

11. 常见问题排查

问题 1:应用无法启动,日志显示 Permission Denied

# 诊断步骤
# 1. 检查是否是 AppArmor 导致
sudo dmesg | grep -i "apparmor.*DENIED"

# 2. 临时切换到 complain 模式确认
sudo aa-complain /usr/bin/myapp
sudo /usr/bin/myapp  # 如果能启动,说明是 AppArmor 拦截

# 3. 用 aa-logprof 更新 Profile
sudo aa-logprof

# 4. 切换回 enforce
sudo aa-enforce /usr/bin/myapp

问题 2:容器退出,无任何日志

# 可能是 AppArmor 阻止了关键操作
docker run --security-opt apparmor=unconfined <image>  # 临时绕过
# 如果容器能启动,说明需要调整 Profile

问题 3:aa-genprof 生成规则不全

# 确保覆盖所有功能路径
# 在 complain 模式下完整运行应用的所有功能
# 包括:启动、正常操作、异常处理、停止

# 重新扫描日志
sudo aa-logprof

问题 4:AppArmor 未启用

# 检查内核支持
grep -i apparmor /boot/config-$(uname -r)
# 应有:CONFIG_SECURITY_APPARMOR=y

# 检查是否加载
sudo aa-status
# 或
cat /sys/module/apparmor/parameters/enabled
# 输出 Y 表示已启用

# 如果未加载
sudo systemctl enable apparmor
sudo systemctl start apparmor

问题 5:Profile 更新后未生效

# 重新加载 Profile
sudo apparmor_parser -r /etc/apparmor.d/usr.bin.myapp

# 或重新启动 apparmor 服务
sudo systemctl reload apparmor

# 验证
sudo aa-status | grep myapp

12. 总结

核心要点

要点 说明
MAC 安全模块 AppArmor 是 LSM 框架下的强制访问控制系统
基于路径 策略使用文件路径而非标签,直观易用
以程序为中心 每个可执行文件一个 Profile,未配置的程序不受影响
两种模式 Complain(学习/调试)和 Enforce(强制执行)
渐进式部署 从 complain 开始 → aa-logprof 完善 → enforce 上线
容器集成 Docker/K8s 原生支持,docker-default 自动保护
内核执行 策略在内核中强制,应用无法绕过

推荐资源


免责声明:本文内容基于 Linux 内核文档和 AppArmor 官方资料编写,适用于 Linux 2.6.36+ 内核系列。具体 API 行为和发行版配置可能有所差异,请以实际运行环境为准。