← 中文资源

简体中文版本

镜像存在可修复高危漏洞时阻断流水线

扫描构建出的容器镜像,忽略暂无修复的漏洞,仅在有补丁的高危或严重漏洞上阻断发布,避免告警淹没团队。

阅读英文原文

概述

扫描 Dockerfile 或锁文件并不等于扫描镜像。运行时镜像包含基础层的操作系统包,而基础镜像的 CVE 恰恰出现在这里。应当扫描已推送的镜像,并且扫描 digest 而不是 tag,因为 tag 可能在扫描与部署之间被移动。把扫描放在与构建、推送相同的 job 中,位于任何发布步骤之前,失败时直接阻断发布,而不是事后生成一份报告。

步骤

  1. 扫描镜像,忽略暂无修复的漏洞,高危与严重级别直接失败:
trivy image --ignore-unfixed --severity HIGH,CRITICAL \
  --exit-code 1 ghcr.io/acme/api:$GITHUB_SHA
  1. 缓存漏洞数据库,避免每次 job 都重新下载:
- uses: actions/cache@v4
  with:
    path: ~/.cache/trivy
    key: trivy-db-${{ github.run_id }}
    restore-keys: trivy-db-
  1. 输出 SARIF,便于在仓库安全页集中跟踪:
trivy image --ignore-unfixed --severity HIGH,CRITICAL \
  --format sarif -o trivy.sarif ghcr.io/acme/api:$GITHUB_SHA
  1. 部署前按 digest 再扫描一次实际要运行的镜像:
trivy image --exit-code 1 --severity CRITICAL \
  ghcr.io/acme/api@sha256:6f1c2a9d4b7e8f0a1c3d5e7f9b2a4c6d8e0f1a3b5c7d9e1f3a5b7c9d1e3f5a7b

验证

验证分两步。先确认门禁会失败:临时用带已知可修复 CVE 的旧基础镜像构建,流水线应在推送后、发布前停止。再确认门禁会通过:修复后重新构建,扫描退出码为 0,SARIF 结果与镜像 digest 对应。若扫描在数分钟后才报错,说明它被放在了后续工作流中,应移动到构建 job 内。

注意事项

  • 镜像扫描无法发现业务逻辑漏洞,也可能漏掉不经系统包管理器安装的语言依赖。
  • --ignore-unfixed 会隐藏真实风险,应把未修复列表放入定期报告单独评审。
  • 例外必须写明 CVE、原因与到期时间,并在到期后自动失效。
  • 即使代码未变,也应定期重建并重扫,因为新披露的 CVE 需要新的扫描才能发现。
  • 扫描 tag 会留下时间窗,最终必须以 digest 为准。