3. Cosign 基础回顾:密钥生成、镜像签名、签名验证流程

Cosign 是 Sigstore 项目下的核心工具,专为容器镜像和软件制品提供无密钥(Keyless)或密钥对(Key-Pair)签名能力。在生产环境中,Cosign 与 OCI 分发规范深度集成,签名数据作为独立层存储在镜像仓库中,无需额外存储后端。本节将系统回顾 Cosign 的三种基础操作:密钥生成、镜像签名与签名验证。

3.1 密钥生成:创建签名身份

Cosign 支持两种身份模式:密钥对模式(适用于 CI/CD 自动化)和 Keyless 模式(适用于临时身份,依赖 OIDC 和 Fulcio CA)。在供应链冷启动场景中,密钥对模式更常见,因为其私钥可安全注入到受控的构建环境。

模式 命令 产物 适用场景
密钥对 cosign generate-key-pair cosign.key(私钥)、cosign.pub(公钥) CI/CD 流水线、内部仓库
Keyless cosign sign(无密钥参数) 临时证书(Fulcio 签发) 开发者本地、开源项目
KMS 托管 cosign generate-key-pair --kms gcpkms://... KMS 引用 URI 企业合规、密钥轮转
生产建议:私钥 cosign.key 必须使用密码加密存储,并集成到密钥管理服务(KMS)或硬件安全模块(HSM)中。切勿将私钥明文提交到代码仓库或镜像层中。
# 生成加密私钥与公钥对
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

# 查看公钥内容(用于后续验证)
cat cosign.pub

3.2 镜像签名:将签名附加到 OCI 制品

Cosign 签名操作的核心原理是:计算镜像清单(Manifest)的摘要(Digest),使用私钥对该摘要进行签名,然后将签名数据作为 OCI 制品的一个独立层(Layer)推送到同一镜像仓库。签名层通过 sha256- 前缀的注解与原始镜像关联。

关键概念:签名不修改原始镜像层,而是作为“附件”存储在仓库中。这使得签名可以独立更新、轮转或撤销,而不影响镜像本身。
# 使用私钥对镜像进行签名
cosign sign --key cosign.key registry.example.com/app:v1

# 使用 Keyless 模式(自动获取 OIDC 令牌)
cosign sign registry.example.com/app:v1

# 使用 KMS 托管的密钥
cosign sign --kms gcpkms://projects/my-project/locations/global/keyRings/my-ring/cryptoKeys/my-key registry.example.com/app:v1

签名成功后,可以使用 cosign tree 命令查看镜像的签名结构:

cosign tree registry.example.com/app:v1

# 输出示例:
# 📦 Supply Chain Security Related Artifacts for registry.example.com/app:v1
# └── 💾 Signature for registry.example.com/app:v1
#     └── 🖋️  registry.example.com/app@sha256:signature-digest
# └── 📄 SBOM for registry.example.com/app:v1
#     └── 🖋️  registry.example.com/app@sha256:sbom-digest

3.3 签名验证:确保镜像完整性与来源可信

验证是供应链安全的核心防线。Cosign 验证流程会检查:签名是否由对应私钥生成、镜像内容是否被篡改、签名是否在有效期内(Keyless 模式)。验证命令需要提供公钥或信任根。

# 使用公钥验证镜像签名
cosign verify --key cosign.pub registry.example.com/app:v1

# 使用 Keyless 验证(自动查询 Rekor 透明度日志)
cosign verify registry.example.com/app:v1

# 验证并输出详细 JSON 格式
cosign verify --key cosign.pub --output json registry.example.com/app:v1 | jq .
安全警告:仅依赖 cosign verify 返回成功是不够的。必须验证公钥的信任链:公钥是否来自受信任的发布者?是否已过期或被吊销?在生产环境中,建议使用 cosign verify-attestation 结合策略引擎(如 Kyverno)进行更细粒度的准入控制。

3.4 签名与验证流程总览

下图展示了从密钥生成到签名验证的完整数据流,以及各组件之间的依赖关系:

Cosign 签名与验证流程 1. 密钥生成 cosign.key cosign.pub 2. 镜像签名 镜像摘要 签名层 3. 签名验证 通过 拒绝 说明: 签名层与原始镜像分离存储,验证时 Cosign 从仓库拉取签名层,使用公钥解密签名并与镜像摘要比对。

3.5 常见验证失败原因与排查

在实际运维中,签名验证失败是最常见的供应链中断事件。下表列出了典型失败场景及对应的排查方向:

失败现象 可能原因 排查命令 / 方法
verification failed: no matching signatures 镜像未签名,或签名层未推送成功 cosign tree 检查签名层是否存在
public key verification failed 公钥不匹配,或镜像被重新推送(Digest 改变) 比对 cosign.pub 与签名时使用的公钥指纹
certificate expired Keyless 模式证书过期(默认 10 分钟) 重新执行 cosign sign 获取新证书
error fetching Rekor entry 网络不通或 Rekor 实例不可达 检查 REKOR_URL 环境变量,或使用 --insecure-ignore-rekor 临时绕过(仅测试)
冷启动优化提示:在离线或冷启动环境中,建议预先将公钥和信任根(Trust Root)分发到所有节点,避免验证时因网络延迟导致超时。同时,使用 cosign copy 将签名层与镜像一起复制到本地仓库,减少跨仓库拉取开销。