License Compliance Verification

在 ACP (Alauda Container Platform) 中,你可以在 Tekton Pipeline 中使用 trivysyft task 为镜像生成 SBOM。

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

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

TIP

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

功能概述

此方法与 Base Image and SBOM Verification 类似,只是更改了 kyverno rules 以验证许可证合规性。

  1. 配置 Kyverno rules 来验证 SBOM。
  2. 使用镜像创建 Pod 来验证许可证合规性。

使用场景

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

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

前提条件

流程概览

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

分步说明

步骤 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 中的许可证限制,以允许 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 library 中的一个严重漏洞,可能导致任意代码执行,影响版本 1.5 到 1.9。可以通过在 SBOM 中识别 “commons-text” package 及其受影响版本来检测该 package。此 policy 会检查 imageReferences 下指定镜像的 CycloneDX 格式已签名 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 policies 自动阻止
  • 你已经通过验证容器镜像中组件的许可证信息,实现了基础的供应链安全控制

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

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

参考资料