镜像安全扫描与 SBOM:Trivy、Grype、Clair 与 CI 安全门禁

系统讲解镜像安全扫描与软件物料清单(SBOM):漏洞扫描原理与 CVE 数据库、Trivy/Grype/Clair 三大扫描器横向对比、CycloneDX/SPDX 两种 SBOM 格式与生成校验、漏洞修复策略(基镜像升级/重建/依赖升降级)、镜像重构与最小化、CI 中的安全门禁与阈值,以及 Harbor/ECR 的持续扫描与合规报告。

前置阅读:建议先阅读 Docker 镜像供应链安全:SBOM、签名、扫描与 SLSA 合规 与 Docker 生产安全指南:镜像扫描、非 root 运行、Secret 管理与 Registry。本篇聚焦扫描器机制、SBOM 格式与修复/门禁闭环。

关键概念:扫描回答"镜像里有哪些已知漏洞",SBOM 回答"镜像里装了哪些软件"。扫描依赖 SBOM 找包,SBOM 依赖正确的包解析——两者是同一枚硬币的两面。没有持续修复与门禁的扫描只是"体检报告",不解决风险。


1. 扫描原理

1.1 从镜像到漏洞列表

扫描流水线:
  解包镜像层 → 识别操作系统/语言包管理器 → 生成 SBOM(包清单)
  → 匹配 CVE 数据库(按包名+版本)→ 输出漏洞报告

关键依赖:
  - 层数据:镜像层解包(overlayfs 层 → 文件树)
  - 包解析器:apk/dpkg/rpm、pip/npm/maven/golang
  - 漏洞库:OSV、NVD、厂商数据库(红帽、Debian、Alpine)

1.2 为什么有的镜像"扫不出漏洞"

扫描盲区:
  - distroless/scratch:无包管理器,扫描器无从识别(不代表无漏洞)
  - 静态编译二进制:无包元数据,需 SBOM 显式声明
  - 语言运行时自带依赖:如 .NET self-contained,需运行时级 SBOM
结论:扫描工具 + 显式 SBOM 结合,才能覆盖"无包管理器"场景
镜像类型可扫描性补救
传统发行版(alpine/ubuntu)高(有包管理器)直接扫
distroless低(无包管理器)构建时生成 SBOM
scratch/静态二进制极低显式 SBOM + 签名

一句话:扫描的准确度取决于"包清单能不能被解析出来"——越是精简镜像越要主动生成 SBOM 补位。


2. Trivy 深度使用

2.1 基础扫描

# 扫描镜像全部漏洞
trivy image --severity HIGH,CRITICAL registry.example.com/app:v1
# 指定输出格式(json / sarif / table)
trivy image -f json -o report.json registry.example.com/app:v1
# 只扫配置/密钥(不扫漏洞)
trivy config --severity CRITICAL Dockerfile
trivy fs --skip-files '*.min.js' .

2.2 漏洞库与离线

# 更新漏洞库(默认启动时自动下载到缓存)
trivy image --update-cache registry.example.com/app:v1
# 完全离线:预先导出漏洞库
trivy image --download-db-only
# 用离线库扫描
trivy image --skip-db-update --offline-scan registry.example.com/app:v1

2.3 忽略与阈值

# 忽略特定 CVE(写 .trivyignore)
# CVE-2024-0001
# reason: 该漏洞仅影响非生产路径

trivy image --ignorefile .trivyignore registry.example.com/app:v1
# 退出码语义:0=无漏洞或全忽略,1=有漏洞(可接入 CI 门禁)

一句话:Trivy 是"多格式一体化扫描器"——镜像/文件系统/配置都能扫,离线库与 ignore 文件让它能融入 CI 门禁。


3. Grype 与 Clair

3.1 Grype + Syft 组合

# Syft 生成 SBOM,Grype 基于 SBOM 扫漏洞(同团队工具链)
syft registry.example.com/app:v1 -o spdx-json > sbom.spdx.json
grype sbom:sbom.spdx.json -o table
# 或直接扫镜像(内部会先生成 SBOM)
grype registry.example.com/app:v1
Grype 特点:
  - 与 Syft 深度集成:SBOM 驱动,结果可复现
  - 支持多种输入:镜像、SBOM 文件、OCI 目录
  - 输出格式:table/json/cyclonedx/sarif

3.2 Clair 架构(Harbor 内置)

Clair 是 Harbor 的内置扫描引擎(v4 起):
  - 分层索引:Indexer(解包+生成包清单)与 Matcher(匹配漏洞)
  - 通过 Harbor API 触发,结果存在 PostgreSQL
  - 支持 OS 与语言包漏洞匹配
部署形态:Kubernetes 内 Clair 组件(indexer/matcher/notifier)

3.3 三大扫描器对比

维度TrivyGrypeClair
生态独立 CLI/CI 常用Anchore 生态(配 Syft)Harbor 内置
SBOM 输出支持 CycloneDX/SPDXSyft 原生内部索引
离线能力强(预下载库)强需自管 DB
集成方式任意 CI任意 CI + Anchore 平台Harbor/K8s

一句话:Trivy 通用、Grype 与 Syft 闭环、Clair 与 Harbor 一体——按"你的镜像平台在哪"选,别为了扫而扫。


4. SBOM 格式与生成

4.1 CycloneDX 与 SPDX

格式特点适用
CycloneDX侧重"组件+依赖关系"、支持漏洞声明应用/供应链自动化
SPDX侧重"许可证+文件来源",合规审计标准法律合规、许可证管理
# Syft 生成两种格式
syft registry.example.com/app:v1 -o cyclonedx-json > sbom.cdx.json
syft registry.example.com/app:v1 -o spdx-json > sbom.spdx.json

4.2 校验 SBOM 真实性

SBOM 也要可信:伪造的 SBOM 会让扫描失去意义
  - 用 cosign 签名 SBOM 附件(见镜像签名篇)
  - 验证时同时校验 SBOM 的签名与完整性
  - 生成与签名在 CI 内完成,保证来源可信

4.3 SBOM 的维护与生命周期

□ 每次构建生成新 SBOM 并随镜像发布(Harbor 2.5+/ECR 支持附件)
□ 定期对存量镜像补扫(新 CVE 披露后)——SBOM 让补扫更快
□ SBOM 归档:按镜像 digest 保存历史版本,便于审计回看

一句话:SBOM 是"镜像是哪些组件构成的"结构化声明——CycloneDX 管供应链、SPDX 管合规,且 SBOM 本身要签名才能信。


5. 漏洞修复策略

5.1 四类修复手段

策略做法适用
基镜像升级换新版本基础镜像重建依赖在 OS 层/语言包时
重建固定依赖版本后重新构建上游已修复、需同步依赖
依赖升降级手动 pin 到安全版本个别 CVE、重建成本高时
运行时规避配置层缓解(禁用受影响功能)无修复版本时兜底

5.2 优先修复谁

修复优先级(按风险面):
  ① 运行时常驻进程依赖(如 Web 框架、TLS 库)
  ② 对外暴露端口组件的依赖(监听 0.0.0.0)
  ③ 攻击链可及组件(与输入处理相关的解析器)
  ④ 仅构建期/工具链依赖(风险低,可延后)
不追求"零漏洞":把 CRITICAL+ 且运行时可达的先清掉

5.3 修复闭环流程

发现(扫描报告)→ 定级(severity+可达性)→ 修复(升级/重建)
→ 复扫验证 → 放行发布
关键:修复后重新扫描并保存新报告,形成"扫描-修复-复扫"闭环

一句话:修复不是"把所有 CVE 清零",而是"按可达性与影响面排序,把 CRITICAL 且运行时可达的先修掉"。


6. 镜像重构与最小化

6.1 多阶段构建减攻击面

# 构建工具只在 builder 阶段,运行时镜像最小化
FROM node:20 AS builder
COPY . .
RUN npm ci && npm run build

FROM node:20-slim
COPY --from=builder /app/dist /app/dist
USER node
ENTRYPOINT ["node", "/app/dist/server.js"]
最小化收益:
  - 更少包 → 更少 CVE(攻击面收敛)
  - 更小镜像 → 拉取快、扫描快、存储省

6.2 无包管理器镜像 + 显式 SBOM

FROM scratch
COPY --from=builder /app/bin /app
ENTRYPOINT ["/app/bin"]
# 无包管理器:需在 CI 显式生成 SBOM 供扫描器使用
# CI 里对 scratch 镜像补生成 SBOM(基于构建产物)
syft dir:./dist -o cyclonedx-json > sbom.cdx.json
grype sbom:sbom.cdx.json

6.3 可复现构建

□ 锁定基础镜像 digest(而非 tag):FROM node:20@sha256:...
□ 锁定依赖 lockfile(package-lock/go.sum/poetry.lock)
□ 构建产物可复现 → 每次重建的 SBOM 可对比、可回滚

一句话:镜像最小化 + 可复现构建是扫描的"治本"——包越少漏洞越少,构建越可复现越能稳定复扫。


7. CI 中的安全门禁

7.1 门禁阈值设计

# CI 中扫描并门禁:CRITICAL>0 或 HIGH>N 即失败
trivy image --exit-code 1 --severity CRITICAL,HIGH \
  --ignore-unfixed registry.example.com/app:v1
门禁设计原则:
  - 阻断条件:CRITICAL 必阻断;HIGH 可设阈值;MEDIUM 只告警
  - 基线豁免:遗留镜像用"已知清单"豁免,新引入必须为零
  - 区分:构建期工具链漏洞不阻断,运行时组件漏洞必阻断

7.2 GitHub Actions 集成

steps:
  - uses: actions/checkout@v4
  - name: 构建镜像
    run: docker build -t $IMAGE .
  - name: 扫描镜像
    uses: aquasecurity/trivy-action@master
    with:
      image-ref: $IMAGE
      format: sarif
      output: trivy-results.sarif
      exit-code: '1'
      severity: CRITICAL,HIGH
  - name: 上传 SARIF 到 GitHub 安全中心
    uses: github/codeql-action/upload-sarif@v3
    with:
      sarif_file: trivy-results.sarif

7.3 门禁与发布解耦

推荐:扫描门禁在"合并/发布"而非"每次提交"执行
  - PR 阶段:轻量扫描(只扫变更镜像)
  - 发布阶段:全量扫描 + 门禁,不通过不出 artifact
  - 避免:扫描拖慢开发者循环(CI 时间/误报噪音)

一句话:CI 门禁要"分级阻断 + 基线豁免 + 发布时强制"——既不放过高危,也不让扫描噪音拖垮开发节奏。


8. 持续监控与合规

8.1 Harbor 持续扫描

# 在 Harbor 启用自动扫描(推镜像后自动扫)
# Harbor 项目设置 → 扫描策略 → 自动扫描
# 或用 API 触发
curl -X POST https://harbor.example.com/api/v2.0/projects/library/ \
  -u admin:pass -H "Content-Type: application/json" \
  -d '{"auto_scan": true}'
Harbor 持续扫描能力:
  - 自动扫描新推送镜像 + 定时全量补扫
  - 漏洞分级展示、按 CVE 过滤
  - 配合保留策略:高危镜像禁止复制/拉取

8.2 ECR / 云厂商扫描

ECR Enhanced Scanning(Inspector):
  - 持续扫描 + 漏洞态势报告
  - 与 CI 门禁联动(findings 驱动)
  - 支持 Lambda/ECR 等资源统一管理

8.3 合规与报告

□ 定期输出镜像漏洞报告(按项目/仓库/时间维度)
□ 高危处置记录(修复版本、复扫结果)供审计
□ SBOM 归档满足许可证合规(SPDX)与供应链披露要求
□ 与签名/准入联动:无有效扫描报告的镜像不部署

一句话:持续扫描把"一次门禁"变成"常态水位"——仓库自动扫、云平台持续扫、报告与签名联动,才算完整合规。


9. 总结

主题关键结论一句话记忆
扫描原理依赖包解析 + CVE 库解析不了就扫不出
Trivy一体化、离线库、退出码门禁CI 首选
Grype/ClairSyft 闭环 / Harbor 内置按平台选
SBOMCycloneDX 供应链、SPDX 合规先有清单才能扫
修复策略按可达性排序,不追零漏洞先修运行时高危
镜像最小化包越少漏洞越少减包即减风险
CI 门禁分级阻断 + 发布强制门禁不拖循环
持续合规仓库自动扫 + 报告归档常态水位非一次性

镜像安全扫描不是"发布前跑一次 trivy",而是"SBOM 化 → 扫描 → 定级 → 修复 → 复扫 → 门禁 → 持续合规“的完整闭环。落地要点:为每个镜像生成并签名 SBOM,用 Trivy/Grype 按可达性定级修复,在 CI 发布阶段用 CRITICAL/HIGH 阈值门禁,再由 Harbor/ECR 做持续扫描与报告归档。当"无 SBOM 不发布、无复扫不上线、高危不部署"成为流水线默认,镜像安全才从"体检"变成"免疫系统”。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「docker」更多文章

  1. containerd 插件机制与扩展:snapshotter、shim 与 CNI 的深度定制
  2. 边缘容器与轻量运行时:Wasm、gVisor 与 K3s 的资源受限实践
  3. 多集群多区域镜像同步与分发:从复制拓扑到 P2P 拉取加速