许可证合规性验证

在 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 规则以验证许可证合规性。

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

使用场景

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

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

前提条件

流程概览

步骤操作说明
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:
              # 凭证需要存在于 kyverno 部署所在的 namespace 中
              - registry-credentials

          attestations:
            - type: https://cyclonedx.org/bom
              attestors:
                - entries:
                    - attestor:
                      keys:
                        publicKeys: |- # <- 签名者的公钥
                          -----BEGIN PUBLIC KEY-----
                          MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFZNGfYwn7+b4uSdEYLKjxWi3xtP3
                          UkR8hQvGrG25r0Ikoq0hI3/tr0m7ecvfM75TKh5jGAlLKSZUJpmCGaTToQ==
                          -----END PUBLIC KEY-----

                        ctlog:
                          ignoreSCT: true

                        rekor:
                          ignoreTlog: true

              conditions:
                - any:
                    # 检查镜像是否包含特定许可证
                    - key: "{{ components[].licenses[].license.id }}"
                      operator: AllNotIn
                      value: ["GPL-3.0-only", "GPL-3.0-or-later"]
                      message: |
                        该镜像包含不允许的 GPL 许可证。
                        Found licenses: {{ components[].licenses[].license.id }}

                    # 检查镜像是否包含特定许可证名称
                    - key: "{{ components[].licenses[].license.name }}"
                      operator: AllNotIn
                      value: ["GPL"]
                      message: |
                        该镜像包含不允许的 Expat 许可证。
                        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 许可证。
        • key: "{{ components[].licenses[].license.name }}":镜像包含不允许的 Expat 许可证。

将 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 许可证,则 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 许可证。

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" 包来检测受影响的组件。此 policy 会检查 imageReferences 下指定镜像的、CycloneDX 格式的已验证 SBOM,如果其中包含 commons-text 包的 1.5-1.9 版本,则拒绝该镜像。

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

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 建立了可工作的许可证合规性验证方案
  • 你的容器镜像会在其 attestations 中自动包含 SBOM 信息
  • 只有包含可接受许可证的镜像才能在指定 namespace 中部署
  • 不符合规范的镜像会被 Kyverno policies 自动阻止
  • 你已经通过验证容器镜像中组件的许可证信息,实现了基础的供应链安全控制

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

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

参考资料