• Русский
  • Сканирование и верификация уязвимостей

    В ACP (Alauda Container Platform) можно использовать Tekton Pipeline для сборки образа и сканирования его на наличие уязвимостей.

    В частности, используйте задачу trivy для генерации результатов сканирования уязвимостей, затем используйте cosign для загрузки аттестации результатов сканирования уязвимостей, и в конце используйте kyverno для проверки аттестации результатов сканирования уязвимостей.

    Обзор функциональности

    Этот метод использует инструменты, аналогичные trivy, для сканирования образа на наличие уязвимостей, а затем использует Kyverno для проверки результатов сканирования уязвимостей:

    1. Используйте Tekton Task trivy для сканирования образа на наличие уязвимостей.
    2. Используйте Tekton Task cosign для загрузки результатов сканирования уязвимостей в образ.
    3. Настройте правила Kyverno для проверки результатов сканирования уязвимостей.
    4. Используйте образ для создания Pod, чтобы проверить результаты сканирования уязвимостей.

    Сценарии использования

    В следующих сценариях необходимо обращаться к рекомендациям в этом документе:

    • Реализация сканирования и проверки уязвимостей в кластерах Kubernetes с использованием Kyverno
    • Применение политик безопасности, разрешающих развертывание только образов с приемлемым уровнем уязвимостей
    • Настройка автоматического сканирования и проверки уязвимостей в CI/CD pipeline
    • Обеспечение безопасности образов и соответствия требованиям по уязвимостям в production-средах
    • Реализация controls безопасности цепочки поставки для контейнерных образов путем проверки их статуса уязвимостей

    Предварительные требования

    • Кластер Kubernetes с установленными Tekton Pipelines, Tekton Chains и Kyverno
    • Registry с включенной возможностью push образов
    • Установленный и настроенный kubectl CLI для доступа к кластеру
    • Установленный cosign CLI tool
    • Установленный jq CLI tool

    Обзор процесса

    ШагОперацияОписание
    1Сгенерировать ключи подписиСоздать пару ключей для подписи артефактов с помощью cosign
    2Настроить аутентификациюНастроить учетные данные registry для push образов
    3Настроить Tekton ChainsНастроить Chains на использование OCI storage и signing, отключить TaskRun SLSA Provenance
    4Создать пример pipelineСоздать определение pipeline с задачами trivy scanner и cosign upload
    5Запустить пример pipelineСоздать и запустить PipelineRun с корректной конфигурацией
    6Дождаться подписанияДождаться, пока PipelineRun будет подписан Chains
    7Получить информацию об образеИзвлечь URI и digest образа из PipelineRun
    8(Необязательно) Получить аттестацию уязвимостейПолучить и проверить аттестацию результатов сканирования уязвимостей
    9Проверить с помощью KyvernoСоздать и применить политику Kyverno для проверки результатов сканирования уязвимостей
    10(Необязательно) Требовать недавнее сканированиеДобавить условие, требующее, чтобы результаты сканирования уязвимостей были получены не более чем 168 часов назад
    11Очистить ресурсыУдалить тестовые ресурсы и политики

    Пошаговые инструкции

    Шаги 1–3: Базовая настройка

    Эти шаги идентичны руководству Quick Start: Signed Provenance. Следуйте инструкциям в этом руководстве для:

    • Step 1: Generate Signing Keys
    • Step 2: Set up Authentication
    • Step 3: Configure Tekton Chains
    • Get the signing secret
      • Important: Это сделано только для удобства, поэтому здесь используется глобальный signing certificate Chains. В реальном использовании можно использовать отдельный сертификат для подписи информации об уязвимостях образа.
      • Импортируйте secret в namespace, в котором выполняется pipeline.

    Шаг 4: Создание примера Pipeline

    Это ресурс Pipeline, который используется для сборки образа и генерации cosign vulnerability attestation.

    apiVersion: tekton.dev/v1
    kind: Pipeline
    metadata:
      name: chains-demo-4
    spec:
      params:
        - default: |-
            echo "Generate a Containerfile for building an image."
    
            cat << 'EOF' > Containerfile
            FROM ubuntu:latest
            ENV TIME=1
            EOF
    
            echo -e "\nContainerfile contents:"
            echo "-------------------"
            cat Containerfile
            echo "-------------------"
            echo -e "\nContainerfile generated successfully!"
          description: A script to generate a Containerfile for building an image.
          name: generate-containerfile
          type: string
        - default: <registry>/test/chains/demo-4:latest
          description: The target image address built
          name: image
          type: string
      results:
        - description: first image artifact output
          name: first_image_ARTIFACT_OUTPUTS
          type: object
          value:
            digest: $(tasks.build-image.results.IMAGE_DIGEST)
            uri: $(tasks.build-image.results.IMAGE_URL)
      tasks:
        - name: generate-containerfile
          params:
            - name: script
              value: $(params.generate-containerfile)
          taskRef:
            params:
              - name: kind
                value: task
              - name: catalog
                value: catalog
              - name: name
                value: run-script
              - name: version
                value: "0.1"
            resolver: hub
          timeout: 30m0s
          workspaces:
            - name: source
              workspace: source
        - name: build-image
          params:
            - name: IMAGES
              value:
                - $(params.image)
            - name: TLS_VERIFY
              value: "false"
          runAfter:
            - generate-containerfile
          taskRef:
            params:
              - name: kind
                value: task
              - name: catalog
                value: catalog
              - name: name
                value: buildah
              - name: version
                value: "0.9"
            resolver: hub
          timeout: 30m0s
          workspaces:
            - name: source
              workspace: source
            - name: registryconfig
              workspace: registryconfig
        - name: trivy-scanner
          params:
            - name: COMMAND
              value: |-
                set -x
    
                mkdir -p .git
    
                # support for insecure registry
                export TRIVY_INSECURE=true
    
                echo "generate cyclonedx sbom"
                trivy image --skip-db-update --skip-java-db-update --scanners vuln --format cyclonedx --output .git/sbom-cyclonedx.json $(tasks.build-image.results.IMAGE_URL)@$(tasks.build-image.results.IMAGE_DIGEST)
                cat .git/sbom-cyclonedx.json
    
                echo "trivy scan vulnerabilities based on cyclonedx sbom"
                trivy sbom --skip-db-update --skip-java-db-update --format cosign-vuln --output .git/trivy-scan-result.json .git/sbom-cyclonedx.json
                cat .git/trivy-scan-result.json
    
                echo "trivy scan vulnerabilities based on cyclonedx sbom and output in table format"
                trivy sbom --skip-db-update --skip-java-db-update --format table .git/sbom-cyclonedx.json
          runAfter:
            - build-image
          taskRef:
            params:
              - name: kind
                value: task
              - name: catalog
                value: catalog
              - name: name
                value: trivy-scanner
              - name: version
                value: "0.4"
            resolver: hub
          timeout: 30m0s
          workspaces:
            - name: source
              workspace: source
            - name: registryconfig
              workspace: registryconfig
        - name: cosign-uploads
          params:
            - name: COMMAND
              value: |-
                set -x
    
                export COSIGN_ALLOW_INSECURE_REGISTRY=true
                export COSIGN_TLOG_UPLOAD=false
                export COSIGN_KEY=$(workspaces.signkey.path)/cosign.key
    
                echo "Signing image vuln"
                cosign attest --type vuln --predicate .git/trivy-scan-result.json $(tasks.build-image.results.IMAGE_URL)@$(tasks.build-image.results.IMAGE_DIGEST)
    
                echo "Signing image sbom"
                cosign attest --type cyclonedx --predicate .git/sbom-cyclonedx.json $(tasks.build-image.results.IMAGE_URL)@$(tasks.build-image.results.IMAGE_DIGEST)
          runAfter:
            - trivy-scanner
          taskRef:
            params:
              - name: kind
                value: task
              - name: catalog
                value: catalog
              - name: name
                value: cosign
              - name: version
                value: "0.1"
            resolver: hub
          timeout: 30m0s
          workspaces:
            - name: source
              workspace: source
            - name: registryconfig
              workspace: registryconfig
            - name: signkey
              workspace: signkey
      workspaces:
        - name: source
          description: The workspace for source code.
        - name: registryconfig
          description: The workspace for distribution registry configuration.
        - name: signkey
          description: The workspace for private keys and passwords used for image signatures.
    TIP

    Это руководство демонстрирует упрощенный рабочий процесс: генерация Containerfile и output задачи git-clone выполняются прямо внутри pipeline. В production-среде обычно:

    1. Используют задачу git-clone для получения исходного кода из репозитория
    2. Собирают образ с использованием Containerfile, который уже присутствует в исходном коде
    3. Такой подход обеспечивает корректный version control и сохраняет разделение между кодом и конфигурацией pipeline
    Пояснение полей YAML
    • То же самое, что и в Step 4: Create a Sample Pipeline, но добавляет следующий контент:
      • workspaces:
        • signkey: Workspace для закрытых ключей и паролей, используемых для подписей образов.
      • tasks:
        • trivy-scanner: Задача для сканирования образа на наличие уязвимостей.
        • cosign-uploads: Задача для загрузки аттестации результатов сканирования уязвимостей. :::

    Сохраните это в YAML-файл с именем chains-demo-4.yaml и примените его:

    $ export NAMESPACE=<default>
    
    # create the pipeline in the namespace
    $ kubectl create -n $NAMESPACE -f chains-demo-4.yaml
    
    pipeline.tekton.dev/chains-demo-4 created

    Шаг 5: Запуск примера Pipeline

    Это ресурс PipelineRun, который используется для запуска pipeline.

    apiVersion: tekton.dev/v1
    kind: PipelineRun
    metadata:
      generateName: chains-demo-4-
    spec:
      pipelineRef:
        name: chains-demo-4
      taskRunTemplate:
        serviceAccountName: <default>
      workspaces:
        - name: registryconfig
          secret:
            secretName: <registry-credentials>
        - name: signkey
          secret:
            secretName: <signing-secrets>
        - name: source
          volumeClaimTemplate:
            spec:
              accessModes:
                - ReadWriteOnce
              resources:
                requests:
                  storage: 1Gi
              storageClassName: <nfs>

    :::details {title="Пояснение полей YAML"}

    • То же самое, что и в Step 5: Run a Sample Pipeline. Ниже описаны только различия.
    • workspaces
      • signkey: имя secret с signing key.
        • secret.secretName: Signing secret, подготовленный на предыдущем шаге Get the signing secret. Но вам нужно создать новый secret в том же namespace, что и PipelineRun. :::

    Сохраните это в YAML-файл с именем chains-demo-4.pipelinerun.yaml и примените его:

    $ export NAMESPACE=<default>
    
    # create the pipeline run in the namespace
    $ kubectl create -n $NAMESPACE -f chains-demo-4.pipelinerun.yaml

    Дождитесь завершения PipelineRun.

    $ kubectl get pipelinerun -n $NAMESPACE -w
    
    chains-demo-4-<xxxxx>     True        Succeeded   2m  2m

    Шаг 6: Дождаться подписания PipelineRun

    Дождитесь, пока у PipelineRun появится аннотация chains.tekton.dev/signed: "true".

    $ export NAMESPACE=<default>
    $ export PIPELINERUN_NAME=<chains-demo-4-xxxxx>
    
    $ kubectl get pipelinerun -n $NAMESPACE $PIPELINERUN_NAME -o yaml | grep "chains.tekton.dev/signed"
    
        chains.tekton.dev/signed: "true"

    Когда у PipelineRun есть аннотация chains.tekton.dev/signed: "true", это означает, что образ подписан.

    Шаг 7: Получить образ из PipelineRun

    # Get the image URI
    $ export IMAGE_URI=$(kubectl get pipelinerun -n $NAMESPACE $PIPELINERUN_NAME -o jsonpath='{.status.results[?(@.name=="first_image_ARTIFACT_OUTPUTS")].value.uri}')
    
    # Get the image digest
    $ export IMAGE_DIGEST=$(kubectl get pipelinerun -n $NAMESPACE $PIPELINERUN_NAME -o jsonpath='{.status.results[?(@.name=="first_image_ARTIFACT_OUTPUTS")].value.digest}')
    
    # Combine the image URI and digest to form the full image reference
    $ export IMAGE=$IMAGE_URI@$IMAGE_DIGEST
    
    # Print the image reference
    $ echo $IMAGE
    
    <registry>/test/chains/demo-4:latest@sha256:93635f39cb31de5c6988cdf1f10435c41b3fb85570c930d51d41bbadc1a90046

    Этот образ будет использоваться для проверки результатов сканирования уязвимостей.

    Шаг 8: (Необязательно) Получить cosign vuln attestation

    Если вам интересно содержимое cosign vuln attestation, можно продолжить чтение следующего материала.

    Подробнее о cosign vuln attestation см. в cosign vuln attestation

    Получите публичный signing key согласно разделу Get the signing public key.

    # Disable tlog upload and enable private infrastructure
    $ export COSIGN_TLOG_UPLOAD=false
    $ export COSIGN_PRIVATE_INFRASTRUCTURE=true
    
    $ export IMAGE=<<registry>/test/chains/demo-4:latest@sha256:5e7b466e266633464741b61b9746acd7d02c682d2e976b1674f924aa0dfa2047>
    
    $ cosign verify-attestation --key cosign.pub --type vuln $IMAGE | jq -r '.payload | @base64d' | jq -s

    Вывод будет похож на следующий и содержит результаты сканирования уязвимостей.

    :::details {title="cosign vuln attestation"}

    {
      "_type": "https://in-toto.io/Statement/v0.1",
      "predicateType": "https://cosign.sigstore.dev/attestation/vuln/v1",
      "predicate": {
        "scanner": {
          "uri": "pkg:github/aquasecurity/trivy@dev",
          "version": "dev",
          "result": {
            "CreatedAt": "2025-06-07T07:05:30.098889688Z",
            "Metadata": {
              "OS": {
                "Family": "ubuntu",
                "Name": "24.04"
              }
            },
            "Results": [
              {
                "Class": "os-pkgs",
                "Packages": [
                  {
                    "Arch": "amd64",
                    "ID": "coreutils@9.4-3ubuntu6",
                    "Identifier": {
                      "BOMRef": "pkg:deb/ubuntu/coreutils@9.4-3ubuntu6?arch=amd64&distro=ubuntu-24.04",
                      "PURL": "pkg:deb/ubuntu/coreutils@9.4-3ubuntu6?arch=amd64&distro=ubuntu-24.04",
                      "UID": "82bb3c93286700bc"
                    },
                    "Licenses": [
                      "GPL-3.0-or-later",
                      "BSD-4-Clause-UC",
                      "GPL-3.0-only",
                      "ISC",
                      "FSFULLR",
                      "GFDL-1.3-no-invariants-only",
                      "GFDL-1.3-only"
                    ],
                    "Name": "coreutils"
                  }
                ],
                "Vulnerabilities": [
                  {
                    "CVSS": {
                      "nvd": {
                        "V2Score": 2.1,
                        "V2Vector": "AV:L/AC:L/Au:N/C:N/I:P/A:N",
                        "V3Score": 6.5,
                        "V3Vector": "CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:N"
                      },
                      "redhat": {
                        "V2Score": 6.2,
                        "V2Vector": "AV:L/AC:H/Au:N/C:C/I:C/A:C",
                        "V3Score": 8.6,
                        "V3Vector": "CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H"
                      }
                    },
                    "InstalledVersion": "9.4-3ubuntu6",
                    "LastModifiedDate": "2025-04-20T01:37:25.86Z",
                    "PkgID": "coreutils@9.4-3ubuntu6",
                    "PkgName": "coreutils",
                    "PublishedDate": "2017-02-07T15:59:00.333Z",
                    "References": [
                      "http://seclists.org/oss-sec/2016/q1/452",
                      "http://www.openwall.com/lists/oss-security/2016/02/28/2",
                      "http://www.openwall.com/lists/oss-security/2016/02/28/3",
                      "https://access.redhat.com/security/cve/CVE-2016-2781",
                      "https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772%40%3Cdev.mina.apache.org%3E",
                      "https://lore.kernel.org/patchwork/patch/793178/",
                      "https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/v2.28/v2.28-ReleaseNotes",
                      "https://nvd.nist.gov/vuln/detail/CVE-2016-2781",
                      "https://www.cve.org/CVERecord?id=CVE-2016-2781"
                    ],
                    "Severity": "LOW",
                    "SeveritySource": "ubuntu",
                    "Status": "affected",
                    "VendorSeverity": {
                      "azure": 2,
                      "cbl-mariner": 2,
                      "nvd": 2,
                      "redhat": 2,
                      "ubuntu": 1
                    },
                    "VulnerabilityID": "CVE-2016-2781"
                  }
                ]
              }
            ],
            "SchemaVersion": 2
          }
        },
        "metadata": {
          "scanStartedOn": "2025-06-07T07:05:30.104726629Z",
          "scanFinishedOn": "2025-06-07T07:05:30.104726629Z"
        }
      }
    }

    :::details {title="Описание полей"}

    • predicateType: Тип predicate.
    • predicate.scanner:
      • uri: URI сканера.
      • version: Версия сканера.
      • result: Результат сканирования уязвимостей.
        • CreatedAt: Время завершения сканирования уязвимостей.
        • Metadata:
          • OS:
            • Family: Семейство ОС.
            • Name: Имя ОС.
        • Results: Результаты сканирования уязвимостей.
          • Class:
            • os-pkgs: Пакеты ОС.
            • lang-pkgs: Пакеты языков.
          • Packages: Пакеты образа.
          • Vulnerabilities: Уязвимости образа.
            • Severity: Уровень серьезности уязвимости.
            • PkgID: Идентификатор пакета, связанного с уязвимостью.
            • PkgName: Имя пакета.
            • CVSS: CVSS уязвимости.
              • nvd: NVD уязвимости.
              • redhat: Red Hat уязвимости. :::

    Шаг 9: Проверка результатов сканирования уязвимостей с помощью Kyverno

    Шаг 9.1: Создать политику Kyverno для отклонения образов с уязвимостями высокого риска

    TIP

    Для этого шага требуются права cluster administrator.

    Подробнее о Kyverno ClusterPolicy см. в Kyverno ClusterPolicy

    Политика выглядит следующим образом:

    apiVersion: kyverno.io/v1
    kind: ClusterPolicy
    metadata:
      name: reject-high-risk-image
    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://cosign.sigstore.dev/attestation/vuln/v1
                  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:
                    - all:
                        - key: "{{ scanner.result.Results[].Vulnerabilities[].Severity }}"
                          operator: AllNotIn
                          # supported values: UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL
                          value: ["HIGH", "CRITICAL"]
                          message: |
                            The image contains high-risk vulnerabilities, please fix them before proceeding.
                            Severity levels: {{ scanner.result.Results[].Vulnerabilities[].Severity }}
    
                        - key: "{{ scanner.result.Results[].Vulnerabilities[?CVSS.redhat.V3Score > `1.0`][] | length(@) }}"
                          operator: Equals
                          value: 0
                          message: |
                            The image contains high-risk vulnerabilities, please fix them before proceeding.
                            High-risk vulnerabilities (CVSS > 1.0): {{ scanner.result.Results[].Vulnerabilities[?CVSS.redhat.V3Score > `1.0`].CVSS.redhat.V3Score[] }}.
                            Severity levels: {{ scanner.result.Results[].Vulnerabilities[?CVSS.redhat.V3Score > `1.0`].Severity[] }}.
                            PkgIDs: {{ scanner.result.Results[].Vulnerabilities[?CVSS.redhat.V3Score > `1.0`].PkgID[] }}.

    :::details {title="Пояснение полей YAML"}

    • Политика в целом соответствует политике из Image Signature Verification
    • spec.rules[0].verifyImages[].attestations[0].conditions
      • type: Тип cosign vuln attestation — https://cosign.sigstore.dev/attestation/vuln/v1
      • attestors: То же самое, что и выше.
      • conditions: Условия, которые необходимо проверить.
        • all: Должны выполняться все условия.
          • key: "{{ scanner.result.Results[].Vulnerabilities[].Severity }}": Уровень серьезности уязвимостей не должен быть HIGH или CRITICAL.
          • key: "{{ scanner.result.Results[].Vulnerabilities[?CVSS.redhat.V3Score > 1.0][] | length(@) }}": Количество уязвимостей с CVSS score выше 1.0 должно быть равно 0. :::

    Сохраните политику в YAML-файл с именем kyverno.reject-high-risk-image.yaml и примените ее:

    $ kubectl apply -f kyverno.reject-high-risk-image.yaml
    
    clusterpolicy.kyverno.io/reject-high-risk-image configured

    Шаг 9.2: Проверить политику

    В namespace policy, где определена политика, создайте Pod для проверки политики.

    Используйте собранный образ для создания Pod.

    $ export NAMESPACE=<policy>
    $ export IMAGE=<<registry>/test/chains/demo-4:latest@sha256:0f123204c44969876ed12f40066ccccbfd68361f68c91eb313ac764d59428bef>
    
    $ kubectl run -n $NAMESPACE vuln-image --image=${IMAGE} -- sleep 3600

    Если в вашем образе есть уязвимости высокого риска, 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
    
    reject-high-risk-image:
      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-4:latest and predicate https://cosign.sigstore.dev/attestation/vuln/v1: The image contains high-risk vulnerabilities, please fix them before proceeding.
        High-risk vulnerabilities (CVSS > 1.0): [8.6,2.7,6.2,5.9,7.5,4.7,7.4,4.7,7.4,4.7,7.4,4.7,7.4,5.9,3.6,3.6,7.3,4.4,6.5,5.4].
        Severity levels: ["LOW","MEDIUM","LOW","LOW","MEDIUM","MEDIUM","MEDIUM","MEDIUM","MEDIUM","MEDIUM","MEDIUM","MEDIUM","MEDIUM","LOW","LOW","LOW","MEDIUM","MEDIUM","MEDIUM","MEDIUM"].
        PkgIDs: ["coreutils@9.4-3ubuntu6","gpgv@2.4.4-2ubuntu17","gpgv@2.4.4-2ubuntu17","libgcrypt20@1.10.3-2build1","liblzma5@5.6.1+really5.4.5-1build0.1","libpam-modules@1.5.3-5ubuntu5.1","libpam-modules@1.5.3-5ubuntu5.1","libpam-modules-bin@1.5.3-5ubuntu5.1","libpam-modules-bin@1.5.3-5ubuntu5.1","libpam-runtime@1.5.3-5ubuntu5.1","libpam-runtime@1.5.3-5ubuntu5.1","libpam0g@1.5.3-5ubuntu5.1","libpam0g@1.5.3-5ubuntu5.1","libssl3t64@3.0.13-0ubuntu3.5","login@1:4.13+dfsg1-4ubuntu3.2","passwd@1:4.13+dfsg1-4ubuntu3.2","perl-base@5.38.2-3.2build2.1","golang.org/x/net@v0.23.0","golang.org/x/net@v0.23.0","stdlib@v1.22.12"].

    Измените условия в ClusterPolicy, чтобы разрешить образы с уязвимостями высокого риска, но с CVSS score меньше 10.0.

    conditions:
      - all:
          - key: "{{ scanner.result.Results[].Vulnerabilities[].Severity }}"
            operator: AllNotIn
            value: ["CRITICAL"]
            message: |
              The image contains high-risk vulnerabilities, please fix them before proceeding.
              Severity levels: {{ scanner.result.Results[].Vulnerabilities[].Severity }}
    
          - key: "{{ scanner.result.Results[].Vulnerabilities[?CVSS.redhat.V3Score > `10.0`][] | length(@) }}"
            operator: Equals
            value: 0
            message: |
              The image contains high-risk vulnerabilities, please fix them before proceeding.
              High-risk vulnerabilities (CVSS > 10.0): {{ scanner.result.Results[].Vulnerabilities[?CVSS.redhat.V3Score > `10.0`].CVSS.redhat.V3Score[] }}.
              Severity levels: {{ scanner.result.Results[].Vulnerabilities[?CVSS.redhat.V3Score > `10.0`].Severity[] }}.
              PkgIDs: {{ scanner.result.Results[].Vulnerabilities[?CVSS.redhat.V3Score > `10.0`].PkgID[] }}.

    Затем снова создайте Pod, чтобы проверить политику.

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

    Pod будет создан успешно.

    Шаг 10: (Необязательно) Требовать, чтобы результаты сканирования уязвимостей были не старше 168 часов

    TIP

    Если вы хотите добавить в политику дополнительные условия, можно продолжить чтение следующего материала.

    Поскольку Cosign Vulnerability Scan Record Attestation включает поле scanFinishedOn, а trivy соответствует спецификации, мы можем использовать это поле, чтобы определить, были ли результаты сканирования уязвимостей получены не более 168 часов назад.

    Нам нужно только добавить условие в ClusterPolicy, чтобы проверить, находится ли поле scanFinishedOn в пределах 168 часов.

    conditions:
      - all:
          - key: "{{ time_since('','{{metadata.scanFinishedOn}}','') }}"
            operator: LessThanOrEquals
            value: "168h"
            message: "The vulnerability scan results must be within 168 hours, not {{ metadata.scanFinishedOn }}"

    Здесь это не демонстрируется; заинтересованные читатели могут попробовать сами.

    Шаг 11: Очистка ресурсов

    Удалите Pod, созданные на предыдущих шагах.

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

    Удалите политику.

    $ kubectl delete clusterpolicy reject-high-risk-image

    Ожидаемые результаты

    После выполнения этого руководства:

    • У вас будет рабочая конфигурация Tekton Chains для сканирования уязвимостей и Kyverno для проверки уязвимостей
    • Ваши container images автоматически будут включать результаты сканирования уязвимостей в своих аттестациях
    • Только образы с приемлемым уровнем уязвимостей смогут быть развернуты в указанном namespace
    • Образы с уязвимостями высокого риска будут автоматически блокироваться политиками Kyverno
    • Вы реализуете базовый control безопасности цепочки поставки, проверяя статус уязвимостей ваших container images

    Это руководство служит основой для внедрения безопасности цепочки поставки в ваши CI/CD pipeline. В production-среде следует:

    1. Настроить корректную изоляцию namespace и control доступа
    2. Реализовать безопасное управление ключами для signing keys
    3. Настроить мониторинг и оповещения о нарушениях политик
    4. Регулярно обновлять signing keys и security policies

    Ссылки