apparmor的profile分为全局和局部两类:全局profile作用于系统级服务,存放于/etc/apparmor.d/,需systemctl enable apparmor并确认内核启用;局部profile针对单个应用,须用apparmor_parser加载且重启进程才生效,两者不可叠加,匹配以execve绝对路径为准。

AppArmor 的 profile 管理分全局和局部两类,本质区别在于作用范围和加载方式——全局 profile 影响系统级服务或默认策略,局部 profile 针对单个应用或容器定制。实际使用中,90% 的权限问题出在混淆两者边界,或忽略加载生效条件。
全局 Profile:系统级策略基线
全局 profile 通常指预装的、覆盖基础服务的策略文件,如 /etc/apparmor.d/usr.sbin.tcpdump 或 /etc/apparmor.d/usr.bin.python3。它们由发行版提供(Ubuntu/SUSE 自带),存放于 /etc/apparmor.d/ 下,命名严格对应可执行路径(斜杠转点号)。
- 不建议直接修改预置 profile,应通过 include 机制复用:比如在自定义 profile 中写 #include
调用全局变量(如 @{HOME}、@{PROC}) - 启用全局策略需确保 apparmor-utils 已安装,且 systemctl enable apparmor 开机自启
- 全局策略是否生效,取决于内核模块是否启用:cat /sys/module/apparmor/parameters/enabled 输出 Y 才算真正激活
局部 Profile:按需约束单个进程
局部 profile 是为特定二进制文件(如 /usr/local/bin/myapp)单独编写的策略,文件名必须是 /etc/apparmor.d/usr.local.bin.myapp。它不依赖系统默认策略,完全独立控制该程序行为。
- 编写后必须用 sudo apparmor_parser -r /etc/apparmor.d/usr.local.bin.myapp 加载,否则 aa-status 不会显示
- 加载成功 ≠ 进程受控:只有重启服务(systemctl restart myapp)或新启动进程才会匹配该 profile;已运行的进程不受影响
- 推荐先设为 complain 模式:sudo aa-complain /etc/apparmor.d/usr.local.bin.myapp,运行一段时间后查 dmesg | grep DENIED 补全规则,再切 enforce
Profile 冲突与优先级
AppArmor 不支持 profile 叠加,只认第一个匹配的 profile。若一个程序有多个潜在匹配路径(如符号链接、硬链接、不同路径启动),以实际 execve 调用的绝对路径为准。
- 例如 /usr/bin/zapret 和 /opt/bin/zapret 是两个独立路径,需分别写 profile
- 通配符(如 /usr/local/bin/*)能匹配多个程序,但属于“宽泛授权”,不推荐用于生产环境
- 若发现策略未生效,先运行 aa-status --verbose 查看哪个 profile 实际绑定到了进程 PID
容器场景下的 Profile 管理
Docker 默认使用 docker-default 全局 profile,但你可为单个容器指定局部 profile——这需要两步:先用 apparmor_parser 加载自定义 profile(如 /etc/apparmor.d/docker-myapp),再在 docker run 或 Pod YAML 中显式声明 --security-opt apparmor=docker-myapp。
- 容器 runtime(Docker/containerd)必须支持 AppArmor,可通过 docker info | grep apparmor 确认
- Kubernetes 中需在 Pod SecurityContext 设置 apparmor.security.beta.kubernetes.io/pod: runtime/default 或指定 profile 名
- 注意:容器内进程路径(如 /bin/sh)仍需与 host 上 profile 路径一致,否则匹配失败











