必须用非root用户运行docker镜像,因其能有效限制容器内进程权限,遵循最小权限原则,防止提权攻击和容器逃逸,显著降低安全风险。

直接从 Dockerfile 入手,是控制容器安全最前置、最有效的方式。很多运行时风险——比如提权、漏洞暴露、敏感信息泄露——其根源都在构建阶段就被写进了镜像。只要在 Dockerfile 里做对几件事,就能堵住绝大多数常见隐患。
用非 root 用户启动应用
默认以 root 运行容器,等于把一把万能钥匙交给应用代码。一旦被攻破,攻击者可在容器内任意操作,甚至尝试逃逸到宿主机。
- 在 Dockerfile 中显式创建普通用户,并设置 UID/GID(避免使用 0)
- 用 COPY --chown=user:group 确保文件归属正确
- 在安装依赖后、复制代码前就切换用户,确保后续所有操作都不依赖 root 权限
- 注意:某些语言运行时(如 Node.js、Python)无需 root 即可监听非特权端口(如 8080),不必为端口绑定妥协
选最小、可信的基础镜像
镜像越小,攻击面越窄;来源越可信,后门风险越低。别贪图方便用 latest 或未经验证的第三方镜像。
- 优先选用官方维护的 slim 或 alpine 变体(如
python:3.11-slim-bookworm、node:20-alpine) - 避免使用
FROM ubuntu:latest这类宽泛标签,明确指定带补丁号的版本(如ubuntu:22.04.4) - 对高安全要求场景,考虑 distroless 镜像(如
gcr.io/distroless/python3),它不含 shell 和包管理器,无法交互式入侵
杜绝敏感信息硬编码
密码、密钥、API token 写进 Dockerfile 或 COPY 进镜像,等于把钥匙焊死在门上。
- Dockerfile 中禁止出现 ENV DB_PASSWORD=xxx 或 RUN echo "secret" > /app/.env 这类指令
- 配置文件若必须存在,应留占位符(如
DB_PASSWORD=__REPLACE_AT_RUNTIME__),由启动时注入 - 构建阶段所需密钥(如私钥拉取私有包)应通过 docker build --secret 传递,而非 COPY 进镜像
- 确需环境变量时,统一通过
docker run -e或.env文件注入,且不在镜像层中留存
精简暴露面与权限控制
少一步操作,就少一个被利用的机会。Dockerfile 不只是“让程序跑起来”,更是定义“它被允许做什么”的契约。
- 只 EXPOSE 实际需要的端口(如 8080),不暴露管理端口(如 2375)、调试端口(如 9229)
- 禁用
ADD指令(尤其远程 URL 场景),改用COPY+RUN curl | tar显式控制下载行为 - 多阶段构建中,构建阶段可用 root,但最终阶段只 COPY 二进制或必要文件,不带编译工具链
- 最后加上 USER 指令,且不再有 RUN 命令跟在其后——这是强制执行非 root 的最后一道防线











