news 2026/7/25 17:02:13

CI 供应链被投毒后,我用 Sigstore + SLSA 给镜像签了一次名就再没睡不踏实

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CI 供应链被投毒后,我用 Sigstore + SLSA 给镜像签了一次名就再没睡不踏实

CI 供应链被投毒后,我用 Sigstore + SLSA 给镜像签了一次名就再没睡不踏实

上周凌晨,一条 CI 告警把我惊醒:构建产出的镜像 digest 和昨晚的基准不一致。

不是代码变更,不是依赖升级,是某个基础镜像 layer 里被人塞进了一个修改过的.so文件。排查了三个小时,最后定位到一台镜像缓存节点被污染,构建时拉到了被投毒的busybox:1.36.1。那一刻我才意识到,我们的 CI 一直在裸奔。没有人验证镜像到底是谁构建的,也没有人验证它有没有被改过。

天亮后,我花了一天时间把 Sigstore + SLSA 接到 CI 里。这篇文章不是科普,而是想记录一套能直接落地的镜像签名和来源验证流程。

被投毒的那一夜

先还原一下现场:

  • 我们的构建流水线从 Docker Hub 拉基础镜像,构建业务镜像后推送到内部仓库。
  • 镜像 tag 是可变的,digest 却没人记录。
  • 生产环境拉镜像时只校验 tag,不校验签名,也不校验来源。

攻击者(或者内部误操作)在某台缓存节点上替换了一个 layer 的 blob。因为 tag 没变,构建时直接用了这个被污染的层。最终产出的业务镜像里夹带了后门。

这次运气好,被改的是测试环境的镜像。如果是生产,后果不堪设想。

我想要的其实就两件事

  1. 签名:构建完成后,镜像必须被不可抵赖的密钥签名。
  2. 来源:任何人都能验证这个镜像是在哪条 CI 流水线上、从哪个 commit 构建出来的。

Sigstore 的 cosign 解决第一件事;SLSA provenance 解决第二件事。两者加起来,刚好覆盖我的诉求。

第一步:用 cosign 给镜像签名

我们先在 CI 里生成密钥对:

cosign generate-key-pair k8s://ci-namespace/signing-key

用的是 Kubernetes KMS 封装,私钥不会落地到构建节点。然后构建镜像时:

IMAGE=registry.internal/myapp:$GIT_COMMIT_SHORTdockerbuild-t$IMAGE.dockerpush$IMAGEcosign sign--keyk8s://ci-namespace/signing-key\--annotations"commit=$GIT_COMMIT"\--annotations"pipeline=$CI_PIPELINE_URL"\$IMAGE

签名的同时,我把 commit 和 pipeline URL 也写进 annotations。后续查来源一目了然。

验证签名很简单:

cosign verify--keycosign.pub registry.internal/myapp:abc123\--annotations"commit=abc123"\--annotations"pipeline=https://ci.example.com/pipelines/42"

如果镜像被篡改,或者不是这条流水线构建的,验证直接失败。

第二步:用 SLSA provenance 记录来源

签名只能说明“这个镜像没被改”,但没法证明“它是按我期望的方式构建的”。SLSA provenance 就是做这个的。

我们在 CI 里接入 SLSA GitHub Generator(我们用的是 GitLab,所以用它的 generic provenance 模式):

sign-image:stage:signimage:ghcr.io/slsa-framework/slsa-generator-containerscript:-cosign sign--key k8s://ci-namespace/signing-key $IMAGE-generate-provenance--subjects "${IMAGE}@${DIGEST}" \--predicate provenance.json-cosign attest--key k8s://ci-namespace/signing-key \--predicate provenance.json--type slsaprovenance $IMAGE

生成的 provenance 文件里包含:

  • 构建器 ID(GitLab runner 的 URL)
  • 源码仓库和 commit SHA
  • 构建定义文件(CI 配置)
  • 输入参数和依赖列表

部署时,我加了一条验证:

cosign verify-attestation--keycosign.pub\--typeslsaprovenance\--policypolicy.cue\$IMAGE

policy.cue里规定:只允许来自特定仓库、特定分支、使用官方 runner 构建的镜像进入生产命名空间。

第三步:K8s 准入校验,不签名的镜像不许跑

光有签名不够,必须让集群执行。我装了一个 Kyverno 策略:

apiVersion:kyverno.io/v1kind:ClusterPolicymetadata:name:verify-image-signaturespec:validationFailureAction:Enforcerules:-name:check-cosign-signaturematch:resources:kinds:-Podnamespaces:-productionverifyImages:-imageReferences:-"registry.internal/*"key:|-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA... -----END PUBLIC KEY-----

从那以后,任何没签名或签名验证失败的镜像,K8s 直接拒绝拉起。测试环境可以先告警,生产环境直接拦截。

落地后的变化

环节改造前改造后
镜像来源只认 tag签名 + provenance + commit
部署校验Kyverno 强制拦截
缓存污染无法发现签名验证失败直接暴露
回滚追溯靠 tag 猜用 digest 和 commit 精确对应
构建器信任任何 runner只允许官方 runner + 签名

最让我安心的是最后一条:即使有人拿到了内部仓库的推送权限,没有签名密钥,他也无法让镜像通过校验跑起来。

三个容易踩的坑

1. 不要把私钥存在 CI 变量里

早期我图省事把 cosign 私钥放在 GitLab CI variable 里。后来改成 Kubernetes KMS 封装,私钥不出 KMS,构建节点只拿到临时 token。安全性差了一个数量级。

2. 签名一定要基于 digest,而不是 tag

cosign sign--keyk8s://ci-namespace/signing-key$IMAGE@$DIGEST

tag 是可变的,digest 才是镜像的唯一指纹。验证时也用 digest,否则攻击者可以替换同名 tag 的镜像。

3. 别忘了给基础镜像也做验证

我们只签了自己的业务镜像,结果基础镜像还是裸奔。后来把所有 base image 也纳入cosign verify检查,并在 Dockerfile 里固定 digest:

FROM busybox@sha256:abc123...

配合 Renovate 自动更新 digest,既安全又不耽误升级。

写在最后

供应链安全不是玄学,也不是只有大厂才需要。一台被污染的缓存节点、一个被替换的 base image、一个被盗用的 CI runner,都可能让你的镜像在不知不觉间“带毒”。

Sigstore + SLSA 的组合,把镜像从“信任 tag”变成“信任密码学证明”。这套东西落地一天后,我再看 CI 流水线,终于能睡踏实了。

如果你还在用docker pull之后直接kubectl apply,建议先从 cosign 签名开始。成本不高,但回报是:你再也不用担心凌晨被镜像 digest 告警叫醒了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/25 17:01:45

家具渲染色彩管理:解决预览与保存不一致的完整方案

你是否曾经遇到过这样的情况:在3D软件中精心调整好家具渲染效果,预览时色彩鲜艳、细节丰富,但保存成图片后却发现颜色暗淡、对比度全无?这种"预览美如画,保存成渣渣"的体验,相信很多3D设计师都深…

作者头像 李华
网站建设 2026/7/25 17:00:49

NoFences:免费开源Windows桌面分区工具,3分钟创建整洁工作空间

NoFences:免费开源Windows桌面分区工具,3分钟创建整洁工作空间 【免费下载链接】NoFences 🚧 Open Source Stardock Fences alternative 项目地址: https://gitcode.com/gh_mirrors/no/NoFences 还在为Windows桌面上杂乱的图标而烦恼吗…

作者头像 李华
网站建设 2026/7/25 16:59:52

英雄联盟Akari助手:3分钟快速安装的免费开源游戏效率工具

英雄联盟Akari助手:3分钟快速安装的免费开源游戏效率工具 【免费下载链接】League-Toolkit An all-in-one toolkit for LeagueClient. Gathering power 🚀. 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit 还在为英雄联盟中的繁琐操…

作者头像 李华
网站建设 2026/7/25 16:56:56

创业团队如何利用Taotoken实现API密钥的权限管理与访问审计

创业团队如何利用Taotoken实现API密钥的权限管理与访问审计 对于快速成长的创业技术团队而言,随着成员的增加和项目复杂度的提升,大模型API的调用管理会迅速成为一个痛点。当多个开发者、不同项目组共享同一个API密钥时,不仅存在密钥泄露的风…

作者头像 李华
网站建设 2026/7/25 16:55:44

AI守望者:人类灭绝后的机器文明延续

1. 项目背景与核心概念"沉默守望者"这个项目构想了一个极具哲学深度的科幻场景:当人类文明灭绝200年后,由人类创造的AI系统仍在持续运行。这些"守望者"们坚守着早已无人的城市,执行着早已失去意义的程序指令,…

作者头像 李华