Image Signature Verification

在 Tekton Chains 中,可以自动为构建的镜像生成签名,并将签名记录在 SLSA Provenance 中。

目录

功能概述

该方法使用 Tekton Chains 自动为构建的镜像生成签名,然后使用 cosign 或 Kyverno 验证签名:

  1. 配置 Tekton Chains 自动为构建的镜像生成签名。
  2. 使用 buildah Tekton Task 构建镜像。
  3. (可选)使用 cosign CLI 验证签名。
  4. 配置 Kyverno 规则,仅允许已签名的镜像。
  5. 使用该镜像创建 Pod 以验证签名。
TIP

相比于 Quick Start: Signed Provenance,此方法仅增加了更多的验证步骤。

使用场景

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

  • 在 Kubernetes 集群中使用 Kyverno 实现镜像签名验证
  • 强制安全策略,仅允许已签名的镜像部署
  • 在 CI/CD 流水线中设置自动化镜像签名验证
  • 确保生产环境中镜像的完整性和真实性
  • 为容器镜像实施供应链安全控制

前提条件

  • 已安装 Tekton Pipelines、Tekton Chains 和 Kyverno 的 Kubernetes 集群
  • 支持镜像推送的镜像仓库
  • 已安装并配置好访问集群的 kubectl CLI
  • 已安装 cosign CLI 工具
  • 已安装 jq CLI 工具

流程概览

步骤操作说明
1生成签名密钥使用 cosign 创建用于签名工件的密钥对
2设置认证配置镜像推送的仓库凭证
3配置 Tekton Chains设置 Chains 使用 OCI 存储并配置签名
4创建示例流水线创建包含必要任务和工作空间的流水线定义
5运行示例流水线创建并运行配置正确的 PipelineRun
6等待签名等待 PipelineRun 被 Chains 签名
7获取镜像信息从 PipelineRun 中提取镜像 URI 和摘要
8使用 Kyverno 验证签名配置并使用 Kyverno 策略验证镜像签名
9清理资源删除测试 Pod 和策略

逐步操作说明

步骤 1-7:基础设置

这些步骤与 Quick Start: Signed Provenance 指南完全相同。请按照该指南中的说明完成:

步骤 8:使用 Kyverno 验证签名

步骤 8:验证镜像和证明 中,我们使用 cosign CLI 验证签名。 这里我们改用 Kyverno 来验证签名。

步骤 8.1:创建 Kyverno 策略,仅允许已签名镜像部署

TIP

此步骤需要集群管理员权限。

关于 Kyverno ClusterPolicy 的更多详情,请参考 Kyverno ClusterPolicy

策略内容如下:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: only-cosign-image-deploy
spec:
  webhookConfiguration:
    failurePolicy: Fail
    timeoutSeconds: 30
  background: false
  rules:
    - name: check-image
      match:
        any:
          - resources:
              kinds:
                - Pod
              namespaces:
                - policy
      verifyImages:
        - imageReferences:
            - "*"
            # - "<registry>/test/*"
          skipImageReferences:
            - "ghcr.io/trusted/*"
          failureAction: Enforce
          verifyDigest: false
          required: false
          useCache: false
          imageRegistryCredentials:
            allowInsecureRegistry: true
            secrets:
              # 凭证需要存在于 Kyverno 部署所在的命名空间
              - registry-credentials

          attestors:
            - count: 1
              entries:
                - keys:
                    publicKeys: |- # <- 签名者的公钥
                      -----BEGIN PUBLIC KEY-----
                      MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFZNGfYwn7+b4uSdEYLKjxWi3xtP3
                      UkR8hQvGrG25r0Ikoq0hI3/tr0m7ecvfM75TKh5jGAlLKSZUJpmCGaTToQ==
                      -----END PUBLIC KEY-----

                    ctlog:
                      ignoreSCT: true

                    rekor:
                      ignoreTlog: true
YAML 字段说明
  • spec.rules[].match.any[].resources:匹配并验证的资源。
    • kinds:匹配并验证的资源类型。
      • Pod:Pod 资源。
    • namespaces:匹配并验证的资源所在命名空间。
      • policy:匹配并验证 policy 命名空间中的资源。
  • spec.rules[].verifyImages:需要验证的镜像
    • imageReferences:需要验证的镜像引用。
      • *:验证所有镜像引用。
      • <registry>/test/*:仅验证 <registry>/test 仓库中的镜像引用。
    • skipImageReferences:跳过验证的镜像引用。
      • ghcr.io/trusted/*:跳过 ghcr.io/trusted 仓库中的镜像引用。
    • imageRegistryCredentials
      • allowInsecureRegistry:是否允许不安全的仓库。
      • secrets:用于镜像仓库凭证的 Secret。
        • registry-credentials:Secret 名称,需存在于 Kyverno 部署的命名空间。
    • attestors:用于镜像验证的验证者。
      • count:需要匹配的验证者数量。
      • entries:验证者条目。
        • keys:验证者的密钥。
          • publicKeys:验证者的公钥。
            • 此公钥与 signing-secrets Secret 中的 cosign.pub 公钥相同。
          • ctlog:验证者的 ctlog。
            • ignoreSCT:是否忽略 SCT。
              • 在隔离网络环境中,先忽略 SCT。
          • rekor:验证者的 rekor。
            • ignoreTlog:是否忽略 Tlog。
              • 在隔离网络环境中,先忽略 Tlog。

需调整的配置

  • spec.rules[].attestors[].entries[].keys.publicKeys:签名者的公钥。
    • 此公钥与 signing-secrets Secret 中的 cosign.pub 公钥相同。
    • 公钥可从 获取签名公钥 部分获得。

保存为名为 kyverno.only-cosign-image-deploy.yaml 的 yaml 文件,并通过以下命令应用:

$ kubectl apply -f kyverno.only-cosign-image-deploy.yaml

clusterpolicy.kyverno.io/only-cosign-image-deploy configured

步骤 8.2:验证策略

在定义策略的 policy 命名空间中,创建一个 Pod 来验证该策略。

使用流水线创建的已签名镜像创建 Pod。

$ export NAMESPACE=<policy>
$ export IMAGE=<<registry>/test/chains/demo-1:latest@sha256:93635f39cb31de5c6988cdf1f10435c41b3fb85570c930d51d41bbadc1a90046>

$ kubectl run -n $NAMESPACE signed --image=${IMAGE} -- sleep 3600

pod/signed created

Pod 会成功创建。

$ export NAMESPACE=<policy>
$ kubectl get pod -n $NAMESPACE signed

NAME      READY   STATUS    RESTARTS   AGE
signed   1/1     Running   0          10s

使用未签名镜像创建 Pod。

$ export NAMESPACE=<policy>
$ export IMAGE=<<registry>/test/chains/unsigned:latest>

$ kubectl run -n $NAMESPACE unsigned --image=${IMAGE} -- sleep 3600

收到如下输出,表示 Pod 被策略阻止。

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

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

only-cosign-image-deploy:
  check-image: 'failed to verify image ubuntu:latest:
    .attestors[0].entries[0].keys: no signatures found'

步骤 9:清理资源

删除前面步骤中创建的 Pods。

$ export NAMESPACE=<policy>
$ kubectl delete pod -n $NAMESPACE signed

pod "signed" deleted

删除策略。

$ kubectl delete clusterpolicy only-cosign-image-deploy

预期结果

完成本指南后:

  • 已成功搭建 Tekton Chains 进行镜像签名,Kyverno 进行签名验证的环境
  • 容器镜像在构建过程中自动签名
  • 仅允许已签名的镜像在指定命名空间中部署
  • 未签名镜像会被 Kyverno 策略自动阻止
  • 实现了容器镜像的基础供应链安全控制

本指南为在 CI/CD 流水线中实现供应链安全提供了基础。在生产环境中,您应当:

  1. 配置合适的命名空间隔离和访问控制
  2. 实施安全的签名密钥管理
  3. 设置策略违规的监控和告警
  4. 定期轮换签名密钥并更新安全策略
  5. 考虑实施额外的安全控制,如漏洞扫描

参考资料