License Compliance Verification

在 ACP (Alauda Container Platform) 中,你可以在 Tekton Pipeline 中使用 trivy 或 syft 任务为镜像生成 SBOM。

SBOM 包含镜像中每个组件的许可证信息。
我们可以使用 Kyverno 策略拒绝包含特定许可证的镜像。

由于该镜像的 SBOM 已在 Base Image and SBOM Verification 中生成,这里我们不会重新创建 pipeline,而是直接使用现有镜像来验证该能力。

TIP

本章基于 Base Image and SBOM Verification,仅增加了用于验证镜像许可证信息的逻辑。

功能概述

此方法与 Base Image and SBOM Verification 类似,只是将 kyverno 规则修改为验证许可证合规性。

  1. 配置 Kyverno 规则以验证 SBOM。
  2. 使用该镜像创建 Pod,以验证许可证合规性。

使用场景

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

  • 在 Kubernetes 集群中使用 Kyverno 实现许可证合规性验证
  • 强制执行安全策略,阻止包含特定许可证(例如 GPL)的镜像
  • 在 CI/CD pipeline 中设置自动化许可证验证
  • 确保生产环境中的许可证合规性
  • 通过验证容器镜像的组件许可证,实施供应链安全控制

前提条件

流程概览

步骤操作说明
1验证许可证信息创建并应用 Kyverno policy 以验证组件许可证
2(可选)验证 CVE 检查在 policy 中添加条件以检查特定漏洞
3清理删除测试资源和 policy

逐步说明

步骤 1:验证镜像的许可证信息

步骤 1.1:创建一个 Kyverno policy 来验证基础镜像信息

TIP

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

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

policy 如下:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-component-licenses
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:
              # The credential needs to exist in the namespace where kyverno is deployed
              - registry-credentials

          attestations:
            - type: https://cyclonedx.org/bom
              attestors:
                - entries:
                    - attestor:
                      keys:
                        publicKeys: |- # <- The public key of the signer
                          -----BEGIN PUBLIC KEY-----
                          MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFZNGfYwn7+b4uSdEYLKjxWi3xtP3
                          UkR8hQvGrG25r0Ikoq0hI3/tr0m7ecvfM75TKh5jGAlLKSZUJpmCGaTToQ==
                          -----END PUBLIC KEY-----

                        ctlog:
                          ignoreSCT: true

                        rekor:
                          ignoreTlog: true

              conditions:
                - any:
                    # Check if the image contains specific licenses
                    - key: "{{ components[].licenses[].license.id }}"
                      operator: AllNotIn
                      value: ["GPL-3.0-only", "GPL-3.0-or-later"]
                      message: |
                        The image contains GPL licenses which are not allowed.
                        Found licenses: {{ components[].licenses[].license.id }}

                    # Check if the image contains specific license names
                    - key: "{{ components[].licenses[].license.name }}"
                      operator: AllNotIn
                      value: ["GPL"]
                      message: |
                        The image contains Expat license which is not allowed.
                        Found licenses: {{ components[].licenses[].license.name }}
YAML 字段说明
  • 该 policy 与 Image Signature Verification 中的 policy 基本一致
  • spec.rules[0].verifyImages[].attestations[0].conditions
    • type:cyclonedx SBOM attestation 类型为 https://cyclonedx.org/bom
    • attestors:与上面相同。
    • conditions:需要验证的条件。
      • any:必须满足任意一个条件。
        • key: "{{ components[].licenses[].license.id }}":镜像包含不允许的 GPL licenses。
        • key: "{{ components[].licenses[].license.name }}":镜像包含不允许的 Expat license。

将 policy 保存到名为 kyverno.verify-component-licenses.yaml 的 yaml 文件中,并使用以下命令应用:

$ kubectl create -f kyverno.verify-component-licenses.yaml

clusterpolicy.kyverno.io/verify-component-licenses created

步骤 1.2:验证 policy

在定义该 policy 的 policy namespace 中,创建一个 Pod 来验证该 policy。

使用已构建的镜像创建 Pod。

$ export NAMESPACE=<policy>
$ export IMAGE=<<registry>/test/chains/demo-5:latest@sha256:a6c727554be7f9496e413a789663060cd2e62b3be083954188470a94b66239c7>

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

如果镜像包含 GPL licenses,则 Pod 创建会失败。

会收到如下输出:

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

resource Pod/policy/high-risk was blocked due to the following policies

verify-component-licenses:
  check-image: |
    image attestations verification failed, verifiedCount: 0, requiredCount: 1, error: .attestations[0].attestors[0].entries[0].keys: attestation checks failed for <registry>/test/chains/demo-5:latest and predicate https://cyclonedx.org/bom: The image contains GPL licenses which are not allowed.
    Found licenses: ["GPL-3.0-only","GPL-3.0-or-later","Latex2e"]
    ; The image contains Expat license which is not allowed.
    Found licenses: [,"GPL","LGPL","public-domain"]

修改 ClusterPolicy 中的 license 限制,以允许 GPL licenses。

conditions:
  - any:
    - key: "{{ components[].licenses[].license.id }}"
      operator: AllNotIn
      value: ["GPL-8.0-only"]
      message: |
        The image contains GPL licenses which are not allowed.
        Found licenses: {{ components[].licenses[].license.id }}

    - key: "{{ components[].licenses[].license.name }}"
      operator: AllNotIn
      value: ["GPL-x"]
      message: |
        The image contains Expat license which is not allowed.
        Found licenses: {{ components[].licenses[].license.name }}

然后创建一个 Pod 来验证该 policy。

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

pod/component-licenses created

Pod 将成功创建。

步骤 2:(可选)验证 Image Check CVE-2022-42889

TIP
  • 如果你想为 policy 添加更多条件,可以继续阅读下面的内容。
  • 这是一个简单示例,你可以使用相同的方法检查其他漏洞。

CVE-2022-42889 是 Apache Commons Text 库中的一个严重漏洞,可能导致任意代码执行,影响 1.5 到 1.9 版本。可通过在 SBOM 中识别版本受影响的 "commons-text" package 来检测受影响的 package。此 policy 会检查 imageReferences 下指定镜像的 CycloneDX 格式 attested SBOM,如果其中包含 commons-text package 的 1.5-1.9 版本,则拒绝该镜像。

我们只需要在 ClusterPolicy 中添加一个条件,检查镜像中是否包含 commons-text package。

conditions:
  - all:
    - key: "{{ components[?name=='commons-text'].version || 'none' }}"
      operator: AllNotIn
      value: ["1.5","1.6","1.7","1.8","1.9"]

这里不再演示,感兴趣的读者可以自行尝试。

步骤 3:清理资源

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

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

删除 policy。

$ kubectl delete clusterpolicy verify-component-licenses

预期结果

完成本指南后:

  • 你已经拥有一个可用于许可证合规性验证的 Kyverno 工作环境
  • 你的容器镜像会在其 attestation 中自动包含 SBOM 信息
  • 只有包含可接受许可证的镜像才能部署到指定 namespace
  • 不合规许可证的镜像会被 Kyverno policy 自动阻止
  • 你已经通过验证容器镜像中组件的许可证信息,实现了一个基础的供应链安全控制

本指南为在 CI/CD pipeline 中实施许可证合规性验证提供了基础。在生产环境中,你应该:

  1. 配置适当的 namespace 隔离和访问控制
  2. 为签名密钥实施安全的密钥管理
  3. 为 policy 违规设置监控和告警
  4. 根据许可证要求定期更新安全 policy

参考资料