3. 镜像签名基础:Cosign的工作原理、生成密钥对、对容器镜像进行签名
在Serverless流水线中实施镜像签名验证,首先需要理解签名工具的核心机制。Cosign是Sigstore项目下最成熟的容器镜像签名工具,它利用公钥基础设施(PKI)或更现代的密钥less模式,为OCI制品提供加密签名。本章将深入Cosign的工作原理,并演示从密钥生成到镜像签名的完整操作流程。
3.1 Cosign签名架构与工作流程
Cosign的签名模型基于“签名-验证”分离原则:签名者使用私钥对镜像摘要(Digest)进行签名,验证者使用对应的公钥验证签名的合法性与完整性。签名本身不修改原始镜像层,而是作为独立的OCI制品(通常是.sig或.att标签)存储在镜像仓库中。
核心设计理念:签名绑定的是镜像的加密摘要(SHA256),而非镜像标签(Tag)。这防止了标签被篡改后签名仍然有效的风险。
3.2 生成密钥对:Cosign的密钥管理
Cosign支持两种密钥生成模式:本地密钥对和密钥less模式(Keyless)。在Serverless流水线中,推荐使用密钥less模式结合OIDC身份认证,但理解本地密钥对是掌握签名基础的前提。
3.2.1 本地密钥对生成
使用cosign generate-key-pair命令生成一对加密密钥:
# 生成密钥对(默认使用ECDSA-P256算法)
cosign generate-key-pair
# 输出文件:
# cosign.key —— 私钥(必须安全保管,建议使用KMS或密钥管理服务)
# cosign.pub —— 公钥(可公开,用于验证签名)
# 指定输出路径
cosign generate-key-pair --output-key-prefix myapp
# 生成 myapp.key 和 myapp.pub
安全警告:私钥(
.key文件)是签名的唯一凭证。在CI/CD流水线中,不要将私钥明文存储在代码仓库或环境变量中。应使用密钥管理服务(如AWS KMS、Azure Key Vault、HashiCorp Vault)或Cosign的KMS集成。
3.2.2 密钥less模式(推荐用于Serverless)
密钥less模式利用Sigstore的Fulcio证书颁发机构和Rekor透明日志,无需管理本地密钥对:
# 密钥less签名(自动获取临时证书)
cosign sign --keyless <镜像引用>
# 密钥less验证(自动查询Rekor日志)
cosign verify --keyless <镜像引用>
| 特性 | 本地密钥对 | 密钥less模式 |
|---|---|---|
| 密钥管理 | 需要自行保管私钥 | 无需管理密钥,临时证书自动签发 |
| 身份绑定 | 绑定公钥指纹 | 绑定OIDC身份(如GitHub Actions、GitLab CI) |
| 审计追溯 | 无内置透明日志 | 签名记录写入Rekor透明日志,可公开审计 |
| 适用场景 | 私有仓库、离线环境 | 公有云CI/CD、Serverless流水线 |
3.3 对容器镜像进行签名
签名操作的核心是计算镜像的加密摘要,并使用私钥对该摘要进行签名。Cosign自动处理摘要提取、签名生成和制品推送。
3.3.1 使用本地密钥签名
# 1. 构建或拉取镜像
docker build -t registry.example.com/myapp:v1 .
docker push registry.example.com/myapp:v1
# 2. 使用私钥签名
cosign sign --key cosign.key registry.example.com/myapp:v1
# 3. 验证签名
cosign verify --key cosign.pub registry.example.com/myapp:v1
# 输出示例:
# Verification for registry.example.com/myapp:v1 --
# The following checks were performed on each of these signatures:
# - The cosign claims were validated
# - The signatures were verified against the specified public key
3.3.2 签名后的仓库结构
签名完成后,镜像仓库中会新增一个与镜像摘要关联的签名制品:
# 查看镜像标签
skopeo list-tags docker://registry.example.com/myapp
# 输出:
# {
# "Repository": "registry.example.com/myapp",
# "Tags": [
# "v1",
# "v1.sig" ← Cosign自动生成的签名标签
# ]
# }
# 签名标签的命名规则:
# <原始标签>.sig —— 签名制品
# <原始标签>.att —— 附加声明(in-toto attestation)
3.3.3 签名验证的详细过程
当验证者执行cosign verify时,Cosign执行以下步骤:
- 拉取签名制品:从镜像仓库获取与镜像标签关联的
.sig制品。 - 计算镜像摘要:对当前镜像内容重新计算SHA256摘要。
- 解密签名:使用公钥解密签名,得到原始摘要的哈希值。
- 摘要比对:比较解密后的哈希值与重新计算的摘要是否一致。
- 验证声明:检查签名中的声明(如签名时间、身份信息)是否有效。
3.4 多平台镜像签名注意事项
对于多架构镜像(manifest list),Cosign要求对每个平台特定的镜像摘要分别签名,或对整个manifest list签名:
# 对多平台镜像签名(自动处理所有子镜像)
cosign sign --key cosign.key registry.example.com/myapp:multi-arch
# 验证多平台镜像
cosign verify --key cosign.pub registry.example.com/myapp:multi-arch
# 查看签名是否覆盖所有平台
cosign verify-attestation --key cosign.pub registry.example.com/myapp:multi-arch
最佳实践:在Serverless流水线中,建议在镜像构建完成后立即执行签名操作,并将签名步骤作为流水线的强制门禁。结合OPA策略,可以在部署前验证签名是否满足组织定义的策略规则。
3.5 本章小结
- Cosign签名模型:基于镜像摘要的加密签名,不修改原始镜像层,签名作为独立OCI制品存储。
- 密钥管理:本地密钥对适用于私有环境;密钥less模式利用OIDC和透明日志,更适合Serverless流水线。
- 签名操作:
cosign sign自动完成摘要计算、签名生成和制品推送;cosign verify执行四步验证流程。 - 多平台支持:Cosign原生支持manifest list签名,确保多架构镜像的完整性。