前置阅读:建议先阅读 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 三大扫描器对比
| 维度 | Trivy | Grype | Clair |
|---|---|---|---|
| 生态 | 独立 CLI/CI 常用 | Anchore 生态(配 Syft) | Harbor 内置 |
| SBOM 输出 | 支持 CycloneDX/SPDX | Syft 原生 | 内部索引 |
| 离线能力 | 强(预下载库) | 强 | 需自管 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/Clair | Syft 闭环 / Harbor 内置 | 按平台选 |
| SBOM | CycloneDX 供应链、SPDX 合规 | 先有清单才能扫 |
| 修复策略 | 按可达性排序,不追零漏洞 | 先修运行时高危 |
| 镜像最小化 | 包越少漏洞越少 | 减包即减风险 |
| CI 门禁 | 分级阻断 + 发布强制 | 门禁不拖循环 |
| 持续合规 | 仓库自动扫 + 报告归档 | 常态水位非一次性 |
镜像安全扫描不是"发布前跑一次 trivy",而是"SBOM 化 → 扫描 → 定级 → 修复 → 复扫 → 门禁 → 持续合规“的完整闭环。落地要点:为每个镜像生成并签名 SBOM,用 Trivy/Grype 按可达性定级修复,在 CI 发布阶段用 CRITICAL/HIGH 阈值门禁,再由 Harbor/ECR 做持续扫描与报告归档。当"无 SBOM 不发布、无复扫不上线、高危不部署"成为流水线默认,镜像安全才从"体检"变成"免疫系统”。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。