15.10.5 镜像与运行时安全加固

本节聚焦镜像供应链与容器运行时的安全加固,目标是在构建、分发与运行三阶段降低攻击面与供应链风险,确保镜像可追溯、运行可控、变更可审计。

原理草图:镜像供应链与运行时加固闭环#

文章图片

镜像安全加固要点#

  • 最小化镜像:选择精简基础镜像(如 Alpine、Distroless),仅保留运行所需依赖,减少漏洞数量与扫描噪音。
  • 固定版本与不可变构建:在 Dockerfile 中固定基础镜像与依赖版本,避免使用 latest;结合构建时锁定包版本,提升可复现性。
  • 多阶段构建:编译与运行分离,最终镜像只包含产物与运行依赖,避免编译工具进入生产环境。
  • 删除敏感文件:构建过程中清理密钥、配置模板、缓存与历史文件,避免泄露。
  • 签名与校验:为镜像进行签名(如 Notary/Content Trust),在拉取与部署时校验来源与完整性。
  • 漏洞扫描与准入:在 CI/CD 中执行镜像漏洞扫描(如 Trivy/Clair),设置严重级别门禁;部署前再次扫描。

示例:多阶段构建与最小镜像#

# 文件:/opt/app/Dockerfile
# 构建阶段
FROM golang:1.21-alpine AS build
WORKDIR /src
COPY . .
RUN apk add --no-cache git ca-certificates \
 && go build -o /bin/app ./cmd/app

# 运行阶段(distroless)
FROM gcr.io/distroless/base-debian12
COPY --from=build /bin/app /bin/app
USER 65532:65532
ENTRYPOINT ["/bin/app"]
# 构建镜像并查看体积
cd /opt/app
docker build -t app:1.0.0 .
docker images app:1.0.0

预期效果:运行镜像只包含二进制和运行时依赖,体积显著缩小,漏洞面减少。

示例:Trivy 漏洞扫描#

# 安装 Trivy(示例:RHEL/CentOS)
sudo rpm -ivh https://github.com/aquasecurity/trivy/releases/latest/download/trivy_0.49.1_Linux-64bit.rpm

# 扫描镜像并设置门禁
trivy image --severity HIGH,CRITICAL --exit-code 1 app:1.0.0

命令解释
- --severity HIGH,CRITICAL:仅关注高危与严重漏洞
- --exit-code 1:发现漏洞则退出码为 1,用于 CI 门禁

示例:镜像签名与验证(Docker Content Trust)#

# 启用 Content Trust(Notary)
export DOCKER_CONTENT_TRUST=1

# 推送镜像时会生成签名
docker tag app:1.0.0 registry.local/app:1.0.0
docker push registry.local/app:1.0.0

# 拉取时验证签名
docker pull registry.local/app:1.0.0

排错提示
- 拉取失败提示 “no trust data”:
- 确认推送阶段开启了 DOCKER_CONTENT_TRUST=1
- 仓库是否支持 Notary

运行时安全加固要点#

  • 只读根文件系统:对容器启用只读根文件系统,仅对必要目录挂载可写卷,防止篡改。
  • 最小权限运行:禁止使用 root 用户,设置 USER;限制 capabilities,仅保留必要特权。
  • 安全配置隔离:启用 seccompAppArmor/SELinux 配置文件,限制系统调用与访问路径。
  • 网络最小暴露:仅开放必要端口,使用内部网络隔离,限制跨容器访问。
  • 资源约束配合安全:在资源限制基础上开启 OOM 防护、PID 限制,降低异常行为影响。
  • 日志与审计:配置容器运行时审计日志,记录镜像来源、启动参数、能力提升等关键事件。

示例:只读根文件系统 + 非 root + Cap 限制#

# 运行容器:只读根文件系统、非 root 用户、删除所有能力
docker run -d --name app-secure \
  --read-only \
  --user 10001:10001 \
  --cap-drop ALL \
  --tmpfs /tmp:rw,noexec,nosuid,size=64m \
  -p 8080:8080 \
  app:1.0.0

命令解释
- --read-only:根文件系统只读
- --cap-drop ALL:移除全部 Linux capabilities
- --tmpfs /tmp:仅允许临时目录可写,限制执行与提权

示例:启用 seccomp 与 AppArmor#

# 查看默认 seccomp profile 路径
cat /etc/docker/seccomp.json | head -n 5

# 使用自定义 seccomp
docker run -d --name app-seccomp \
  --security-opt seccomp=/etc/docker/seccomp.json \
  app:1.0.0

# AppArmor(Ubuntu 示例)
sudo aa-status | head
docker run -d --name app-apparmor \
  --security-opt apparmor=docker-default \
  app:1.0.0

排错提示
- 容器启动失败提示 “operation not permitted”:
- 检查 seccomp/ AppArmor 是否过严
- 逐步放开所需系统调用或改为默认策略

示例:运行时审计与日志#

# 查看容器启动参数与镜像来源
docker inspect app-secure --format '{{.Config.Image}} {{.HostConfig.SecurityOpt}}'

# Docker 守护进程日志(systemd)
sudo journalctl -u docker --since "1 hour ago"

推荐实践流程#

  1. 在构建阶段:锁定依赖版本 → 多阶段构建 → 扫描与签名。
  2. 在分发阶段:启用私有仓库访问控制 → 强制拉取校验 → 版本不可变策略。
  3. 在运行阶段:最小权限用户 → 只读根文件系统 → 安全策略与准入控制。

常见问题与规避#

  • 镜像层堆积导致漏洞增多:通过多阶段构建和清理缓存控制层大小与风险。
  • 生产环境仍使用 root:调整应用权限,使用非特权端口或反向代理。
  • 绕过安全策略:在编排平台中启用强制准入策略,禁止手工运行非合规镜像。
  • 扫描误报过多:限制扫描到运行时依赖层,使用 --ignore-unfixed 或白名单管理。

安装与环境准备#

# 安装 Docker(示例:Ubuntu)
sudo apt-get update
sudo apt-get install -y docker.io
sudo systemctl enable --now docker

# 安装 Trivy
sudo apt-get install -y wget
wget -qO - https://github.com/aquasecurity/trivy/releases/latest/download/trivy_0.49.1_Linux-64bit.deb -O /tmp/trivy.deb
sudo dpkg -i /tmp/trivy.deb

练习#

  1. 使用多阶段构建将一个编译型应用从 400MB 降至 50MB 以下,并记录镜像层差异。
  2. 启用 --read-only 后运行容器,验证写入根目录时的报错信息并给出解决方案。
  3. 使用 Trivy 扫描一个已知存在漏洞的镜像,记录漏洞 ID 与修复建议。
  4. 配置 seccomp 限制 ptrace 调用,验证调试工具是否被禁止。

通过上述加固策略,镜像与运行时安全可形成闭环,降低供应链攻击与运行时逃逸风险,支撑生产环境的稳定与合规。