4. Cosign 基础操作:签名、验证与存储解析

Cosign 是 Sigstore 项目原生的容器镜像签名工具,支持对 OCI 制品进行密钥对签名、密钥less 签名(Keyless Signing)以及验证。本章将围绕 Cosign 的核心操作展开,涵盖签名生成、验证流程、签名信息查看以及签名格式与存储位置的底层原理。

前置条件: 已安装 Cosign 二进制(≥ v2.0),并拥有一个可访问的容器镜像仓库(如 Docker Hub、Harbor 或 GHCR)。本示例使用镜像 registry.example.com/app:v1 作为操作对象。

4.1 使用 Cosign 对容器镜像签名

Cosign 支持两种签名模式:密钥对签名(使用本地生成的私钥/公钥)和 Keyless 签名(基于 OIDC 身份与 Fulcio 证书)。以下分别演示两种方式。

4.1.1 密钥对签名

  1. 生成密钥对:
    cosign generate-key-pair
    执行后会在当前目录生成 cosign.key(私钥)和 cosign.pub(公钥)。私钥需设置密码保护。
  2. 对镜像签名:
    cosign sign --key cosign.key registry.example.com/app:v1
    输入私钥密码后,Cosign 会计算镜像摘要,生成签名负载并将其推送到镜像仓库。

4.1.2 Keyless 签名(无密钥模式)

  1. 直接执行签名命令:
    cosign sign registry.example.com/app:v1
    系统会自动打开浏览器进行 OIDC 身份认证(支持 GitHub、Google、Microsoft 等)。
  2. 认证完成后,Cosign 会向 Fulcio 申请短期证书,并用该证书对镜像签名,同时将签名记录上传至 Rekor 透明日志。
推荐实践: 在 CI/CD 流水线中优先使用 Keyless 签名,避免私钥管理负担;在离线或内网环境使用密钥对签名。

4.2 验证签名

验证签名是确保镜像来源可信的关键步骤。Cosign 提供 verify 命令,支持基于公钥或 Keyless 方式的验证。

4.2.1 基于公钥验证

cosign verify --key cosign.pub registry.example.com/app:v1

输出示例:

Verification for registry.example.com/app:v1 --
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":"registry.example.com/app:v1"},"image":{"docker-manifest-digest":"sha256:abc123..."},"type":"cosign container image signature"},"optional":null}]

4.2.2 Keyless 验证

cosign verify registry.example.com/app:v1

Cosign 会自动从 Rekor 日志中检索签名证书,并验证证书链是否由 Fulcio 签发,同时检查镜像摘要是否匹配。

注意: Keyless 验证要求网络能够访问 Rekor 和 Fulcio 服务。若在离线环境,需提前缓存信任根(trust root)。

4.3 查看签名信息

使用 cosign verify 输出的 JSON 格式签名信息包含以下关键字段:

字段 说明 示例值
critical.identity.docker-reference 被签名镜像的完整引用 registry.example.com/app:v1
critical.image.docker-manifest-digest 镜像清单的 SHA256 摘要 sha256:abc123...
critical.type 签名类型标识 cosign container image signature
optional 可选的附加元数据(如 CI 流水线 ID) {"build":"jenkins-123"}

若要查看更底层的签名原始数据,可使用 cosign verify-attestation 或直接通过 OCI 仓库 API 拉取签名层。

4.4 签名格式与存储位置

Cosign 将签名作为 OCI 制品存储在镜像仓库中,遵循 cosign 签名规范。签名并不直接修改原始镜像层,而是以独立的标签或引用形式存在。

4.4.1 签名存储结构

当对 registry.example.com/app:v1 签名后,仓库中会新增以下内容:

  • 签名标签: registry.example.com/app:sha256-<digest>.sig — 存储签名负载(Base64 编码的签名值)。
  • 证书标签(Keyless 模式): registry.example.com/app:sha256-<digest>.cert — 存储 Fulcio 签发的短期证书。
  • 可选的附加信息: 如 .att 标签用于存储 SBOM 或 attestation 断言。

4.4.2 签名格式解析

签名负载本身是一个 JSON 结构,包含以下核心部分:

{
  "payloadType": "application/vnd.dev.cosign.simplesigning.v1+json",
  "payload": "eyJjcml0aWNhbCI6eyJpZGVudGl0eSI6eyJkb2NrZXItcmVmZXJlbmNlIjoicmVnaXN0cnkuZXhhbXBsZS5jb20vYXBwOnYxIn0sImltYWdlIjp7ImRvY2tlci1tYW5pZmVzdC1kaWdlc3QiOiJzaGEyNTY6YWJjMTIzLi4uIn0sInR5cGUiOiJjb3NpZ24gY29udGFpbmVyIGltYWdlIHNpZ25hdHVyZSJ9LCJvcHRpb25hbCI6bnVsbH0=",
  "signatures": [
    {
      "keyid": "",
      "sig": "MEUCIQ..."
    }
  ]
}
  • payloadType:固定为 application/vnd.dev.cosign.simplesigning.v1+json。
  • payload:Base64 编码的 简单签名负载(Simple Signing Payload),包含镜像引用和摘要。
  • signatures:签名值数组,每个元素包含 keyid 和 sig(Base64 编码的签名结果)。

4.4.3 存储位置示意图

下图展示了 Cosign 签名在 OCI 仓库中的存储布局:

Cosign 签名在 OCI 仓库中的存储布局 Cosign 签名在 OCI 仓库中的存储布局 OCI 镜像仓库:registry.example.com/app 镜像标签 :v1 签名标签 :sha256-xxx.sig 证书标签 :sha256-xxx.cert 签名标签内容 • payloadType: cosign v1 • payload: Base64 编码的 简单签名负载 • signatures: 签名值数组 证书标签内容 • PEM 编码的 X.509 证书 • 由 Fulcio 签发 • 包含 OIDC 身份信息 • 有效期通常为 10 分钟

4.5 操作流程总结

以下表格对比了密钥对签名与 Keyless 签名的核心差异:

维度 密钥对签名 Keyless 签名
身份绑定 基于本地公钥指纹 基于 OIDC 身份(邮箱、用户名)
密钥管理 需安全存储私钥 无需管理长期密钥
可审计性 依赖公钥分发 依赖 Rekor 透明日志
离线支持 完全支持 需预缓存信任根
推荐场景 内网、离线环境 CI/CD、公有云环境