4. 容器镜像安全基线:镜像漏洞扫描、最小化基础镜像、非root运行、镜像签名与验证
容器镜像是云原生应用交付的核心载体,其安全性直接决定了运行时的风险暴露面。本章围绕镜像安全基线的四个关键维度——漏洞扫描、最小化基础镜像、非root运行、签名与验证,建立可量化、可核验的交付前验收标准。
4.1 镜像漏洞扫描:从发现到阻断
镜像漏洞扫描是安全左移的第一道防线。验收标准要求:所有交付镜像必须通过CVE扫描,且不允许存在Critical(严重)级别漏洞。High级别漏洞需提供官方修复版本或明确的缓解措施说明。
| 漏洞等级 | 验收要求 | 处置方式 |
|---|---|---|
| Critical(严重) | 禁止交付 | 升级基础镜像或安装补丁包 |
| High(高危) | 需附缓解说明 | 提供CVE编号、影响范围、临时规避措施 |
| Medium(中危) | 记录在案 | 纳入后续版本修复计划 |
| Low(低危) | 可选修复 | 不影响交付验收 |
扫描工具选型建议:推荐使用Trivy、Grype或Anchore Engine。验收时需提供扫描报告原文(JSON/HTML格式),并附带工具版本、漏洞数据库更新时间戳。
4.2 最小化基础镜像:减少攻击面
最小化原则要求:镜像中只包含运行应用所必需的文件和依赖,移除所有包管理器、shell、调试工具、编译工具链和临时文件。推荐使用scratch、alpine、distroless等精简基础镜像。
验收检查清单:
- 基础镜像大小是否小于200MB(Java应用可放宽至400MB)
- 是否包含
apt/yum/apk等包管理器 - 是否包含
/bin/sh、/bin/bash等shell - 是否包含
curl、wget、netcat等网络调试工具 - 是否包含
gcc、make等编译工具 - 是否包含
.git目录、__pycache__等缓存文件
以下是一个典型的多阶段构建Dockerfile示例,展示如何实现最小化交付:
# 第一阶段:编译
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o myapp .
# 第二阶段:运行
FROM scratch
COPY --from=builder /app/myapp /myapp
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
ENTRYPOINT ["/myapp"]
4.3 非root运行:权限最小化
容器内进程默认以root用户运行是常见的安全风险。验收标准:镜像必须显式指定非root用户运行,且该用户UID应大于10000(避免与宿主机系统用户冲突)。
| 检查项 | 通过标准 | 失败示例 |
|---|---|---|
| Dockerfile中USER指令 | 必须存在且指向非root用户 | 无USER指令或USER root |
| 用户UID | UID > 10000 | UID 1000(可能冲突) |
| 容器内进程 | ps命令显示非root用户 | 进程用户为root |
| 文件权限 | 应用目录属主为非root用户 | 目录属主为root且权限777 |
常见陷阱:部分基础镜像(如
alpine)默认不包含非root用户。需要在Dockerfile中手动创建:RUN addgroup -g 10001 -S appgroup && adduser -u 10001 -S appuser -G appgroup。同时注意,如果应用需要监听1024以下端口,需配合CAP_NET_BIND_SERVICE能力或使用端口映射。
4.4 镜像签名与验证:供应链完整性
镜像签名确保镜像在构建、传输、存储过程中未被篡改。验收标准:所有交付镜像必须使用私钥签名,并在部署前由验证方使用公钥完成完整性校验。推荐使用cosign工具(Sigstore项目)或docker trust(Docker Content Trust)。
签名与验证流程:
- 构建镜像并推送至镜像仓库
- 使用私钥对镜像摘要签名:
cosign sign --key cosign.key <镜像地址> - 将签名信息存储于镜像仓库(OCI标准)或独立签名存储
- 部署前验证签名:
cosign verify --key cosign.pub <镜像地址> - 验证通过后允许拉取和部署
4.5 基线核验清单与交付验收
以下为容器镜像安全基线的完整核验清单,用于交付前逐项确认:
| 编号 | 核验项 | 验收标准 | 核验方法 |
|---|---|---|---|
| IMG-01 | 漏洞扫描 | 无Critical漏洞,High漏洞附缓解说明 | Trivy扫描报告 |
| IMG-02 | 最小化基础镜像 | 无包管理器、无shell、无调试工具 | docker history + dive分析 |
| IMG-03 | 非root运行 | USER指令存在且UID>10000 | Dockerfile检查 + 运行时ps验证 |
| IMG-04 | 镜像签名 | cosign签名存在且可验证 | cosign verify命令 |
| IMG-05 | 镜像层数 | 不超过20层(推荐≤10层) | docker inspect | jq '.RootFS.Layers | length' |
| IMG-06 | 敏感信息 | 无硬编码密钥、密码、 | docker history + 静态扫描 |
| IMG-07 | 文件权限 | 应用目录非777,无SUID/SGID文件 | find / -perm /6000 检查 |
自动化集成建议:将上述核验项集成到CI/CD流水线中,使用
conftest或kyverno策略引擎实现自动化策略检查。例如,使用Rego策略检查Dockerfile中是否包含USER指令且UID大于10000。
4.6 常见失败场景与处置
场景一:基础镜像包含高危漏洞
现象:Trivy扫描发现alpine:3.18存在CVE-2024-XXXXX(Critical)。
处置:升级至alpine:3.19或更高版本,重新构建并扫描验证。
现象:Trivy扫描发现alpine:3.18存在CVE-2024-XXXXX(Critical)。
处置:升级至alpine:3.19或更高版本,重新构建并扫描验证。
场景二:镜像以root用户运行
现象:Dockerfile中无USER指令,容器内进程为root。
处置:在Dockerfile末尾添加
现象:Dockerfile中无USER指令,容器内进程为root。
处置:在Dockerfile末尾添加
USER 10001:10001,并确保应用目录权限正确。
场景三:镜像签名验证失败
现象:cosign verify返回
处置:检查镜像标签是否与签名时一致,确认公钥与私钥匹配,重新签名并推送。
现象:cosign verify返回
error: no matching signatures。处置:检查镜像标签是否与签名时一致,确认公钥与私钥匹配,重新签名并推送。
通过以上四个维度的严格核验,确保交付的容器镜像在漏洞管理、攻击面控制、权限最小化和供应链完整性方面达到安全基线要求,为运行时安全奠定坚实基础。