• Русский
  • Проверка происхождения системы сборки

    В SLSA provenance есть поле builder.id, которое используется для указания среды сборки образа.

    В этом документе мы будем использовать это поле builder.id для проверки образа.

    TIP

    Поскольку Tekton Chains уже выполнил и подпись образа, и генерацию SLSA provenance на подготовительном этапе, мы можем напрямую повторно использовать процесс и образы из Быстрый старт: Signed Provenance.

    В этом документе мы сосредоточимся на проверке SLSA provenance.

    Обзор возможностей

    Этот метод использует Chains для автоматической генерации SLSA Provenance для собранного образа, а затем Kyverno для проверки provenance:

    1. Настройте Tekton Chains для автоматической генерации SLSA Provenance для собранного образа.
    2. Используйте Tekton Task buildah для сборки образа.
    3. (Необязательно) Используйте cosign cli для проверки attestation.
    4. Настройте правила Kyverno для проверки attestation.
    5. Используйте образ для создания Pod, чтобы проверить attestation.

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

    Следующие сценарии требуют обращения к рекомендациям из этого документа:

    • Проверка среды сборки container image с использованием SLSA provenance
    • Реализация проверки происхождения системы сборки с помощью политик CUE или Rego
    • Принудительное применение политик безопасности, разрешающих только образы, собранные в определенных средах сборки
    • Настройка автоматической проверки происхождения системы сборки в CI/CD pipelines
    • Обеспечение целостности и подлинности происхождения системы сборки в production-средах

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

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

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

    ШагОперацияОписание
    1Генерация ключей подписиСоздайте пару ключей для подписи artifacts с помощью cosign
    2Настройка аутентификацииНастройте учетные данные registry для push образов
    3Настройка Tekton ChainsНастройте Chains на использование OCI storage и задайте подпись
    4Создание примера pipelineСоздайте определение pipeline с необходимыми tasks и workspaces
    5Запуск примера pipelineСоздайте и запустите PipelineRun с корректной конфигурацией
    6Ожидание подписиДождитесь, пока PipelineRun будет подписан Chains
    7Получение информации об образеИзвлеките URI и digest образа из PipelineRun
    8(Необязательно) Проверка подписей с помощью cosignПроверьте attestation образа с помощью cosign CLI
    9Проверка подписей с помощью KyvernoНастройте и проверьте attestation образа с помощью политик Kyverno
    10Очистка ресурсовУдалите test Pods и политики

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

    Шаги 1-7: (Необязательно) Базовая настройка

    NOTE

    Если вы измените поле builder.id, вам нужно повторно запустить pipeline, чтобы сгенерировать образ. Поскольку старый образ не подписан новым builder.id, политика его заблокирует.

    В противном случае вы можете пропустить этот шаг и использовать старый образ для проверки политики.

    Эти шаги полностью совпадают с руководством Быстрый старт: Signed Provenance. Пожалуйста, следуйте инструкциям в этом руководстве для:

    Шаг 8: (Необязательно) Проверка информации о builder с помощью cosign

    TIP

    Этот шаг необязателен и должен выполняться, когда вам нужно проверить подлинность builder образа с помощью cosign.

    Если вам интересно, как использовать CUE или Rego для проверки информации о builder, вы можете продолжить чтение следующего содержимого.

    Получите публичный ключ подписи согласно разделу Получение публичного ключа подписи.

    Cosign предоставляет два способа проверки attestation:

    Ниже показаны методы проверки для этих двух способов.

    Способ 1: Использование CUE для проверки

    Сгенерируйте CUE-файл для проверки информации о builder.

    // Predicate должен соответствовать следующим ограничениям.
    predicate: {
        builder: {
            id: "https://alauda.io/builders/tekton/v1"
        }
    }

    Сохраните CUE-файл как builder.cue

    Проверьте информацию о builder с помощью cosign.

    # Disable tlog upload and enable private infrastructure
    $ export COSIGN_TLOG_UPLOAD=false
    $ export COSIGN_PRIVATE_INFRASTRUCTURE=true
    
    $ export IMAGE=<<registry>/test/chains/demo-1:latest@sha256:93635f39cb31de5c6988cdf1f10435c41b3fb85570c930d51d41bbadc1a90046>
    
    $ cosign verify-attestation --key cosign.pub --type slsaprovenance --policy builder.cue $IMAGE

    Если вы получите такой вывод, значит проверка информации о builder прошла успешно.

    will be validating against CUE policies: [builder.cue]
    will be validating against CUE policies: [builder.cue]
    
    Verification for <registry>/test/chains/demo-1:latest@sha256:8ac1af8dd89652bf32abbbd0c5f667ae9fe6d92c91972617e70b5398303c8e27 --
    The following checks were performed on each of these signatures:
      - The cosign claims were validated
      - The signatures were verified against the specified public key
    {"payloadType":"application/vnd.in-toto+json","payload":"","signatures":[]}

    Измените builder id в файле builder.cue на другое значение https://alauda.io/builders/tekton/v2 и повторите проверку.

    $ cosign verify-attestation --key cosign.pub --type slsaprovenance --policy builder.cue $IMAGE

    Если вы получите такой вывод, значит проверка информации о builder не прошла.

    will be validating against CUE policies: [builder.cue]
    will be validating against CUE policies: [builder.cue]
    There are 2 number of errors occurred during the validation:
    
    - predicate.builder.id: conflicting values "https://alauda.io/builders/tekton/v1" and "https://alauda.io/builders/tekton/v2"
    - predicate.builder.id: conflicting values "https://alauda.io/builders/tekton/v1" and "https://alauda.io/builders/tekton/v2"
    Error: 2 validation errors occurred
    error during command execution: 2 validation errors occurred

    Способ 2: Использование Rego для проверки

    Сгенерируйте Rego-файл для проверки информации о builder.

    package signature
    
    default allow = false
    
    # Define the allowed builder.id
    allowed_builder_id = "https://alauda.io/builders/tekton/v1"
    
    # Verify the builder.id
    allow {
        # Check if the builder.id in the predicate is equal to the allowed value
        input.predicate.builder.id == allowed_builder_id
    }
    
    # Return error message when not match
    deny[msg] {
        input.predicate.builder.id != allowed_builder_id
        msg := sprintf("unexpected builder.id: %v, expected: %v", [input.predicate.builder.id, allowed_builder_id])
    }

    Сохраните Rego-файл как builder.rego

    Проверьте информацию о builder с помощью cosign.

    # Disable tlog upload and enable private infrastructure
    $ export COSIGN_TLOG_UPLOAD=false
    $ export COSIGN_PRIVATE_INFRASTRUCTURE=true
    
    $ export IMAGE=<<registry>/test/chains/demo-1:latest@sha256:93635f39cb31de5c6988cdf1f10435c41b3fb85570c930d51d41bbadc1a90046>
    
    $ cosign verify-attestation --key cosign.pub --type slsaprovenance --policy builder.rego $IMAGE

    Если вы получите такой вывод, значит проверка информации о builder прошла успешно.

    will be validating against Rego policies: [builder.rego]
    will be validating against Rego policies: [builder.rego]
    
    Verification for <registry>/test/chains/demo-1:latest --
    The following checks were performed on each of these signatures:
      - The cosign claims were validated
      - The signatures were verified against the specified public key
    {"payloadType":"application/vnd.in-toto+json","payload":"","signatures":[]}

    Измените builder id в файле builder.rego на другое значение https://alauda.io/builders/tekton/v2 и повторите проверку.

    $ cosign verify-attestation --key cosign.pub --type slsaprovenance --policy builder.rego $IMAGE

    Если вы получите такой вывод, значит проверка информации о builder не прошла.

    will be validating against Rego policies: [builder.rego]
    will be validating against Rego policies: [builder.rego]
    There are 2 number of errors occurred during the validation:
    
    - expression value, false, is not true
    - expression value, false, is not true
    Error: 2 validation errors occurred
    error during command execution: 2 validation errors occurred

    Шаг 9: Проверка подписи с помощью Kyverno

    TIP

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

    Содержимое provenance примерно следующее; мы будем использовать поле builder.id для проверки среды сборки.

    {
      "_type": "https://in-toto.io/Statement/v0.1",
      "predicateType": "https://slsa.dev/provenance/v0.2",
      "predicate": {
        "buildType": "tekton.dev/v1beta1/TaskRun",
        "builder": {
          "id": "https://alauda.io/builders/tekton/v1"
        },
        "materials": [
          {
            "digest": {
              "sha256": "8d5ea9ecd9b531e798fecd87ca3b64ee1c95e4f2621d09e893c58ed593bfd4c4"
            },
            "uri": "oci://<registry>/devops/tektoncd/hub/buildah"
          }
        ],
        "metadata": {
          "buildFinishedOn": "2025-06-06T10:21:27Z",
          "buildStartedOn": "2025-06-06T10:20:55Z"
        }
      }
    }

    Шаг 9.1: Создайте политику Kyverno, чтобы разрешить развертывание только образов, собранных в определенных средах сборки

    TIP

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

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

    apiVersion: kyverno.io/v1
    kind: ClusterPolicy
    metadata:
      name: verify-tekton-built-images
    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://slsa.dev/provenance/v0.2
                  attestors:
                    - entries:
                        - 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: "{{ builder.id }}"
                          operator: Equals
                          value: "https://alauda.io/builders/tekton/v1"
                          message: "The builder.id must be equal to https://alauda.io/builders/tekton/v1, not {{ builder.id }}"
    Пояснение полей YAML
    • Политика в целом соответствует политике из Проверка подписи образа. Ниже описаны только различия.
    • spec.rules[0].verifyImages[].attestations[0].conditions
      • type: тип slsa provenance — это https://slsa.dev/provenance/v0.2 или https://slsa.dev/provenance/v1.
      • attestors: как и выше.
      • conditions: условия, которые нужно проверить.
        • all: должны быть выполнены все условия.
          • key: "{{ builder.id }}": эта проверка убеждается, что поле builder.id в attestation равно https://alauda.io/builders/tekton/v1

    Нужно скорректировать конфигурацию

    • spec.rules[].attestors[].entries[].keys.publicKeys: публичный ключ signer.

    Сохраните политику в yaml-файл с именем kyverno.verify-tekton-built-images.yaml и примените ее:

    $ kubectl apply -f kyverno.verify-tekton-built-images.yaml
    
    clusterpolicy.kyverno.io/verify-tekton-built-images configured

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

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

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

    $ export NAMESPACE=<policy>
    $ export IMAGE=<<registry>/test/chains/demo-1:latest@sha256:93635f39cb31de5c6988cdf1f10435c41b3fb85570c930d51d41bbadc1a90046>
    
    $ kubectl run -n $NAMESPACE built --image=${IMAGE} -- sleep 3600
    
    pod/built created

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

    $ kubectl get pod -n $NAMESPACE built
    
    NAME      READY   STATUS    RESTARTS   AGE
    built   1/1     Running   0          10s

    Измените builder id в ClusterPolicy на другое значение https://alauda.io/builders/tekton/v2 и повторите проверку.

    conditions:
      - all:
          - key: "{{ builder.id }}"
            operator: Equals
            value: "https://alauda.io/builders/tekton/v2"
            message: "The builder.id must be equal to https://alauda.io/builders/tekton/v2, not {{ builder.id }}"
    $ kubectl run -n $NAMESPACE unbuilt --image=${IMAGE} -- sleep 3600

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

    Error from server: admission webhook "mutate.kyverno.svc-fail" denied the request:
    
    resource Pod/policy/unbuilt was blocked due to the following policies
    
    verify-tekton-built-images:
      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-1@sha256:93635f39cb31de5c6988cdf1f10435c41b3fb85570c930d51d41bbadc1a90046
        and predicate https://slsa.dev/provenance/v0.2: The builder.id must be equal to
        https://alauda.io/builders/tekton/v2, not https://alauda.io/builders/tekton/v1'

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

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

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

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

    $ kubectl delete clusterpolicy verify-tekton-built-images

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

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

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

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

    1. Настроить корректную изоляцию namespace и контроль доступа
    2. Реализовать безопасное управление ключами для ключей подписи
    3. Настроить мониторинг и оповещения о нарушениях политик
    4. Регулярно ротировать ключи подписи и обновлять политики безопасности
    5. Рассмотреть возможность внедрения дополнительных механизмов безопасности, таких как сканирование уязвимостей

    Ссылки