Модифицирующие политики

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

Kyverno поддерживает реализацию модифицирующих политик, которые позволяют изменять объекты перед запуском, в том числе предотвращать запуск уязвимых контейнеров.

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

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

В открытом контуре ключи и метаданные подписей обычно загружаются из общедоступных источников (OCI-реестр, URL); в закрытом — ключи и конфигурация политик проверки подписей (например, для Cosign) должны быть доставлены в контур вручную или через утверждённый канал.

Обратите внимание! При настройке политики неймспейсы системных компонентов необходимо добавлять в исключения!

Подготовка

Для подписи образов необходимо:

  1. Установить Cosign:
curl -sSL https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64 -o /usr/local/bin/cosign
chmod +x /usr/local/bin/cosign
  1. Сгенерировать ключевую пару, которая впоследствии будет использована для подписи образов (можно использовать существующую):
cosign generate-key-pair

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

  1. Подписать образ контейнера с использованием закрытого (приватного) ключа, созданного на предыдущем этапе:
cosign sign --key cosign.key --tlog-upload=false $IMAGE

При использовании локальных реестров образов может понадобиться флаг --allow-insecure-registry=true.

Публичный ключ, полученный на этом этапе, необходимо добавить в манифест политики, а приватный - передать разработчику для подписи образов или девопсу для добавления в pipeline.

  1. Просканировать образ и получить отчет:
trivy image --ignore-unfixed --format cosign-vuln --output $FILE_NAME.json $IMAGE
  1. Добавить аттестацию (отчет, полученный на предыдущем этапе):
cosign attest --key cosign.key --tlog-upload=false --type vuln --predicate $FILE_NAME.json $IMAGE 

При использовании локальных реестров образов может понадобиться флаг --allow-insecure-registry=true.

Установите в целевой кластер политику по шагам импорта манифеста в менеджере политик безопасности.

Проверка подписи контейнера

Вместо текста “публичный ключ” вставьте публичный ключ, полученный на шаге 3. В блок imageReferences введите адрес вашего registry (реестра образов).

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  annotations:
    policies.kyverno.io/category: infosec
    policies.kyverno.io/description: Проверка подписи образа позволяет
      контролировать его целостность и запускать контейнеры только из
      проверенных и доверенных образов
    policies.kyverno.io/severity: High
    policies.kyverno.io/title: Image Signature Checker
  name: image-sign-check
spec:
  validationFailureAction: Enforce
  background: false
  rules:
    - name: check-image
      match:
        any:
        - resources:
            kinds:
              - Pod
      verifyImages:
      - imageReferences:
        - "*"
        attestors:
        - count: 1
          entries:
          - keys:
              publicKeys: |-
                -----BEGIN PUBLIC KEY-----
                публичный ключ
                -----END PUBLIC KEY-----                
              rekor:
                ignoreTlog: true
                url: https://rekor.sigstore.dev
              ctlog:
                ignoreSCT: true
          - keys:
              publicKeys: |-
                -----BEGIN PUBLIC KEY-----
                публичный ключ
                -----END PUBLIC KEY-----                
              rekor:
                ignoreTlog: true
                url: https://rekor.sigstore.dev
              ctlog:
                ignoreSCT: true

После этого, при запуске, образы будут проверяться перед запуском.

Блокировка подов с критическими уязвимостями

Вместо текста “публичный ключ” вставьте публичный ключ, полученный на шаге 3. В блок imageReferences введите адрес вашего registry (реестра образов).

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: image-vuln-check
  annotations:
    policies.kyverno.io/title: Image Vulnerability Checker
    policies.kyverno.io/category: "infosec"
    policies.kyverno.io/severity: High
    policies.kyverno.io/description: >-
      Хорошей практикой считается не запускать образы контейнеров, которые содержат уязвимости,
      например, уровня High и Critical. При помощи указанной политики можно контролировать максимально
      допустимый уровень CVSSv3 Score, которым могут обладать уязвимости в запускаемом контейнере.      
spec:
  validationFailureAction: "Enforce"
  background: true
  schemaValidation: true
  failurePolicy: "Fail"
  webhookTimeoutSeconds: 10
  rules:
    - name: image-vuln-check
      match:
        any:
        - resources:
            kinds:
            - Pod
      verifyImages:
      - imageReferences:
        - my.test.registry/*
        mutateDigest: false
        verifyDigest: false
        attestations:
          - type: https://cosign.sigstore.dev/attestation/vuln/v1
            attestors:
            - entries:
              - keys:
                  publicKeys:                    |-
                      -----BEGIN PUBLIC KEY-----
                      публичный ключ
                      -----END PUBLIC KEY-----                      
                  rekor:
                    ignoreTlog: true
                    url: https://rekor.sigstore.dev
                    pubkey:                    |-
                      -----BEGIN PUBLIC KEY-----
                      публичный ключ
                      -----END PUBLIC KEY-----                      
                  ctlog:
                    pubkey:                    |-
                      -----BEGIN PUBLIC KEY-----
                      публичный ключ
                      -----END PUBLIC KEY-----                      
            conditions:
              - any:
                - key: "{{ scanner.result.Results[].Vulnerabilities[?CVSS.nvd.V3Score > `7`][] | length(@) }}"
                  message: "Было найдено: {{ scanner.result.Results[].Vulnerabilities[?CVSS.nvd.V3Score > `7`][] | length(@) | to_string(@) }} уязвимости(тей) с оценкой больше 7 по CVSSv3 Score"
                  operator: Equals
                  value: 0