4. 镜像签名与验证:Sigstore/Cosign 原理、密钥管理、签名策略、验证流程

镜像签名与验证是容器供应链安全的核心防线。Sigstore 项目及其核心工具 Cosign 为 Kubernetes 生态提供了免密钥基础设施(PKI)的签名方案,使得镜像的发布者身份验证和完整性校验变得可审计、可自动化。本节将深入剖析 Sigstore/Cosign 的工作原理、密钥生命周期管理、签名策略设计以及准入控制中的验证流程。

4.1 Sigstore 体系与 Cosign 核心原理

Sigstore 是一个用于代码和软件工件的签名服务,它通过三个核心组件解决了传统签名方案中密钥分发和证书管理的痛点:

  • Fulcio(根证书颁发机构):基于 OIDC(OpenID Connect)身份签发短期证书,无需用户自行管理长期私钥。
  • Rekor(透明日志):不可篡改的签名事件账本,提供全局可审计性,任何签名操作都会被永久记录。
  • Cosign(签名工具):负责对容器镜像进行签名、验证和存储签名元数据。

Cosign 将签名信息存储在 OCI 制品仓库中(通常作为镜像的标签或附加层),而不是依赖独立的签名服务器。这种设计使得签名与镜像天然绑定,便于在 Kubernetes 准入控制阶段直接拉取验证。

关键优势: Sigstore 的“无密钥”模式(Keyless Signing)允许开发者使用 GitHub/GitLab/Google 等 OIDC 身份进行签名,私钥仅在签名会话期间存在,极大降低了密钥泄露风险。
Sigstore 组件架构与 Keyless 签名流程 开发者 / CI OIDC Provider Fulcio CA Rekor 透明日志 OCI 仓库 镜像 + 签名 1. 身份认证 2. 请求证书 3. 签发短期证书 4. 签名并推送镜像 5. 记录签名事件 说明: Keyless 模式下,私钥仅在内存中短暂存在,证书由 Fulcio 基于 OIDC 令牌签发,签名元数据推送至 Rekor 实现全局审计。

4.2 密钥管理策略

Cosign 支持三种密钥管理模式,每种模式适用于不同的安全等级和运维场景:

管理模式 密钥生命周期 适用场景 安全等级
Keyless(无密钥) 会话级私钥,签名后立即销毁 CI/CD 流水线、开发者个人签名 高(依赖 OIDC 和 Rekor)
密钥对(本地/云 KMS) 长期私钥,需定期轮换 企业级发布、离线环境 中高(取决于 KMS 保护)
硬件安全模块(HSM) 私钥永不出模块,物理隔离 金融、政府、合规要求严格场景 极高
密钥轮换最佳实践: 如果使用密钥对模式,建议每 90 天轮换一次私钥,并使用 cosign rotate 命令更新仓库中的公钥记录。对于 Keyless 模式,由于证书有效期通常为 10 分钟,无需手动轮换。

4.3 签名策略设计

签名策略定义了“谁可以签名”以及“签名必须满足哪些条件”。在 Kubernetes 准入控制中,策略通常以 ClusterImagePolicy(CIP)资源的形式表达。以下是常见的策略维度:

  • 身份约束:只允许特定 OIDC 发行者(如 https://.actions.githubusercontent.com)或特定邮箱域名的身份进行签名。
  • 仓库约束:仅对指定仓库前缀(如 registry.example.com/production/*)的镜像要求签名。
  • 时间约束:签名证书必须在有效期内,且签发时间不能早于某个基准时间(防止重放攻击)。
  • 透明日志约束:签名事件必须已写入 Rekor 透明日志,且日志条目可验证。
策略示例(ClusterImagePolicy YAML 片段):
apiVersion: cosigned.sigstore.dev/v1beta1
kind: ClusterImagePolicy
metadata:
  name: require-signed-prod-images
spec:
  images:
    - glob: "registry.example.com/production/*"
  authorities:
    - keyless:
        identities:
          - issuer: "https://.actions.githubusercontent.com"
            subjectRegExp: ".*@example\\.com"
      ctlog:
        - url: "https://rekor.example.com"

4.4 验证流程与准入控制集成

在 Kubernetes 中,镜像签名验证通常通过 动态准入控制 Webhook 实现。当 Pod 创建请求到达 API Server 时,Webhook 会拦截请求并执行以下验证流程:

  1. 提取镜像引用:从 Pod 规约中解析出所有容器镜像地址。
  2. 匹配策略:根据 ClusterImagePolicy 判断该镜像是否需要验证签名。
  3. 拉取签名:从 OCI 仓库中拉取与镜像关联的签名对象(.sig 标签)。
  4. 验证签名:使用策略中指定的公钥或 Keyless 方式验证签名有效性。
  5. 检查透明日志:查询 Rekor 确认签名事件已被记录且未被篡改。
  6. 返回准入决策:验证通过则允许创建,否则拒绝并返回错误信息。
K8s 准入控制中 Cosign 签名验证流程 API Server 准入 Webhook OCI 仓库 Rekor 日志 策略引擎 允许 / 拒绝 1. Pod 创建请求 2. 拉取签名 3. 查询日志 4. 验证结果 5. 准入决策 6. 返回 API Server

4.5 验证失败处理与审计

当签名验证失败时,Webhook 应返回清晰的拒绝原因,并记录审计日志。常见的失败场景包括:

失败场景 典型错误信息 推荐处理方式
镜像未签名 no signature found for image 拒绝创建,通知开发团队补签
签名者身份不匹配 identity not allowed by policy 拒绝创建,检查 CI 身份配置
证书已过期 certificate expired 拒绝创建,要求重新签名
透明日志验证失败 rekor entry not found or invalid 拒绝创建,检查 Rekor 连通性
审计建议: 将所有验证结果(包括成功和失败)以结构化日志格式输出到集中式日志平台(如 Elasticsearch/Loki),并设置告警规则:当同一镜像在短时间内被多次拒绝时,自动触发安全事件响应流程。