Docker容器默认启用Seccomp,禁用约44个高风险系统调用;真正限制异常调用需提供严格校验的自定义JSON配置,字段名(如default_action、syscalls)、architectures字段、绝对路径缺一不可,否则容器无法启动。

直接结论:Docker容器默认已启用Seccomp,但仅禁用约44个高风险系统调用;若要真正限制“异常”调用(比如非业务必需、易被利用的syscall),必须提供自定义JSON配置文件,并确保字段名、架构、路径三者全部正确,否则容器根本启动不了。
seccomp profile JSON格式必须严格校验
Linux内核的seccomp-bpf机制只认标准JSON,不接受YAML、TOML或带注释的JSON。Docker daemon加载时会逐字段校验,常见错误包括:
-
defaultAction(错)→ 正确是default_action(下划线,全小写) -
syscall(错)→ 正确是syscalls(复数,s不能少) - 漏掉
architectures字段 → 容器报错:error: invalid seccomp profile: missing required field "architectures"
实操建议:用 jq 预检语法和字段:
jq -e '.default_action, .architectures, .syscalls' /etc/docker/seccomp.json >/dev/null
返回非零即失败,CI/CD中可直接加入流水线校验步骤。
default_action 设为 SCMP_ACT_ERRNO 还是 SCMP_ACT_KILL?
选哪个取决于你是否想让容器“静默失败”还是“立刻崩溃”:
-
SCMP_ACT_ERRNO:调用被拒时返回EPERM错误,应用可能继续运行(比如日志里报错但没panic)——适合调试阶段或对稳定性要求高的服务 -
SCMP_ACT_KILL:直接向进程发SIGSYS终止,不留余地——适合生产环境,防止错误被忽略或绕过
注意:SCMP_ACT_ALLOW 不能作为 default_action 值(Docker会拒绝加载),它只能用于 syscalls 列表里的显式放行项。
为什么容器一跑就报 openat: Operation not permitted?
因为 openat 是绝大多数运行时(Go、Node.js、Python、JVM)打开文件、加载so库、读取/proc信息的基础调用,禁掉它等于禁掉整个运行时初始化流程。
真实最小可用集合通常包含:
-
openat(必留,否则连ls都失败) -
read、write、close(I/O基础) -
statx或stat、fstat(路径检查与元数据读取) - Go容器额外需要
clone、epoll_wait、getrandom - Node.js容器额外需要
epoll_pwait、rt_sigprocmask
别靠猜——先用 strace -f -e trace=raw_syscall -p $(pidof your-app) 抓真实调用,再筛出高频且非特权的项。盲目禁用 openat 或 statx 是最常踩的坑。
--security-opt seccomp= 后面的路径必须是 daemon 可读的绝对路径
Docker daemon 运行在宿主机 root 上下文,它看不到你 shell 当前目录,也解析不了 ~ 或 ./。常见错误命令:
docker run --security-opt seccomp=profile.json ... # ❌ daemon 在 / 找 profile.json
正确做法:
- 把配置文件放到 daemon 可读位置,例如
/etc/docker/seccomp-restrict.json - 确认权限:
sudo chmod 644 /etc/docker/seccomp-restrict.json - 启动时用绝对路径:
docker run --security-opt seccomp=/etc/docker/seccomp-restrict.json ...
如果用 Docker Compose,security_opt 字段同样只接受绝对路径,相对路径不会自动补全到宿主机上下文。
最易被忽略的一点:seccomp本身不区分路径、参数或调用来源,它只看系统调用号。想限制“只允许读/tmp下的文件”,光靠seccomp做不到——得配合只读挂载(--read-only --tmpfs /tmp)或AppArmor。seccomp是第一道 syscall 级闸门,但不是万能锁。


















