Docker 安全加固
容器与宿主机共享内核,配置不当等于把大门敞开。本章从镜像、进程、密钥、能力与供应链几个方面给出可落地的加固清单。
最小基础镜像与非 root 运行
基础镜像越小攻击面越小,alpine、distroless 比完整发行版精简得多;更关键的是别用 root 跑应用。在 Dockerfile 里创建专用用户并切换:
FROM node:20-alpine
RUN addgroup -S app && adduser -S -G app app # 建非特权用户(alpine 语法)
USER app
CMD ["node", "server.js"]
docker run -d --user 10001:10001 myapp # 或运行时按 uid:gid 指定
docker exec -it $(docker ps -ql) id # 确认输出含 uid=10001(app)
镜像漏洞扫描
镜像可能自带已知漏洞,发布前扫一遍:Docker Desktop 内置 docker scout;开源工具 Trivy 命令更通用、离线可用:
docker scout quickview myapp:1.0 # Docker 官方扫描(需 scout 插件)
trivy image myapp:1.0 # Trivy:一条命令扫本地镜像漏洞
扫描结果按严重级别列出 CVE,高危项对应升级基础镜像或依赖版本。
密钥不进镜像
把密码写进 Dockerfile 或 ENV 会永久留在镜像历史里,任何人拿到镜像都能翻出来。运行期密钥用 --env-file 或 -e 注入;构建期敏感值用 BuildKit secret,不进任何层:
docker run -d --env-file ./prod.env myapp # 密钥放宿主机 .env(注意权限 600)
docker build --secret id=sshkey,src=/root/.ssh/id_rsa -t app .
# 构建时:RUN --mount=type=secret,id=sshkey 才能读到,层里查不到内容
RUN --mount=type=secret,id=sshkey npm ci
收窄 Capabilities 与只读文件系统
容器默认继承一长串 Linux capabilities,按最小权限收窄:先 --cap-drop=ALL 全部丢弃,再按需 --cap-add 加回个别能力;根文件系统以只读挂载,可写目录单独 tmpfs:
docker run -d --cap-drop=ALL --cap-add=NET_BIND_SERVICE \
--read-only --tmpfs /tmp -p 80:8080 myapp
只读根文件系统能挡住「写文件落地」类攻击,应用需要写日志/临时文件时把目录挂 tmpfs 或具名卷。
供应链与 docker 组风险
- 只用官方或可信来源镜像,并锁定具体版本标签(如 nginx:1.27.4-alpine),不要裸用 latest;
- 定期 docker pull 更新基础镜像并用上文扫描复查,及时升级有漏洞的镜像;
- docker 组权限等同于 root:能执行 docker 命令基本就能控制宿主机,别轻易把用户加进 docker 组,生产环境更要把好这道口子。
小结
安全没有一招制胜:最小镜像 + 非 root 运行降低提权面,secret/env 注入替代硬编码密钥,cap-drop 与 --read-only 收窄内核接口,官方源 + 锁版本 + 定期扫描守住供应链。四项都做齐,容器才算基本合格。