4. 镜像安全基线:镜像扫描工具(Trivy/Clair)、最小化基础镜像选择(Distroless/Alpine)、镜像签名与验证(Cosign)

容器镜像作为云原生应用的分发与运行载体,其安全性直接决定了生产环境的攻击面。镜像安全基线旨在通过“构建前预防 — 构建时扫描 — 分发时验证”三层防线,消除已知漏洞、减少攻击面并确保镜像完整性。本章围绕镜像扫描、基础镜像选择与签名验证三个核心实践展开。

4.1 镜像扫描工具:Trivy 与 Clair

镜像扫描工具通过解析镜像层文件系统与软件包数据库,将已安装的组件版本与公开漏洞库(CVE/NVD、Red Hat OVAL、Ubuntu CVE Tracker 等)进行比对,输出漏洞列表与严重等级。Trivy 与 Clair 是社区最广泛使用的两类扫描引擎。

特性 Trivy Clair
部署模式 单二进制 CLI / 客户端模式 服务端 + 客户端(API 驱动)
漏洞库更新 自动下载,离线缓存 需配置更新器,依赖 PostgreSQL
扫描速度 快(秒级,适合 CI 流水线) 中等(需等待索引完成)
支持格式 Docker / OCI / 本地文件系统 / Git 仓库 Docker / OCI / 索引清单
输出格式 Table / JSON / SARIF / HTML JSON(通过 Clairctl 或 API)
密钥/配置扫描 内置(支持 IaC 与 Secret 检测) 无
基线建议:在 CI 流水线中优先使用 Trivy 作为快速门禁扫描,设置 --severity CRITICAL,HIGH 为阻断条件;Clair 更适合部署在私有镜像仓库后端,对已推送镜像进行持续异步扫描。

以下为 Trivy 在 CI 中的典型阻断配置示例:

# .gitlab-ci.yml 片段
container_scan:
  stage: test
  script:
    - trivy image --severity CRITICAL,HIGH --exit-code 1 --ignore-unfixed \
        --vuln-type os,library $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  only:
    - main

4.2 最小化基础镜像选择:Distroless 与 Alpine

基础镜像的体积与组件数量直接决定攻击面。最小化原则要求仅保留应用运行时必需的依赖,移除 shell、包管理器、编译器与调试工具。Alpine Linux 与 Google Distroless 是两种主流方案。

维度 Alpine Distroless
基础 musl libc + BusyBox glibc / 特定语言运行时(Java、Python、Node.js)
镜像大小 ~5 MB(空镜像) ~2–20 MB(视运行时而定)
Shell 与包管理器 有(apk、sh) 无
CVE 数量(典型) 低(但 musl 兼容性问题偶发) 极低(仅包含运行时必要库)
调试能力 可进入容器执行命令 无法直接进入(需附加 debug 镜像)
适用场景 通用微服务、需要轻量调试 生产环境、安全合规要求严格
避坑提示:Alpine 使用 musl libc,部分依赖 glibc 特性的 Go 或 C 扩展库可能出现运行时异常。建议在编译阶段使用 CGO_ENABLED=0 静态编译,或直接选用 Distroless 镜像消除兼容性风险。

以下为多阶段构建选择 Distroless 的 Dockerfile 示例:

# 构建阶段
FROM golang:1.21 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/server

# 运行阶段 — 使用 Distroless 静态镜像
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=builder /app/server /server
USER nonroot:nonroot
ENTRYPOINT ["/server"]

4.3 镜像签名与验证:Cosign

镜像签名确保镜像在构建后未被篡改,并建立发布者身份的可信链。Cosign 是 Sigstore 项目下的无密钥签名工具,支持密钥对、密钥管理服务(KMS)以及 OIDC 身份绑定。签名以 OCI 制品形式存储在镜像仓库中,验证时无需额外基础设施。

Cosign 镜像签名与验证流程 开发者 / CI 流水线 cosign sign OCI 镜像仓库 镜像摘要 + 签名载荷(.sig) K8s 准入控制器 cosign verify 通过 / 拒绝 部署策略 公钥 / KMS 密钥 / OIDC 身份令牌 — 由 Sigstore 或内部 PKI 分发

Cosign 签名与验证的核心命令:

# 使用密钥对签名(推荐 KMS 或环境变量保护私钥)
cosign generate-key-pair
cosign sign --key cosign.key registry.example.com/app:v1

# 在部署前验证签名
cosign verify --key cosign.pub registry.example.com/app:v1

# 使用密钥管理服务(AWS KMS 示例)
cosign sign --key awskms:///arn:aws:kms:us-east-1:123456789012:key/abcd-1234 \
  registry.example.com/app:v1
基线策略:在 Kubernetes 集群中部署 cosigned 准入控制器(现为 Sigstore Policy Controller),强制所有 Pod 引用的镜像必须包含有效签名。未签名或签名验证失败的镜像将被拒绝创建,实现“只运行已签名镜像”的安全基线。

4.4 镜像安全基线策略总结

将上述三个实践整合为可执行的基线策略清单:

  1. 基础镜像锁定:禁止使用 latest 标签;仅允许使用 Distroless 或 Alpine 作为运行阶段基础镜像;建立组织级基础镜像白名单。
  2. 构建时扫描门禁:CI 流水线中集成 Trivy,CRITICAL 与 HIGH 漏洞数 > 0 时阻断构建;每周更新漏洞库。
  3. 镜像签名强制:所有推送至生产仓库的镜像必须使用 Cosign 签名;私钥由 KMS 或 CI 密钥管理服务托管。
  4. 部署验证:Kubernetes 准入控制器配置 Cosign 验证策略,拒绝未签名或签名无效的镜像。
  5. 定期重扫描:对已部署镜像每 24 小时通过 Clair 或 Trivy 重新扫描,发现新漏洞时触发告警与自动修复流水线。
注意:镜像签名仅保证内容完整性,不替代漏洞扫描。签名应在扫描通过后执行,确保已签名的镜像同时满足漏洞阈值与来源可信要求。