4. 容器镜像签名:使用 Cosign 对 Docker 镜像进行签名、验证签名完整性
容器镜像签名是软件供应链安全的关键环节。本章将深入讲解如何使用 Cosign 对 Docker 镜像进行签名,并验证签名的完整性,确保镜像从构建到部署的整个链路中未被篡改。
4.1 签名与验证的核心流程
Cosign 的签名机制基于公钥基础设施(PKI)或密钥对。签名过程将镜像的摘要(Digest)与签名者的身份绑定,生成一个不可篡改的签名对象。验证过程则通过公钥或身份信息确认签名的有效性。
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 流水线的构建阶段,将验证操作集成到部署阶段的准入控制器中。这样可以在镜像构建完成后立即签名,并在部署前强制验证,形成完整的签名链路闭环。