4. 容器镜像签名:使用 Cosign 对 Docker 镜像进行签名、验证签名完整性

容器镜像签名是软件供应链安全的关键环节。本章将深入讲解如何使用 Cosign 对 Docker 镜像进行签名,并验证签名的完整性,确保镜像从构建到部署的整个链路中未被篡改。

4.1 签名与验证的核心流程

Cosign 的签名机制基于公钥基础设施(PKI)或密钥对。签名过程将镜像的摘要(Digest)与签名者的身份绑定,生成一个不可篡改的签名对象。验证过程则通过公钥或身份信息确认签名的有效性。

Cosign 镜像签名与验证流程 签名流程 1. 构建 Docker 镜像 2. 生成密钥对(公钥/私钥) 3. 使用私钥签名镜像 4. 签名推送至镜像仓库 验证流程 1. 拉取待验证镜像 2. 获取签名者公钥 3. 使用公钥验证签名 4. 输出验证结果(通过/失败) 镜像与签名

4.2 环境准备与密钥生成

在执行签名操作前,需要确保 Cosign 已正确安装,并生成用于签名的密钥对。

4.2.1 安装 Cosign

Cosign 支持多种安装方式,推荐使用官方发布的二进制文件或包管理器。

平台 安装命令
Linux (amd64) curl -O -L https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64 && chmod +x cosign-linux-amd64 && sudo mv cosign-linux-amd64 /usr/local/bin/cosign
macOS (Homebrew) brew install cosign
Windows (Scoop) scoop install cosign

4.2.2 生成密钥对

Cosign 支持多种密钥类型,包括标准 RSA 密钥对和更安全的 ECDSA 密钥对。以下命令生成一个 ECDSA P-256 密钥对:

# 生成私钥(cosign.key)和公钥(cosign.pub)
cosign generate-key-pair

# 系统会提示输入私钥密码,请妥善保管
Enter password for private key: 
Enter password for private key again: 
Private key written to cosign.key
Public key written to cosign.pub
安全提示:私钥(cosign.key)是签名的核心凭证,必须严格保护。建议使用硬件安全模块(HSM)或密钥管理服务(KMS)存储私钥,避免明文存储在磁盘上。

4.3 对 Docker 镜像进行签名

签名操作将镜像的摘要与签名者的身份绑定。Cosign 支持对镜像标签(Tag)和镜像摘要(Digest)进行签名。

4.3.1 签名镜像标签

使用私钥对指定镜像标签进行签名:

# 使用私钥签名镜像
cosign sign --key cosign.key your-registry/your-image:latest

# 示例输出
Pushing signature to: your-registry/your-image:sha256-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.sig

签名成功后,Cosign 会将签名对象(.sig)推送到镜像仓库中,与原始镜像关联存储。

4.3.2 签名镜像摘要

对镜像摘要进行签名可以提供更精确的不可变引用:

# 获取镜像摘要
cosign digest your-registry/your-image:latest

# 对摘要进行签名
cosign sign --key cosign.key your-registry/your-image@sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

4.4 验证签名完整性

验证签名是确保镜像来源可信的关键步骤。Cosign 支持多种验证方式,包括使用公钥、KMS 或 Sigstore 的 Fulcio 证书。

4.4.1 使用公钥验证

最基本的验证方式是通过签名者的公钥:

# 使用公钥验证镜像签名
cosign verify --key cosign.pub your-registry/your-image:latest

# 验证成功输出示例
Verification for your-registry/your-image:latest --
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - The signatures were verified using the specified public key
  - Any certificates were verified against the Fulcio roots.
[
  {
    "critical": {
      "identity": {
        "docker-reference": "your-registry/your-image"
      },
      "image": {
        "docker-manifest-digest": "sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      },
      "type": "cosign container image signature"
    },
    "optional": null
  }
]

4.4.2 验证失败场景

当镜像被篡改或签名不匹配时,验证会失败并返回错误信息:

# 验证失败示例
cosign verify --key cosign.pub your-registry/your-image:latest
Error: verifying image: invalid signature when validating ASN.1 encoded signature
重要:验证失败并不一定意味着镜像被恶意篡改,也可能是密钥轮换、签名过期或镜像标签被重新指向导致的。建议在 CI/CD 流水线中集成验证步骤,并配置明确的失败处理策略。

4.5 签名验证的常见参数对比

参数 说明 示例值
--key 指定私钥或公钥文件路径 cosign.key 或 cosign.pub
--allow-insecure-registry 允许对非 TLS 仓库进行操作(仅测试环境使用) 无值
--tlog-upload 是否将签名记录上传至 Rekor 透明度日志(默认 true) false
--attachment-tag-prefix 自定义签名附件的标签前缀 cosign-
--payload-path 指定签名载荷的输出路径 /tmp/payload.json

4.6 签名验证的最佳实践

  • 密钥管理:私钥应存储在安全的密钥管理服务(如 AWS KMS、Azure Key Vault、GCP KMS)或硬件安全模块中,避免直接暴露在构建环境中。
  • 自动化验证:在 Kubernetes 的准入控制器(如 Kyverno、OPA Gatekeeper)中集成 Cosign 验证,确保只有经过签名的镜像才能被部署。
  • 透明度日志:默认情况下,Cosign 会将签名记录上传至 Rekor 透明度日志,提供公开可审计的签名记录。在私有环境中可以禁用此功能(--tlog-upload=false)。
  • 多签名支持:一个镜像可以被多个签名者签名,验证时只需任意一个有效签名即可通过。
  • 定期轮换密钥:建议定期轮换签名密钥,并更新验证方的公钥列表。
实战要点:在生产环境中,建议将签名操作集成到 CI/CD 流水线的构建阶段,将验证操作集成到部署阶段的准入控制器中。这样可以在镜像构建完成后立即签名,并在部署前强制验证,形成完整的签名链路闭环。