4. 镜像签名实战:使用 Cosign 对容器镜像进行签名、签名格式解析、签名与镜像的关联机制
镜像签名是云原生供应链安全的核心防线。本节将围绕 Cosign 工具,从密钥生成、镜像签名、签名格式解析到签名与镜像的关联机制,进行完整的实战讲解与原理剖析。
4.1 环境准备与密钥生成
Cosign 支持多种密钥后端,包括本地密钥对、KMS、Tink 等。本节以本地密钥对为例,演示最通用的操作流程。
前置条件: 确保已安装 Cosign(v2.0+)和 Docker / containerd 环境。推荐使用 Cosign v2.2 以上版本以支持更完善的 OCI 1.1 规范。
4.1.1 生成密钥对
# 生成加密私钥与公钥对
cosign generate-key-pair
# 执行后会在当前目录生成两个文件:
# cosign.key —— 加密私钥(需密码保护)
# cosign.pub —— 公钥(用于验证签名)
| 文件 | 用途 | 安全等级 |
|---|---|---|
| cosign.key | 签名操作,必须妥善保管 | 高(建议硬件安全模块或 KMS) |
| cosign.pub | 验证签名,可公开分发 | 低(仅用于验证) |
安全提醒: 私钥密码建议使用 16 位以上随机字符串,并纳入密钥管理系统的轮换策略。生产环境中避免将私钥存储在代码仓库或 CI 日志中。
4.2 镜像签名实战
使用 Cosign 对容器镜像进行签名,本质是将签名数据以 OCI 制品的形式附加到镜像仓库中。以下为完整签名流程。
4.2.1 签名命令与参数
# 对镜像进行签名(使用本地私钥)
cosign sign --key cosign.key \
registry.example.com/my-app:v1.0.0
# 使用环境变量传递密码(避免交互输入)
export COSIGN_PASSWORD=mySecurePass123
cosign sign --key cosign.key \
registry.example.com/my-app:v1.0.0
4.2.2 签名流程示意图
4.3 签名格式解析
Cosign 生成的签名遵循 OCI 制品规范,以标准 MIME 类型存储在镜像仓库中。签名数据本身是一个 JSON 负载,包含关键元数据。
4.3.1 签名 OCI 制品结构
# 查看签名制品列表
cosign verify --key cosign.pub \
registry.example.com/my-app:v1.0.0
# 输出示例(简化):
# Verification for registry.example.com/my-app:v1.0.0 --
# The following checks were performed on each of these signatures:
# - The cosign claims were validated
# - The signatures were verified against the specified public key
# - Any certificates were verified against the Fulcio roots
4.3.2 签名负载(Payload)结构
Cosign 签名负载是一个 JSON 对象,包含以下核心字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| payloadType | string | 负载类型,固定为 application/vnd.dev.cosign.simplesigning.v1+json |
| payload | base64 | Base64 编码的简单签名 JSON 对象 |
| signatures | array | 签名列表,包含 keyid、sig 等字段 |
4.3.3 简单签名对象(Simple Signing)
{
"critical": {
"identity": {
"docker-reference": "registry.example.com/my-app"
},
"image": {
"docker-manifest-digest": "sha256:abcdef1234567890..."
},
"type": "cosign container image signature"
},
"optional": {
"creator": "cosign 2.2.0",
"timestamp": 1698000000
}
}
关键字段解析:
critical.image.docker-manifest-digest:镜像的 SHA-256 摘要,用于防篡改绑定。critical.identity.docker-reference:镜像仓库地址,防止签名被重放攻击。optional.timestamp:签名时间戳,用于时效性校验。
4.4 签名与镜像的关联机制
Cosign 通过 OCI 引用(Reference)机制将签名与镜像关联。每个签名制品通过镜像摘要(Digest)建立不可篡改的绑定关系。
4.4.1 关联机制原理
4.4.2 关联验证流程
- 提取镜像摘要: 从镜像清单(Manifest)中获取
sha256:...摘要。 - 查找签名制品: 在仓库中查找
sha256-...-sig标签的 OCI 制品。 - 解析签名负载: 读取签名中的
critical.image.docker-manifest-digest字段。 - 摘要比对: 将签名中的摘要与当前镜像摘要进行比对,一致则通过。
- 公钥验证: 使用公钥对签名数据进行 ECDSA 验签。
4.4.3 验证命令实战
# 使用公钥验证签名
cosign verify --key cosign.pub \
registry.example.com/my-app:v1.0.0
# 验证通过时输出:
# Verification OK -- The following checks were performed:
# - The cosign claims were validated
# - The signatures were verified against the specified public key
# 验证失败时输出:
# Error: verifying signature: invalid signature when validating
最佳实践: 在 CI/CD 流水线中,将
cosign verify 作为镜像部署前的强制检查步骤。结合 Kyverno 或 OPA 策略引擎,可以实现自动化的签名验证准入控制。
4.5 签名管理高级操作
4.5.1 多签名与签名追加
# 使用不同密钥追加签名
cosign sign --key cosign-team.key \
registry.example.com/my-app:v1.0.0
cosign sign --key cosign-security.key \
registry.example.com/my-app:v1.0.0
# 验证所有签名
cosign verify --key cosign-team.pub \
--key cosign-security.pub \
registry.example.com/my-app:v1.0.0
4.5.2 签名清理与轮换
| 操作 | 命令 | 说明 |
|---|---|---|
| 列出签名 | cosign tree <image> |
显示镜像的所有关联制品 |
| 删除签名 | cosign clean <image> |
移除指定镜像的所有签名 |
| 密钥轮换 | 生成新密钥 → 重新签名 → 废弃旧公钥 | 建议每 90 天轮换一次 |
注意: 删除签名操作不可逆,建议在删除前使用
cosign tree 确认签名列表,并确保有备份验证策略。
4.6 本章小结
通过本节实战,我们掌握了以下核心能力:
- 使用 Cosign 生成密钥对并对容器镜像进行签名。
- 解析 Cosign 签名格式,理解 Simple Signing 负载结构。
- 理解签名与镜像通过 OCI Digest 建立的不可篡改关联机制。
- 掌握多签名管理、签名验证与清理操作。