(可选)无密钥签名验证

TIP
  • 如果你对无密钥签名验证感兴趣,可以继续阅读以下内容。
  • 本章内容需要能够访问公网。
  • 但如果你已经部署了私有 Rekor 服务,也可以使用这些能力。
NOTE
  • 此方法要求环境可访问 Internet。
  • 如果你已经部署了私有 Rekor 服务,也可以通过调整相关配置来使用这些能力。
  • 关于部署私有 Rekor 服务不在本文档范围内,请参考相关文档。

虽然 ACP (Alauda Container Platform) 目前不提供部署私有 Rekor 实例的能力,但它提供与 Rekor 服务的集成能力。

这里我们以集成公共 Rekor 为例,介绍如何使用这些服务。 如果你已经部署了私有 Rekor 服务,请参考相关文档进行配置。

功能概览

此方法通过透明日志来增强安全性,从而消除密钥管理的需要:

  1. 配置 Tekton Chains 使用无密钥签名。
  2. 使用 buildah Tekton Task 构建镜像。
  3. 配置 Kyverno 规则以验证无密钥签名。
  4. 使用该镜像创建 Pod,以验证无密钥签名。

使用场景

以下场景需要参考本文档中的指导:

  • 在 Kubernetes 集群中为容器镜像实现无密钥签名和验证
  • 强制执行安全策略,在不管理签名密钥的情况下验证镜像签名
  • 在 CI/CD 流水线中设置自动化透明日志验证
  • 通过 Rekor 透明日志确保镜像来源和完整性
  • 通过将镜像签名与公共 Rekor 服务进行比对,实施供应链安全控制

前提条件

  • 已安装 Tekton Pipelines、Tekton Chains 和 Kyverno 的 Kubernetes 集群
  • 已启用镜像推送的 registry
  • 已安装并配置好可访问集群的 kubectl CLI
  • 已安装 cosign CLI 工具
  • 已安装 jq CLI 工具
  • 已安装 curl
  • 已安装 rekor-cli
    • 用于验证和交互存储在 Rekor 透明日志服务器中的证明信息。

流程概览

步骤操作说明
1生成签名密钥使用 cosign 为制品创建密钥对
2设置身份验证配置镜像推送所需的 registry 凭据
3配置 Tekton Chains设置 Chains 使用 OCI 存储并配置签名
4重新运行流水线触发新的流水线运行以生成透明日志条目
5获取 Rekor 日志索引从 PipelineRun 注解中提取 Rekor 日志索引
6验证 Rekor 签名使用 curl 检索并验证 Rekor 签名
7使用 Rekor CLI使用 rekor-cli 工具获取并验证签名
8使用 Kyverno 验证配置带有 Rekor 验证的 Kyverno 策略

分步说明

步骤 1-3:基础设置

这些步骤与 快速开始:已签名 Provenance 指南完全相同。请按照该指南完成以下内容:

TIP
  • 如果你有私有 Rekor 服务,可以将 transparency.url 设置为你的 Rekor 服务器地址。
    • transparency.url: "<https://rekor.sigstore.dev>"

有关该配置的更多细节,请参阅 透明日志

步骤 4:重新运行流水线以生成镜像

TIP
  • 由于我们修改了透明日志配置,因此需要在 已签名 Provenance 中触发一次新的流水线运行。
  • 这将使 Tekton Chains 为新的镜像和 PipelineRun 生成透明日志条目。

步骤 5:获取 rekor 日志索引

从 PipelineRun 的注解中获取 rekor 日志索引。

$ export NAMESPACE=<pipeline-namespace>
$ export PIPELINERUN_NAME=<pipelinerun-name>
$ kubectl get pipelinerun -n $NAMESPACE $PIPELINERUN_NAME -o jsonpath='{.metadata.annotations.chains\.tekton\.dev/transparency}'

https://rekor.sigstore.dev/api/v1/log/entries?logIndex=232330257

步骤 6:通过 curl 获取 rekor 签名

$ curl -s "https://rekor.sigstore.dev/api/v1/log/entries?logIndex=232330257" | jq

如果你需要查看 rekor 签名的内容,可以执行以下命令:

$ curl -s "https://rekor.sigstore.dev/api/v1/log/entries?logIndex=232330257" | jq -r '.[keys[0]].attestation.data | @base64d' | jq .

{
  "_type": "https://in-toto.io/Statement/v0.1",
  "subject": null,
  "predicateType": "https://slsa.dev/provenance/v0.2",
  "predicate": {
    "buildType": "tekton.dev/v1beta1/PipelineRun",
    "builder": {
      "id": "https://alauda.io/builders/tekton/v1"
    },
    "materials": [
      {
        "digest": {
          "sha256": "8d5ea9ecd9b531e798fecd87ca3b64ee1c95e4f2621d09e893c58ed593bfd4c4"
        },
        "uri": "oci://<registry>/devops/tektoncd/hub/buildah"
      }
    ],
    "metadata": {
      "buildFinishedOn": "2025-06-08T03:11:52Z",
      "buildStartedOn": "2025-06-08T03:10:33Z"
    }
  }
}

此内容与镜像中的 attestation 相同,可用于验证镜像内容的真实性和完整性。 可以直接从 Rekor 检索 attestation 信息,而无需使用镜像 registry 的凭据,这使得验证过程更加便捷且易于访问。

步骤 7:通过 rekor-cli 获取 rekor 签名

通过日志索引获取签名

# the log index is same as the one in the annotations of the PipelineRun
$ rekor-cli get --log-index 232330257 --format json | jq -r .Attestation | jq .

通过镜像 digest 获取签名

# get the uuid by image digest
$ rekor-cli search --sha da4885861a8304abad71fcdd569c92daf33422073d1102013a1fed615dfb285a

Found matching entries (listed by UUID):
108e9186e8c5677a1364e68001a916d3a7316bc2580bd6b5fbbce39a9c62f13282d3e974a6b434ab

# get the signature by uuid
$ rekor-cli get --uuid 108e9186e8c5677a1364e68001a916d3a7316bc2580bd6b5fbbce39a9c62f13282d3e974a6b434ab --format json | jq -r .Attestation | jq .

步骤 8:在 Kyverno 中验证 rekor

修改 ClusterPolicykeys 部分以添加 rekor 验证。

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
spec:
  rules:
    - name: check-image
      verifyImages:
        - attestors:
            - count: 1
              entries:
                - keys:
                    publicKeys: |- # <- The public key of the signer
                      -----BEGIN PUBLIC KEY-----
                      MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFZNGfYwn7+b4uSdEYLKjxWi3xtP3
                      UkR8hQvGrG25r0Ikoq0hI3/tr0m7ecvfM75TKh5jGAlLKSZUJpmCGaTToQ==
                      -----END PUBLIC KEY-----

                    rekor:
                      ignoreTlog: false
                      # url: <https://rekor.sigstore.dev>
                      # # get the public key from the rekor server
                      # # curl <https://rekor.sigstore.dev>/api/v1/log/publicKey
                      # pubkey: |-
                      #   -----BEGIN PUBLIC KEY-----
                      #   MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2G2Y+2tabdTV5BcGiBIx0a9fAFwr
                      #   kBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw==
                      #   -----END PUBLIC KEY-----
YAML 字段说明
  • rekor:rekor 验证配置。
    • ignoreTlog:是否忽略透明日志。
      • 如果为 false,将验证 rekor 服务器。
    • url:rekor 服务器的 URL。
      • 如果未设置,将使用默认 rekor 服务器 https://rekor.sigstore.dev
    • pubkey:签名者的公钥。
      • 如果未设置,将从 rekor 服务器获取公钥。
      • 如果 rekor 服务器是私有的,则需要从 rekor 服务器获取公钥。
        • curl <https://rekor.sigstore.dev>/api/v1/log/publicKey

如果你的镜像未签名,Pod 将被阻止。

Error from server: admission webhook "mutate.kyverno.svc-fail" denied the request:

resource Pod/policy/sign was blocked due to the following policies

only-cosign-image-deploy:
  check-image: 'failed to verify image <registry>/test/chains/demo-1:latest:
    .attestors[0].entries[0].keys: no matching signatures: searching log query: Post
    "http:///api/v1/log/entries/retrieve": POST http:///api/v1/log/entries/retrieve
    giving up after 4 attempt(s): Post "http:///api/v1/log/entries/retrieve": http:
    no Host in request URL'

预期结果

完成本指南后:

  • 你已经完成了一个可正常工作的 Tekton Chains 无密钥签名与 Rekor 集成环境
  • 你的容器镜像会自动签名,且其签名会存储在 Rekor 透明日志中
  • 无需管理签名密钥即可验证镜像签名
  • 只有在 Rekor 中具有有效签名的镜像才能在指定命名空间中部署
  • 你已经通过 Rekor 验证镜像签名,实现了无密钥供应链安全控制

本指南为在 CI/CD 流水线中实现无密钥签名和验证提供了基础。在生产环境中,你应当:

  1. 配置适当的命名空间隔离和访问控制
  2. 为签名验证失败设置监控和告警
  3. 定期审查和更新安全策略
  4. 考虑部署私有 Rekor 实例以增强安全性

参考资料