AppArmor profile 必须用容器内路径写规则,启动时需显式指定名称,且 network/capabilities 等权限须手动白名单声明,缺一不可;否则 profile 不生效。

能,但必须在宿主机提前加载 profile、启动容器时显式指定名称、规则路径要按容器内视角写,且 network/capabilities 等需手动声明——缺一不可,否则 profile 不生效。
AppArmor profile 必须用容器内路径写规则
AppArmor 规则基于文件路径匹配,而容器进程看到的路径是 rootfs 内的视图,不是宿主机路径。比如你挂载了 /host/config 到容器的 /app/config,profile 中必须写 /app/config/** r,,而不是 /host/config/** r,。
- 错误写法:
/host/config/** r,—— 容器内进程根本访问不到该路径,规则永不触发 - 正确写法:
/app/config/** r,—— 与容器内实际运行路径一致 - 二进制路径也同理:若容器内程序位于
/usr/local/bin/myapp,profile 头部必须是/usr/local/bin/myapp { ... }
docker run 必须用 --security-opt=apparmor:xxx 显式启用
Docker 不会自动加载或绑定 AppArmor profile,即使 profile 已通过 apparmor_parser -r /etc/apparmor.d/usr.local.bin.myapp 加载进内核,容器也不会默认使用它。
- 必须在启动时指定:
docker run --security-opt="apparmor:myapp-profile" ... - profile 名称(
myapp-profile)必须与aa-status中列出的名称完全一致,区分大小写 - 如果名称拼错或 profile 未加载,Docker 不报错,但实际运行在“无约束”模式下——
cat /proc/self/attr/current会显示unconfined
network 和 capabilities 不是默认继承,得在 profile 里白名单声明
AppArmor 默认禁止所有网络操作和 capability 使用,不像 seccomp 那样有默认允许集。如果你的应用要监听端口或读取 /proc,必须显式放行。
- 开 TCP 端口:
network inet tcp,或更细粒度如network inet stream, - 绑定 80 端口:
capability net_bind_service,(注意:这仅授权 capability,不等价于net_admin) - 读取 proc:
/proc/** r,,但建议限制到具体路径,如/proc/sys/net/core/somaxconn r, - 没声明
capability dac_override,却尝试读取其他用户文件?直接被 deny 并记入dmesg
验证是否真生效:别只看 docker logs
profile 是否 enforce 模式运行,不能靠容器是否启动成功判断。很多权限拒绝是静默失败,比如 open() 返回 EPERM 而非崩溃。
- 进容器执行:
cat /proc/self/attr/current—— 应输出类似myapp-profile (enforce),不是unconfined - 在宿主机查拒绝日志:
dmesg | grep apparmor | tail -10—— 有APPARMOR DENIED行说明拦截已工作 - 临时切 audit 模式调试:把 profile 第一行改成
#include前加audit,再重载,可捕获所有被拦操作
最容易被忽略的是 profile 名称与 --security-opt 参数的严格一致性,以及规则路径必须按容器内视角书写——这两点错一个,整个 profile 就形同虚设。











