Dockerfile 写作精讲 / 12 - 镜像安全
12 - 镜像安全:漏洞扫描、签名与 SBOM
12.1 安全威胁概览
容器镜像面临的主要安全威胁:
| 威胁类型 | 说明 | 示例 |
|---|
| 已知漏洞 | 基础镜像或依赖中的 CVE | Log4Shell (CVE-2021-44228) |
| 恶意软件 | 镜像中包含挖矿程序等 | 供应链攻击 |
| 配置错误 | 以 root 运行、暴露端口等 | CIS Benchmark 违规 |
| 供应链攻击 | 镜像被篡改 | 镜像投毒 |
| 敏感信息泄露 | 密钥、密码硬编码在镜像中 | .env 文件被复制到镜像 |
12.2 漏洞扫描:Trivy
安装 Trivy
# Ubuntu/Debian
sudo apt-get install trivy
# macOS
brew install trivy
# Docker 方式运行
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image myapp:latest
基本扫描
# 扫描镜像
trivy image myapp:latest
# 扫描本地 Dockerfile
trivy config Dockerfile
# 扫描目录(包含 Dockerfile、Kubernetes manifests 等)
trivy fs .
# 输出 JSON 格式
trivy image --format json --output result.json myapp:latest
# 仅显示高危和严重漏洞
trivy image --severity HIGH,CRITICAL myapp:latest
# 退出码(CI 集成)
trivy image --exit-code 1 --severity CRITICAL myapp:latest
扫描结果解读
myapp:latest (debian 12.4)
Total: 15 (UNKNOWN: 0, LOW: 5, MEDIUM: 6, HIGH: 3, CRITICAL: 1)
┌──────────────┬────────────────┬──────────┬─────────────────────────────────┐
│ Library │ Vulnerability │ Severity │ Fixed Version │
├──────────────┼────────────────┼──────────┼─────────────────────────────────┤
│ libssl3 │ CVE-2024-0727 │ CRITICAL │ 3.0.13-1~deb12u1 │
│ curl │ CVE-2024-2096 │ HIGH │ 7.88.1-10+deb12u5 │
│ libcurl4 │ CVE-2024-2096 │ HIGH │ 7.88.1-10+deb12u5 │
└──────────────┴────────────────┴──────────┴─────────────────────────────────┘
在 CI 中集成 Trivy
# GitHub Actions
name: Security Scan
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
exit-code: '1'
- name: Upload Trivy scan results to GitHub Security
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'trivy-results.sarif'
Trivy 忽略文件
# .trivyignore
# 忽略特定 CVE(需要评估风险后才可忽略)
CVE-2024-0727
# 忽略特定漏洞(带有效期)
CVE-2024-2096
expires: 2026-12-31
12.3 其他扫描工具
| 工具 | 特点 | 安装方式 |
|---|
| Trivy | 全面、快速、免费 | apt/brew/docker |
| Grype | Anchore 出品,速度快 | curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh |
| Docker Scout | Docker 官方集成 | docker scout cves myapp:latest |
| Snyk | 商业工具,有免费额度 | npm install -g snyk |
| Clair | Red Hat 出品,可自建 | 部署为服务 |
Docker Scout
# Docker Desktop 内置 Scout
docker scout cves myapp:latest
# 快速查看建议
docker scout recommendations myapp:latest
# 比较两个版本的漏洞
docker scout compare myapp:v1 myapp:v2
12.4 镜像签名:Cosign
Cosign 是 Sigstore 项目的一部分,用于对容器镜像进行签名和验证。
安装 Cosign
# 下载最新版
COSIGN_VERSION="v2.2.3"
curl -fsSL "https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign-linux-amd64" \
-o /usr/local/bin/cosign
chmod +x /usr/local/bin/cosign
签名镜像
# 生成密钥对
cosign generate-key-pair
# 使用私钥签名
cosign sign --key cosign.key registry.example.com/myapp:latest
# 使用密钥签名并附加签名
cosign sign --key cosign.key \
-a "commit=$(git rev-parse HEAD)" \
-a "builder=$(whoami)" \
registry.example.com/myapp:latest
验证签名
# 使用公钥验证
cosign verify --key cosign.pub registry.example.com/myapp:latest
# 输出验证结果
# The following checks were performed:
# - The cosign claims were validated
# - The signatures were verified against the specified public key
# 在 K8s 中强制验证(使用 Kyverno 或 OPA Gatekeeper)
Keyless 签名(无密钥)
# 使用 OIDC 身份签名(适合 CI/CD)
# 不需要管理密钥对
cosign sign \
--yes \
--identity-token=$(get-oidc-token) \
registry.example.com/myapp:latest
# 在 GitHub Actions 中使用
# 直接使用 GITHUB_TOKEN,无需配置密钥
CI/CD 集成签名
# GitHub Actions 中签名
name: Build and Sign
on: push
jobs:
build:
runs-on: ubuntu-latest
permissions:
id-token: write # OIDC
contents: read
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v5
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
- uses: sigstore/cosign-installer@v3
- name: Sign image
run: cosign sign --yes ghcr.io/${{ github.repository }}:${{ github.sha }}
12.5 SBOM(软件物料清单)
SBOM 记录了镜像中包含的所有软件组件及其版本,是供应链安全的基础。
生成 SBOM
# 使用 syft(Anchore 出品)
syft myapp:latest -o spdx-json > sbom.spdx.json
syft myapp:latest -o cyclonedx-json > sbom.cdx.json
# 使用 Docker SBOM 插件
docker sbom myapp:latest
# 附加 SBOM 到镜像(OCI artifact)
cosign attest --predicate sbom.spdx.json --type spdx \
--key cosign.key \
registry.example.com/myapp:latest
SBOM 内容示例
{
"spdxVersion": "SPDX-2.3",
"name": "myapp",
"packages": [
{
"name": "openssl",
"versionInfo": "3.0.13",
"licenseConcluded": "Apache-2.0"
},
{
"name": "curl",
"versionInfo": "7.88.1",
"licenseConcluded": "MIT"
}
]
}
合规要求
| 标准/法规 | 要求 |
|---|
| 美国行政令 14028 | 联邦采购需提供 SBOM |
| EU CRA | 数字产品需提供 SBOM |
| PCI DSS 4.0 | 软件清单与漏洞管理 |
| ISO 27001 | 资产管理与风险评估 |
12.6 安全基础镜像选择
最小化原则
# ❌ 包含大量不必要的工具
FROM ubuntu:22.04
# ✅ 使用精简镜像
FROM python:3.12-slim
# ✅ 使用 Distroless(无 shell、无包管理器)
FROM gcr.io/distroless/python3
# ✅ 使用 Chainguard Images(零 CVE 目标)
FROM cgr.dev/chainguard/python:latest
安全扫描策略
开发阶段: trivy image --severity CRITICAL (仅阻断严重漏洞)
CI 阶段: trivy image --severity HIGH,CRITICAL (阻断高危和严重)
生产阶段: trivy image --exit-code 1 (阻断所有已知漏洞)
12.7 镜像安全检查清单
| 检查项 | 方法 |
|---|
| 使用非 root 用户 | USER 指令 |
| 不安装不必要的包 | 精简基础镜像 |
| 定期更新基础镜像 | Dependabot / Renovate |
| 扫描漏洞 | Trivy / Grype |
| 不硬编码秘密 | BuildKit secrets |
| 签名镜像 | Cosign |
| 生成 SBOM | syft / docker sbom |
| 固定镜像版本 | 使用 digest 或具体版本标签 |
| 设置只读文件系统 | docker run --read-only |
| 限制资源 | --memory / --cpus |
12.8 常见错误与排查
| 错误 | 原因 | 解决方案 |
|---|
| 扫描发现大量 CVE | 基础镜像过旧 | 更新基础镜像版本 |
| 签名验证失败 | 公钥不匹配或镜像被篡改 | 检查密钥对和镜像来源 |
| SBOM 不完整 | 未包含所有依赖 | 使用多阶段构建时在最终阶段生成 |
| 忽略的 CVE 重新出现 | .trivyignore 过期 | 更新忽略文件 |
12.9 扩展阅读
上一章:11 - BuildKit 高级特性
下一章:13 - 语言最佳实践 — Node.js / Go / Java / Python / Rust 的专项模板。