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

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

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

    TIP

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

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

    Обзор функции

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

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

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

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

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

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

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

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

    ШагОперацияОписание
    1Генерация ключей подписиСоздание пары ключей для подписания артефактов с помощью cosign
    2Настройка аутентификацииКонфигурация учётных данных реестра для пуша образов
    3Настройка Tekton ChainsНастройка Chains для использования OCI-хранилища и подписи
    4Создание примерного пайплайнаСоздание определения пайплайна с необходимыми задачами и рабочими областями
    5Запуск примерного пайплайнаСоздание и запуск PipelineRun с правильной конфигурацией
    6Ожидание подписиОжидание подписания PipelineRun Chains
    7Получение информации об образеИзвлечение URI и дайджеста образа из PipelineRun
    8(Опционально) Проверка подписей с cosignПроверка аттестации образа с помощью cosign CLI
    9Проверка подписей с KyvernoКонфигурация и проверка аттестации образа с помощью политик Kyverno
    10Очистка ресурсовУдаление тестовых Pod и политик

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

    Шаги 1-7: (Опционально) Базовая настройка

    NOTE

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

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

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

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

    TIP

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

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

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

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

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

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

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

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

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

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

    # Отключить загрузку tlog и включить приватную инфраструктуру
    $ 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
    
    # Определяем разрешённый builder.id
    allowed_builder_id = "https://alauda.io/builders/tekton/v1"
    
    # Проверяем builder.id
    allow {
        # Проверяем, что builder.id в предикате равен разрешённому значению
        input.predicate.builder.id == allowed_builder_id
    }
    
    # Возвращаем сообщение об ошибке, если не совпадает
    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.

    # Отключить загрузку tlog и включить приватную инфраструктуру
    $ 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

    Для выполнения этого шага требуются права администратора кластера.

    Содержимое 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:
                  # Учетные данные должны существовать в namespace, где развернут kyverno
                  - registry-credentials
    
              attestations:
                - type: https://slsa.dev/provenance/v0.2
                  attestors:
                    - entries:
                        - keys:
                            publicKeys: |- # <- Публичный ключ подписанта
                              -----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
    • Политика в основном совпадает с той, что в Image Signature Verification. Здесь описаны только отличия.
    • 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 в аттестации равно https://alauda.io/builders/tekton/v1

    Необходимо отредактировать конфигурацию

    • spec.rules[].attestors[].entries[].keys.publicKeys: публичный ключ подписанта.

    Сохраните политику в 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: Очистка ресурсов

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

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

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

    $ kubectl delete clusterpolicy verify-tekton-built-images

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

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

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

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

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

    Ссылки