容器安全基础
非 root、最小镜像、密钥不入镜像。
容器安全基础
这一课你将能做到
- 把 Spring Boot 镜像改成非 root 用户运行,并用
id命令验证容器内进程身份 - 复现「密码写进 Dockerfile 会从
docker history泄漏」的安全事故,掌握运行时注入密钥的正确做法 - 用 Trivy 扫描镜像漏洞、用资源限制防止容器拖垮宿主机,形成一份可落地的安全清单
为什么要学
前面课程的目标一直是「能跑起来」,本课的目标是「敢放进生产」。容器默认配置有三个隐患,恰好在 Java 后端项目里最常见:
- 容器内进程默认以 root 运行——一旦容器被攻破,攻击者在容器内的 root 结合内核漏洞可能影响宿主机。
- 开发者习惯把数据库密码写进 Dockerfile 的 ENV——
docker history对任何拿到镜像的人可见,等于密码随镜像公开。 - 镜像里的基础系统与依赖带着已知 CVE——不扫描就带病上线。
这三条不需要高深知识就能修,改造成本低、面试常问、生产收益高,是性价比最高的一课。
先建立图像
安全问题的成因链条:
镜像层(构建期定型) 运行期(每次 run 决定)
┌──────────────────────────┐ ┌──────────────────────────┐
│ Dockerfile ENV 写了密码 ✗ │ │ -p 0.0.0.0:3306 裸奔 ✗ │
│ 以 root 身份运行 ✗ │ │ 无内存/CPU 限制 ✗ │
│ 基础镜像带 CVE ✗ │ │ 密码明文注入环境变量 △ │
└──────────────────────────┘ └──────────────────────────┘
↓ 修复手段 ↓ 修复手段
多阶段+最小镜像、USER 非 root 端口收敛、资源限额、
密钥不进层(history 可见) .env / secrets 注入
优先级排序(本课顺序即优先级):密钥不入镜像 > 非 root > 端口收敛 > 漏洞扫描 > 资源限制。
跟着做
步骤 1:亲眼确认默认是 root
docker run --rm eclipse-temurin:21-jre id
# 输出:uid=0(root) gid=0(root) groups=0(root)
步骤 2:Dockerfile 改为非 root 运行
FROM eclipse-temurin:21-jre
ENV TZ=Asia/Shanghai
# 创建系统用户(-r 不建家目录,uid 10001 固定便于 volume 授权)
RUN useradd -r -u 10001 appuser
USER appuser
WORKDIR /app
COPY --chown=appuser:appuser target/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
要点:COPY --chown 让 jar 归属应用用户;Java 监听 8080(>1024 非特权端口)无需 root。重新构建并验证:
docker build -t demo-app:1.1-secure .
docker run --rm demo-app:1.1-secure id
# 输出:uid=10001(appuser) —— 非 root 生效
步骤 3:复现「docker history 泄漏密码」
# 反例(仅实验,不要提交)
FROM eclipse-temurin:21-jre
ENV DB_PASSWORD=SuperSecret123
docker build -t leak-demo .
docker history leak-demo
# 输出里能看到:ENV DB_PASSWORD=SuperSecret123 —— 密码随镜像公开
同时它还写进了镜像层元数据,即使后续 ENV 覆盖也删不干净。结论:。