• Русский
  • Проверка репозитория исходного кода

    В Tekton Chains он может собирать определённые входные и выходные данные из PipelineRun и записывать их в SLSA Provenance.

    TIP

    Дополнительные сведения см. в разделе Tekton Chains Type Hinting выше.

    Эту возможность можно использовать для включения информации о репозитории исходного кода в данные SLSA Provenance. Затем можно выполнить проверку репозитория исходного кода в Kyverno.

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

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

    1. Настроить Tekton Chains для автоматической генерации SLSA Provenance для собранного образа.
    2. Использовать git Tekton Task для получения репозитория исходного кода.
    3. Использовать buildah Tekton Task для сборки образа.
    4. Объявить сведения о результатах git и buildah в результатах Pipeline. Это позволяет записывать репозиторий исходного кода и сведения о коммите для образа.
    5. Настроить правила Kyverno для проверки репозитория исходного кода.
    6. Использовать образ для создания Pod, чтобы выполнить проверку репозитория исходного кода.

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

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

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

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

    • Кластер 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 и подпись, отключить TaskRun SLSA Provenance
    4Создать пример PipelineСоздать определение pipeline с task для git clone и task buildah
    5Запустить пример PipelineСоздать и запустить PipelineRun с корректной конфигурацией
    6Дождаться подписиДождаться, пока PipelineRun будет подписан Chains
    7Получить сведения об образеИзвлечь URI и digest образа из PipelineRun
    8(Необязательно) Получить SLSA ProvenanceПолучить и проверить attestation SLSA Provenance
    9Проверить с помощью KyvernoСоздать и применить политику Kyverno для проверки репозитория исходного кода образа
    10ОчиститьУдалить тестовые ресурсы и политики

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

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

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

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

    В предыдущем image build pipeline добавьте task git clone и сохраните вывод task git в results PipelineRun.

    apiVersion: tekton.dev/v1
    kind: Pipeline
    metadata:
      name: chains-demo-3
    spec:
      params:
        - default: |-
            echo "Simulate cloning the code and write the repository URL and commit message into the results."
    
            # This commit sha must be a valid commit sha [0-9a-f]{40}.
            cat << 'EOF' > $(results.array-result.path)
            [
              "https://github.com/tektoncd/pipeline",
              "cccccaaaa0000000000000000000000000000000"
            ]
            EOF
    
            echo -e "\nResults:"
            echo "-------------------"
            cat $(results.array-result.path)
            echo "-------------------"
            echo -e "\nClone successfully!"
          description: A script to simulate cloning the code and write the repository URL and commit message into the results.
          name: generate-git-clone-results
          type: string
        - 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-3: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)
        - description: first repo artifact input
          name: source_repo_ARTIFACT_INPUTS
          type: object
          value:
            digest: sha1:$(tasks.git-clone.results.array-result[1])
            uri: $(tasks.git-clone.results.array-result[0])
      tasks:
        - name: git-clone
          params:
            - name: script
              value: $(params.generate-git-clone-results)
          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: generate-containerfile
          params:
            - name: script
              value: $(params.generate-containerfile)
          runAfter:
            - git-clone
          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
      workspaces:
        - name: source
          description: The workspace for source code.
        - name: registryconfig
          description: The workspace for distribution registry configuration.
    TIP

    В этом руководстве демонстрируется упрощённый рабочий процесс, в котором Containerfile и вывод task git-clone создаются непосредственно внутри pipeline. В production-окружениях обычно:

    1. Используют task git-clone для получения исходного кода из репозитория
    2. Собирают образ с помощью Containerfile, который уже существует в исходном коде
    3. Такой подход обеспечивает корректное управление версиями и сохраняет разделение между кодом и конфигурацией pipeline
    Пояснение полей YAML
    • Большинство полей совпадает с Шаг 4: Создать пример Pipeline. Ниже описаны только различия.
    • params
      • generate-git-clone-results: Скрипт для имитации клонирования кода и записи URL репозитория и сообщения коммита в results.
    • results
      • source_repo_ARTIFACT_INPUTS: URL репозитория исходного кода и сообщение коммита.
        • digest: Commit sha репозитория исходного кода.
      • Этот формат совместим с Tekton Chains; см. Tekton Chains Type Hinting в разделе выше для получения дополнительных сведений.

    Требуется скорректировать конфигурацию

    • params:
      • generate-containerfile
        • default: Скорректируйте адрес исходного образа.
      • image:
        • default: Адрес целевого собираемого образа.

    Сохраните это в yaml-файл с именем chains.demo-3.pipeline.yaml и примените его с помощью:

    $ export NAMESPACE=<default>
    $ kubectl apply -n $NAMESPACE -f chains.demo-3.pipeline.yaml

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

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

    apiVersion: tekton.dev/v1
    kind: PipelineRun
    metadata:
      generateName: chains-demo-3-
    spec:
      pipelineRef:
        name: chains-demo-3
      taskRunTemplate:
        serviceAccountName: <default>
      workspaces:
        - name: registryconfig
          secret:
            secretName: <registry-credentials>
        - name: source
          volumeClaimTemplate:
            spec:
              accessModes:
                - ReadWriteOnce
              resources:
                requests:
                  storage: 1Gi
              storageClassName: <nfs>
    Пояснение полей YAML

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

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

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

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

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

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

    $ export NAMESPACE=<default>
    $ export PIPELINERUN_NAME=<chains-demo-3-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-3:latest@sha256:93635f39cb31de5c6988cdf1f10435c41b3fb85570c930d51d41bbadc1a90046

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

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

    TIP

    Если вам интересен содержимое attestation SLSA Provenance, вы можете продолжить чтение ниже.

    Дополнительные сведения об attestation SLSA Provenance см. в SLSA Provenance

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

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

    Вывод будет похож на следующий и содержит attestation SLSA Provenance.

    Attestation SLSA Provenance
    {
      "_type": "https://in-toto.io/Statement/v0.1",
      "subject": [
        {
          "name": "<registry>/test/chains/demo-3:latest",
          "digest": {
            "sha256": "db2607375049e8defa75a8317a53fd71fd3b448aec3c507de7179ded0d4b0f20"
          }
        }
      ],
      "predicateType": "https://slsa.dev/provenance/v0.2",
      "predicate": {
        "buildConfig": {
          "tasks": null
        },
        "buildType": "tekton.dev/v1beta1/PipelineRun",
        "builder": {
          "id": "https://alauda.io/builders/tekton/v1"
        },
        "invocation": {
          "parameters": {
            "image": "<registry>/test/chains/demo-3:latest"
          }
        },
        "materials": [
          {
            "digest": {
              "sha256": "bad5d84ded24307d12cacc9ef37fc38bce90ea5d00501f43b27d0c926be26f19"
            },
            "uri": "oci://<registry>/devops/tektoncd/hub/run-script"
          },
          {
            "digest": {
              "sha1": "cccccaaaa0000000000000000000000000000000"
            },
            "uri": "https://github.com/tektoncd/pipeline"
          }
        ],
        "metadata": {
          "buildFinishedOn": "2025-06-06T10:28:21Z",
          "buildStartedOn": "2025-06-06T10:27:34Z"
        }
      }
    }
    Описание полей
    • predicateType: Тип predicate.
    • predicate:
      • buildConfig:
        • tasks: Tasks сборки.
      • buildType: Тип сборки, это tekton.dev/v1beta1/PipelineRun.
      • builder:
        • id: Идентификатор builder, это https://alauda.io/builders/tekton/v1.
      • invocation:
        • parameters: Параметры сборки.
      • materials: Материалы сборки.
        • uri:
          • oci://<registry>/devops/tektoncd/hub/run-script: Используемый образ task.
          • https://github.com/tektoncd/pipeline: Репозиторий исходного кода task.
      • metadata: Метаданные сборки.
        • buildFinishedOn: Время завершения сборки.
        • buildStartedOn: Время начала сборки.

    Шаг 9: Проверить ограничение источника образа с помощью Kyverno

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

    TIP

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

    Дополнительные сведения о Kyverno ClusterPolicy см. в Kyverno ClusterPolicy

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

    apiVersion: kyverno.io/v1
    kind: ClusterPolicy
    metadata:
      name: verify-code-repository-material
    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: "{{ buildType }}"
                          operator: Equals
                          value: "tekton.dev/v1beta1/PipelineRun"
                          message: "The buildType must be equal to tekton.dev/v1beta1/PipelineRun, not {{ buildType }}"
    
                        - key: "{{ materials[?starts_with(uri, 'https://github.com/tektoncd/')] | length(@) }}"
                          operator: GreaterThan
                          value: 0
                          message: "The materials must have at least one entry starts with https://github.com/tektoncd/, {{ materials }}"
    Пояснение полей YAML
    • Политика в основном соответствует политике из Image Signature Verification
    • spec.rules[].verifyImages[].attestations[].conditions: Условия для проверки.
      • all: Должны быть выполнены все условия.
        • key: "{{ buildType }}": Тип сборки должен быть равен tekton.dev/v1beta1/PipelineRun.
        • key: "{{ materials[?starts_with(uri, 'https://github.com/tektoncd/')] | length(@) }}": Среди материалов должен быть как минимум один элемент, начинающийся с https://github.com/tektoncd/.

    Сохраните это в yaml-файл с именем verify-code-repository-material.yaml и примените его с помощью:

    $ kubectl create -f verify-code-repository-material.yaml
    
    clusterpolicy.kyverno.io/verify-code-repository-material created

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

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

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

    $ export NAMESPACE=<policy>
    $ export IMAGE=<<registry>/test/chains/demo-3:latest@sha256:db2607375049e8defa75a8317a53fd71fd3b448aec3c507de7179ded0d4b0f20>
    
    $ kubectl run -n $NAMESPACE built-from-specific-repo --image=${IMAGE} -- sleep 3600
    
    pod/built-from-specific-repo created

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

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

    Измените репозиторий исходного кода в ClusterPolicy на другое значение https://gitlab.com/ и выполните проверку снова.

    conditions:
      - all:
          - key: "{{ buildType }}"
            operator: Equals
            value: "tekton.dev/v1beta1/PipelineRun"
            message: "The buildType must be equal to tekton.dev/v1beta1/PipelineRun, not {{ buildType }}"
    
          - key: "{{ materials[?starts_with(uri, 'https://gitlab.com/')] | length(@) }}"
            operator: GreaterThan
            value: 0
            message: "The materials must have at least one entry starts with https://gitlab.com/, {{ materials }}"
    $ kubectl run -n $NAMESPACE unbuilt-from-specific-repo --image=${IMAGE} -- sleep 3600

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

    Error from server: admission webhook "mutate.kyverno.svc-fail" denied the request:
    
    resource Pod/policy/unbuilt-from-specific-repo was blocked due to the following policies
    
    verify-code-repository-material:
      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-3:latest and predicate https://slsa.dev/provenance/v0.2:
        The materials must have at least one entry starts with https://gitlab.com/,
        [{"digest":{"sha256":"bad5d84ded24307d12cacc9ef37fc38bce90ea5d00501f43b27d0c926be26f19"},"uri":"oci://<registry>/devops/tektoncd/hub/run-script"},{"digest":{"sha256":"7a63e6c2d1b4c118e9a974e7850dd3e9321e07feec8302bcbcd16653c512ac59"},"uri":"http://tekton-hub-api.tekton-pipelines:8000/v1/resource/catalog/task/run-script/0.1/yaml"},{"digest":{"sha256":"8d5ea9ecd9b531e798fecd87ca3b64ee1c95e4f2621d09e893c58ed593bfd4c4"},"uri":"oci://<registry>/devops/tektoncd/hub/buildah"},{"digest":{"sha256":"3225653d04c223be85d173747372290058a738427768c5668ddc784bf24de976"},"uri":"http://tekton-hub-api.tekton-pipelines:8000/v1/resource/catalog/task/buildah/0.9/yaml"},{"digest":{"sha1":"cccccaaaa0000000000000000000000000000000"},"uri":"https://github.com/tektoncd/pipeline"}]'

    Шаг 10: Очистить ресурсы

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

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

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

    $ kubectl delete clusterpolicy verify-code-repository-material

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

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

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

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

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

    Ссылки