如何构建容器镜像供应链的安全防护体系?

来源:我的博客作者:鱼儿头衔:草根站长
导读:本期聚焦于鱼儿创作的《如何构建容器镜像供应链的安全防护体系?》,敬请观看详情。镜像被篡改、基础镜像带漏洞、构建依赖被投毒,这些问题在容器化部署中并不罕见。供应链攻击一旦进入镜像仓库,会随发布流程扩散到生产环境,传统的边界防护很难察觉。要堵住这个缺口,需要从镜像的构建、签名、扫描和运行四个环节同时下手。文章围绕容器镜像供应链的信任链展开,先拆解上游基础镜像、构建工具链、依赖包和仓库分发中的风险点,再说明如何用Docker Content Trust、Cosign签名和Sigstore体系验证镜像来源,配合Trivy、Grype等扫描器在CI阶段拦截漏洞。接着介绍镜像最小化、SBOM物料清单和多阶段构建的落地方法,以及准入控制器在运行时执行策略。通过完整链路控制,可以让镜像从开发到发布和运行都有可审计的信任依据。

镜像供应链安全防护的关键,在于把镜像当成一条完整的生产链路来治理,而不是只关注仓库登录或运行时漏洞。一个典型的攻击路径是:攻击者先在公共基础镜像中植入后门,或者把恶意依赖包上传到开发者常用的包源,然后利用 CI 系统自动构建,最终把带有恶意代码的镜像推送到内部仓库。如果集群在拉取镜像时只校验仓库地址和凭证,而不校验镜像摘要、签名和内容,攻击者就能长时间潜伏在业务容器中。因此,镜像供应链需要同时解决来源可信、构建可信、漏洞可见、运行可拦截这四个问题。

如何构建容器镜像供应链的安全防护体系?

另一个容易被忽视的问题是标签漂移。很多人把 latest 当成稳定的版本号使用,这其实埋下了很大隐患。latest 是可变标签,基础镜像维护者每一次推送都会改变其指向,内部仓库也可能因为误操作覆盖已有标签。要稳定复现构建和回滚,最好在 Dockerfile 中使用摘要 digest 固定基础镜像,并让 CI 记录每次构建使用的完整引用。

一、先拆解镜像供应链的主要风险面

要建立有效防护,首先得清楚风险集中在哪些位置。上游基础镜像是最常见的问题来源。公共镜像仓库中有大量同名镜像,普通开发者很难分辨一个 nginx 镜像是否来自官方,是否被篡改过。即便基础镜像本身可信,它携带的底层操作系统和运行时组件也可能存在已知漏洞。例如一个半年前构建的 Node.js 镜像,可能包含多个高危系统库漏洞,如果继续用标签拉取而不更新摘要,CI 每次构建都会继承这些风险。

构建依赖和工具链同样危险。包管理器从远程源下载依赖时,如果源被投毒或 DNS 被劫持,构建产物就可能被植入恶意代码。Dockerfile 中常见的 curl http://xxx | bash 一类操作,等于把远程脚本当成任意代码执行,脚本内容一旦变化,镜像内容也随之变化,极难审计。CI runner 的缓存目录、共享数据卷、构建参数和构建环境变量,也可能被之前的任务污染。

仓库与分发环节的风险也不能忽略。如果镜像仓库的权限模型过粗,多个团队共用同一个写权限账号,就很容易出现标签被覆盖、镜像被替换的情况。Kubernetes 默认允许节点从多个仓库拉取镜像,如果集群策略未限制仓库白名单,攻击者可能诱导调度器拉取外部恶意镜像。下面这个 Dockerfile 片段演示了如何用摘要固定基础镜像,减少上游标签变化带来的不确定性:

# 使用固定摘要的基础镜像,避免 latest 漂移
FROM alpine:3.18@sha256:e2e16842c9b54c54f3e55556d7b64bcbd6d8b0a3f1e5f5a0e5f8c6f0b2f9b3e5 AS build
RUN apk add --no-cache ca-certificates
COPY . /src
WORKDIR /src
RUN go build -o /app .
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /app /app
USER nonroot:nonroot
ENTRYPOINT ["/app"]

二、用签名和来源证明建立信任链

固定的摘要只能保证拉取的内容不变,但不能回答这个镜像是否由可信的构建系统生成。签名正是用来解决来源认证问题。签名机制会把镜像的 manifest 摘要与某个密钥或身份绑定,验证时可以用公钥或 OIDC 身份确认镜像未被第三方篡改。Docker 早期的 Docker Content Trust 使用 Notary 实现,但部署复杂。现在更常用的是 Cosign,它能直接对 OCI 镜像签名,也支持无密钥签名,把 CI 系统的身份作为信任锚点。

在 CI 中启用签名并不复杂。构建并推送镜像后,使用私钥对镜像签名。私钥必须妥善保管,推荐放在 KMS 或 CI 的加密 secret 中,避免提交到代码仓库。验证端只需持有公钥即可。以下命令展示了 Cosign 生成密钥、签名和验证的基本流程:

cosign generate-key-pair

cosign sign --key cosign.key registry.ipipp.com/team/app:v1.2.0

cosign verify --key cosign.pub registry.ipipp.com/team/app:v1.2.0

除了对镜像整体签名,还可以附加证明文件,例如 SBOM 物料清单、构建来源证明和漏洞扫描结果。Sigstore 提供的无密钥签名会临时生成短期证书,并通过 OIDC 身份认证关联到 GitHub Actions 等工作流。这样就不需要管理长期私钥,降低密钥泄露风险。管理员可以在准入控制中要求镜像必须同时具备有效签名和合规的 SBOM,从策略层面把不可信镜像挡在集群之外。

镜像签名不是一次性的动作,而应该嵌入发布流水线。每次构建完成后自动签名,发布前自动验证,并且把签名记录存档。对于回滚场景,同样要验证旧版本镜像的签名是否仍然有效。否则攻击者可能用一个未签名的旧镜像替换当前版本,绕过新版本的修复。

三、在 CI 中做漏洞扫描和 SBOM 生成

签名的镜像只能说明它没有被篡改,但不能说明它没有漏洞。漏洞扫描需要作为 CI 的必要步骤,在推送镜像到生产仓库前完成。扫描器会解析镜像内部的系统包、语言依赖和二进制文件,与漏洞库比对,输出漏洞等级和修复建议。Trivy、Grype 等工具都能直接扫描 OCI 镜像,速度快,适合放在流水线中。

扫描策略要与业务风险对齐。一般可以设置阻断规则:只要存在严重或高危漏洞就停止发布,中低危漏洞可以记录并安排修复。对于有固定修复版本但暂时无法升级的漏洞,可以结合实际运行环境评估可利用性,而不是只看漏洞数量。扫描命令可以很简单:

trivy image --severity HIGH,CRITICAL --ignore-unfixed registry.ipipp.com/team/app:v1.2.0
syft registry.ipipp.com/team/app:v1.2.0 -o spdx-json --file app-sbom.json
cosign attest --predicate app-sbom.json --key cosign.key registry.ipipp.com/team/app:v1.2.0

SBOM 的作用在漏洞披露后更突出。一旦某个基础库爆发漏洞,团队可以通过 SBOM 快速检索哪些镜像包含了受影响组件,而不必逐个人工排查。把 SBOM 作为签名附件保存,还能保证物料清单本身的完整性。建议在 CI 中同时生成 SPDX 或 CycloneDX 格式的 SBOM,并将结果存储到制品仓库或安全平台,形成可持续追踪的资产台账。

四、镜像最小化与运行时准入控制

镜像越小,携带的组件越少,受攻击面也越小。一个完整的 Ubuntu 镜像可能包含数百个系统包,而 distroless 或 scratch 镜像几乎没有 shell 和包管理器,攻击者入侵后也难以横向扩展。多阶段构建是压缩镜像体积的常用手段:第一阶段用完整工具链编译产物,第二阶段只拷贝运行时需要的二进制和证书。比如下面这个 Go 服务的多阶段构建示例:

FROM golang:1.22 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app .

FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /app /app
USER nonroot:nonroot
ENTRYPOINT ["/app"]

把镜像发布到仓库后,还需要在 Kubernetes 侧执行运行时策略。仅靠开发团队自觉维护签名和扫描是不够的,必须有准入控制器强制校验。Kyverno、OPA 等工具可以在创建 Pod 时检查镜像摘要、签名状态、来源仓库,甚至根据漏洞扫描结果决定是否放行。下面是一个 Kyverno 策略,要求所有 Pod 的镜像必须带有可验证的无密钥签名:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-signed-images
spec:
  validationFailureAction: Enforce
  rules:
  - name: check-image-signature
    match:
      resources:
        kinds:
        - Pod
    verifyImages:
    - imageReferences:
      - "*"
      attestors:
      - count: 1
        entries:
        - keyless:
            subject: "https://ipipp.com/team/app"
            issuer: "https://token.actions.githubusercontent.com"

运行时策略还可以限制镜像仓库白名单,禁止使用 latest 标签,要求镜像 ID 与签名时一致。即便攻击者拿到了 CI 凭证,如果无法通过签名和扫描策略,恶意镜像也无法部署。真正落地时要关注策略的迭代过程:先以审计模式观察一段时间,确认误报范围后逐步切换为强制模式,避免阻断正常发布。

镜像供应链安全防护不是一次性加固,而是一套持续运转的工程体系。上游依赖在变化,漏洞库在更新,CI 环境和密钥也可能发生轮换。团队需要定期复盘策略覆盖率,检查签名密钥和扫描规则是否过期,并把镜像来源、签名记录和 SBOM 都纳入审计范围。只有在构建、签名、扫描和运行四个阶段都形成闭环,才能把镜像供应链的风险降到可控水平。

容器镜像安全软件供应链镜像签名修改时间:2026-10-04 12:10:58

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