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 签名与验证流程总览
下图展示了从密钥生成到签名验证的完整数据流,以及各组件之间的依赖关系:
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 将签名层与镜像一起复制到本地仓库,减少跨仓库拉取开销。