导读:本期聚焦于郭世昌创作的《如何实现容器镜像来源可追溯性?从构建、签名到分发的完整方案》,敬请观看详情。容器镜像的来源凭什么可信?当镜像仓库里躺着成百上千个镜像,你能说清每一个是谁构建的、基于什么代码、经过了哪些环节吗?镜像来源可追溯性是容器供应链安全的核心能力,它要求从代码提交、CI构建、镜像打包到最终部署的整条链路都有可验证的记录。本文将围绕镜像构建元数据的采集、镜像内容的摘要机制、镜像签名与验证、SBOM物料清单以及运行时准入校验五个关键环节展开,讲解如何利用Docker build的provenance attestations、cosign签名工具、镜像digest固定等手段,把一条不可篡改的证据链建立起来,并结合实际配置示例说明在Kubernetes环境中如何落地镜像来源校验策略。

容器镜像看似只是一个压缩包,实际上它是代码、依赖、构建环境共同作用后的产物。一旦某个镜像进入了生产环境,安全团队必须能回答三个问题:这个镜像从哪来、里面装了什么、经过谁的手。如果这三个问题答不上来,所谓的供应链安全就只是一句空话。镜像来源可追溯性解决的就是这个问题,它通过构建元数据记录、内容摘要校验、数字签名验证和物料清单等手段,把镜像从源码到运行的全过程串成一条可以事后审计的证据链。

如何实现容器镜像来源可追溯性?从构建、签名到分发的完整方案

为什么镜像追溯这么难:先看清问题的根源

追溯难的第一层原因在于传统镜像构建过程是黑盒。一条docker build命令执行完,除了镜像本身,几乎不留下任何关于构建环境的记录。用了哪个基础镜像、构建时拉取了哪些依赖、构建机器上有什么工具,这些都只存在于构建日志里,而日志往往会随着CI任务的清理而消失。

第二层原因是tag的不可靠性。很多团队习惯用latest或者v1.2.3这样的tag来标识镜像,但tag在仓库层面是可以被覆盖的。今天推送的app:v1.2.3和昨天同名的镜像,内容可能完全不同。如果部署清单里引用的是tag而不是内容摘要,那么追溯实际上建立在流沙之上。

第三层原因是镜像一旦分发出去,就无法约束它的二次传播。一个镜像从内部仓库导出、复制到其他环境后,接收方没有任何手段去验证这个镜像是否被篡改过。这三个问题叠加在一起,构成了镜像追溯的现实困境,也决定了后面的方案必须从构建、分发、运行三个环节同时入手。

构建元数据与内容摘要:追溯链的地基

追溯的第一步是让镜像自带身份信息。内容摘要(digest)是镜像内容的密码学哈希,只要镜像层内容有一比特的变化,摘要就会完全不同。使用sha256摘要引用镜像,可以保证拉取到的内容和当初验证过的内容完全一致:

# 查看镜像的完整摘要
docker images --digests

# 使用摘要而非tag拉取镜像,确保内容不可变
docker pull myregistry.local/app@sha256:8f3c1a2b9d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a

第二步是在构建时主动注入来源信息。最直接的做法是通过LABEL把Git提交号、构建流水线ID、构建时间写进镜像元数据:

# Dockerfile
ARG GIT_COMMIT=unknown
ARG BUILD_ID=unknown
ARG BUILD_TIME=unknown

LABEL org.opencontainers.image.revision=${GIT_COMMIT}
LABEL org.opencontainers.image.source="https://git.internal/app"
LABEL com.example.build.id=${BUILD_ID}
LABEL com.example.build.time=${BUILD_TIME}

这套标签遵循了OCI镜像规范的约定,多数镜像扫描工具都能识别。 LABEL方式的局限在于它是自愿声明的,构建者写什么就是什么,无法防伪造。要解决这个问题,需要引入带签名性质的构建证明(provenance attestation)。BuildKit和Buildx生成的attestation不是由构建者手写,而是由构建系统根据实际构建参数自动生成并附加到镜像上的SLSA格式证明文件,其中包含源码仓库地址、触发构建的commit、使用的Dockerfile路径、构建时间等关键信息,验证方可以确认这些数据来自构建系统而非人为篡改。

镜像签名与验证:让来源可被证明

元数据说明了镜像是怎么来的,签名则证明了镜像是谁认可的。目前业界主流的方案是sigstore项目的cosign工具,它使用非对称密钥对镜像摘要进行签名,签名存储在镜像仓库中与镜像摘要一一绑定。典型的工作流如下:

# 生成签名用的密钥对
cosign generate-key-pair

# 对镜像摘要进行签名(注意签名的是digest而不是tag)
cosign sign --key cosign.key myregistry.local/app@sha256:8f3c1a2b9d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a

# 在部署前验证签名
cosign verify --key cosign.pub myregistry.local/app@sha256:8f3c1a2b9d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a

这里有一个关键细节:签名必须针对digest而不是tag。如果对tag签名,攻击者覆盖tag后就绕过了验证。正确的流程是先解析出镜像的digest,对digest签名,部署时同样通过digest拉取并验证,这样tag篡改就完全失效了。

对于密钥管理,cosign支持无密钥的keyless模式,签名时使用短期证书,证书的身份与OIDC提供方(比如GitLab或GitHub的构建身份)绑定,验证方通过检查证书链来确认签名确实来自某条可信流水线。这种方式免去了私钥分发的麻烦,特别适合多团队协作的场景。无论选哪种模式,签名的私钥或身份凭证都必须只在CI环境中存在,绝不能下发到开发人员本地机器。

SBOM与运行时准入:把追溯延伸到运行阶段

镜像的可追溯性还包括内容透明,也就是弄清楚镜像里装了哪些软件包。SBOM(软件物料清单)以标准格式列出镜像内所有依赖及其版本,可以由构建工具自动生成并作为attestation附在镜像上,也可以单独存储:

# 使用syft为镜像生成SBOM
syft myregistry.local/app:v1.2.3 -o spdx-json > sbom.json

# 将SBOM附加到镜像
cosign attest --predicate sbom.json --type spdxjson \
  --key cosign.key \
  myregistry.local/app@sha256:8f3c1a2b9d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a

有了SBOM之后,当某个依赖爆出漏洞时,可以快速反查哪些镜像受影响,这比逐个扫描线上镜像高效得多。SBOM本身也是一种追溯证据,它记录了构建时刻镜像的真实内容组成,为事后审计提供了依据。

最后一环是在Kubernetes集群入口处强制校验。通过 admission 控制器(如cosign gateway或Kyverno策略引擎),可以要求所有Pod只能运行签名有效、来源合规的镜像。下面是一个Kyverno策略示例,它拒绝任何没有有效签名的镜像:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image-signature
spec:
  validationFailureAction: Enforce
  rules:
    - name: verify-cosign-signature
      match:
        any:
          - resources:
              kinds:
                - Pod
      verifyImages:
        - imageReferences:
            - "myregistry.local/*"
          attestors:
            - entries:
                - keys:
                    publicKeys: |-
                      -----BEGIN PUBLIC KEY-----
                      替换为实际的公钥内容
                      -----END PUBLIC KEY-----

这套策略生效后,即使有人手动提交了一个未签名或者签名不明的镜像到部署清单,也会在准入阶段被拦截。配合审计日志,每一次放行和拦截都有记录,整个追溯链条从构建一直闭合到了运行时。

落地建议与常见误区

推进镜像追溯时,建议按三个阶段逐步实施。第一阶段先做只读观测:在所有流水线中注入LABEL和生成digest记录,在集群中开启审计模式而非强制拦截,摸清存量镜像的合规率。第二阶段对新构建的镜像强制签名,CI流水线不签名就不允许推送。第三阶段才开启准入强制策略,同时给存量镜像预留替换窗口。

常见误区有几个需要特别提醒。一是只签名tag不固定digest,前面已经分析过这等于没签。二是把签名密钥放在CI的环境变量里且长期不轮换,密钥一旦泄露,攻击者可以给任意镜像签名,整个信任体系崩塌。三是忽略了基础镜像的追溯,自己的应用镜像签了名,但FROM的基础镜像来源不明,追溯链在第一层就断了,应当使用可信的基础镜像源并对内部缓存的镜像做定期校验。

镜像来源可追溯性不是单个工具能解决的问题,而是构建、签名、分发、运行四个环节共同构成的体系。一旦这条链路建立起来,它带来的不只是安全合规,还有排障效率的提升,出现问题时能精确定位到代码版本和构建批次,这才是追溯体系真正的日常价值。

容器镜像镜像签名供应链安全修改时间:2026-09-07 01:36:42

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260907/51892.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。