Docker push前必须扫描镜像,否则漏洞、密钥等风险将裸奔上线;应在build后、push前用trivy --exit-code 1同步扫描并校验退出码,而非依赖registry异步拦截。

为什么 docker push 之前不扫描镜像,等于裸奔上线
镜像里藏着漏洞、硬编码密钥、违规基础镜像——这些不会在 docker push 时自动报错,但一推到 registry 就可能被攻击面暴露。CI 流水线里跳过扫描,等于把安全左移变成了“左忘”。
- 常见错误现象:
docker push成功,但第二天收到 SCA 工具告警:镜像含CVE-2023-1234高危漏洞,且已部署到预发环境 - 根本原因:Docker 本身不校验内容安全性,
push只做传输和存储,不触发任何审计逻辑 - 真正该拦截的位置:在
docker build完成后、docker push前,用独立工具对image id或repo:tag扫描并强制校验退出码
trivy image 扫描失败的三个典型卡点
trivy 是目前最轻量又可靠的 CLI 扫描器,但直接套命令常踩坑。
-
trivy image --severity CRITICAL myapp:latest不会阻断推送:默认只输出结果,返回码恒为 0,必须加--exit-code 1 --skip-update - 离线环境扫不了:
trivy默认联网拉漏洞库,CI 节点没外网时会超时卡住,得提前用trivy image --download-db-only同步trivy.db到共享路径 - 多阶段构建镜像扫空:如果只构建了 builder 阶段(如
docker build --target builder),而没指定最终运行镜像,trivy扫的是空层或中间镜像,得确认扫描对象是final阶段生成的image id
如何让 docker push 自动失败在漏洞超标时
核心是把扫描变成 shell 命令链中的一环,靠退出码驱动流程走向。
- 推荐写法(Bash):
trivy image --exit-code 1 --severity CRITICAL,HIGH --skip-update myapp:latest && docker push myapp:latest
- 注意
--exit-code 1必须显式指定,否则即使发现 CRITICAL 漏洞也返回 0 - CI 中建议加
--timeout 5m防止扫描卡死阻塞流水线 - 若用 GitHub Actions,别把
trivy放在docker/build-push-action的同一 step,它俩不共享文件系统;应先docker build -t myapp:latest .,再单独 step 扫描
registry 级别的推送拦截为什么不可靠
有人想在 Harbor 或 ECR 启用“阻止高危镜像推送”,这思路看似省事,实则危险。
- Harbor 的
vulnerability scan是异步的:镜像已入库,扫描才开始,等结果出来早推完了 - ECR 的
image scanning默认关闭,开启后也是事后触发,且不支持自定义阻断策略(比如只拦 CRITICAL,放过 HIGH) - 真正可控的拦截点只有一个:本地或 CI 构建机上,对即将推送的镜像做同步扫描 + 退出码判断
- 额外成本低:一次
trivy扫描平均耗时 10–40 秒,远低于构建本身,但能挡住 90% 的已知漏洞镜像上线
最易被忽略的是镜像标签污染:同一个 myapp:latest 可能被不同分支反复构建推送,但扫描脚本若没绑定具体 image id,就可能扫了旧缓存层,漏掉新引入的漏洞。

















