最直接有效的方式是在 Docker 守护进程级统一启用 no-new-privileges,即通过修改 /etc/docker/daemon.json 添加 "no-new-privileges": true 并重启守护进程;该配置使所有容器默认注入 NO_NEW_PRIVS 内核标志,阻止 setuid/setgid 等提权行为,且可配合 --no-new-privs 和 --no-pivot 进一步加固 runtime 层。

最直接有效的方式是在 Docker 守护进程级统一启用 no-new-privileges,即通过修改 /etc/docker/daemon.json 配置文件,让所有容器默认继承该安全限制,无需每次启动都加参数。
在 daemon.json 中全局启用 no-new-privileges
编辑守护进程配置文件,添加或确认以下字段:
- 设置
"no-new-privileges": true—— 这是 Docker 原生支持的守护进程选项,会自动为每个容器注入NO_NEW_PRIVS内核标志 - 该配置生效后,容器内任何进程(包括
execve()调用)都无法通过 setuid/setgid 二进制、file capabilities 或其他方式获取新特权 - 重启 Docker 守护进程使配置生效:
sudo systemctl restart docker
配合 runtimeArgs 强化底层控制(推荐 Docker 27+)
仅靠 no-new-privileges: true 已能拦截绝大多数提权路径,但若需更彻底阻断 rootfs 修改能力,可进一步在 runtime 层加固:
- 在
daemon.json的runtimes.runc.runtimeArgs中追加"--no-new-privs"(注意:这是 runc 层参数,与上层no-new-privileges语义一致但作用点更低) - 强烈建议同时加入
"--no-pivot",防止容器内调用pivot_root或chroot绕过只读挂载限制 - 组合效果:既封死提权入口,又切断文件系统重挂载路径,形成双重防御
验证是否生效
启动一个测试容器并检查内核标志:
- 运行:
docker run --rm -it alpine cat /proc/1/status | grep NoNewPrivs - 若输出
NoNewPrivs: 1,说明已成功启用 - 再尝试执行 setuid 程序(如
/usr/bin/passwd),应提示Operation not permitted
注意事项与常见误区
这个设置是守护进程级默认行为,不依赖镜像或用户声明。但需注意:
- 它无法覆盖
--privileged模式——一旦使用该参数,所有安全限制(包括 no-new-privs)都会被绕过,必须禁用 - 若容器内应用依赖 setuid(极少见),需重构逻辑,改用
setcap或非特权替代方案 - 与
--user参数协同效果更佳:例如docker run --user 1001:1001+ 守护进程级 no-new-privileges,可确保进程从启动起就无特权上下文


















