Yandex Cloud
Поиск
Связаться с экспертомПопробовать бесплатно
  • Кейсы
  • Документация
  • Блог
  • Все сервисы
    • Cloud Interconnect
    • Cloud Backup
    • Cloud Registry
    • Yandex AI Studio
    • Compute Cloud
    • Object Storage
    • Managed Service for Kubernetes®
    • Yandex BareMetal
    • Smart Web Security
    • Security Deck
    • Managed Service for PostgreSQL
    • Managed Service for ClickHouse®
    • Monium
    • Cloud CDN
    • Network Load Balancer
    • Virtual Private Cloud
    • Cloud DNS
    • Application Load Balancer
    • Yandex Cloud Video
    • Stackland
    • Yandex Cloud Router
    • Yandex Managed Service for Trino
    • Managed Service for MySQL®
    • Managed Service for Valkey™
    • Managed Service for Apache Spark™
    • Yandex StoreDoc
    • Managed Service for OpenSearch
    • Managed Service for Apache Kafka®
    • Data Transfer
    • Yandex MPP Analytics Engine for PostgreSQL
    • Yandex Managed Service for Apache Airflow®
    • Data Processing
    • Yandex MetaData Hub
    • Managed Service for YDB
    • Managed Service for Sharded PostgreSQL
    • Managed Service for YTsaurus
    • Yandex WebSQL
    • DataLens
    • Yandex Search API
    • SpeechSense
    • SpeechKit
    • DataSphere
    • Vision OCR
    • Translate
    • Yandex Neurosupport
    • VibeCraft
    • Yandex Cloud Detection and Response
    • Yandex Identity Hub
    • Key Management Service
    • Certificate Manager
    • Yandex Lockbox
    • Audit Trails
    • SmartCaptcha
    • Cloud Desktop
    • GOST Gateway
    • Yandex SIEM
    • SourceCraft Code Assistant
    • Container Registry
    • Managed Service for GitLab
    • SourceCraft
    • Managed Service for Prometheus®
    • Cloud Functions
    • API Gateway
    • Yandex Cloud Postbox
    • Message Queue
    • Serverless Integrations
    • IoT Core
    • Data Streams
    • Serverless Containers
    • Cloud Notification Service
    • Yandex Query
    • Identity and Access Management
    • Yandex Cloud Console
    • Resource Manager
    • Yandex Cloud Billing
    • Yandex Cloud Quota Manager
    • Cloud Apps
  • Статус работы сервисов
  • Marketplace
    • Популярные
    • Инфраструктура и сеть
    • Платформа данных
    • Искусственный интеллект
    • Безопасность
    • Инструменты DevOps
    • Бессерверные вычисления
    • Управление ресурсами
  • Все решения
    • По отраслям
    • По типу задач
    • Экономика платформы
    • Yandex Cloud Trust
    • Техническая поддержка
    • Каталог партнёров
    • Обучение и сертификация
    • Облако для стартапов
    • Облако для крупного бизнеса
    • Центр технологий для общества
    • Облако для интеграторов
    • Поддержка IT-бизнеса
    • Облако для фрилансеров
    • Обучение и сертификация
    • Блог
    • Документация
    • Контент-программа
    • Мероприятия и вебинары
    • Контакты, чаты и сообщества
    • Идеи
    • Калькулятор цен
    • Тарифы
    • Акции и free tier
  • Кейсы
  • Документация
  • Блог
Создавайте контент и получайте гранты!Готовы написать своё руководство? Участвуйте в контент-программе и получайте гранты на работу с облачными сервисами!
Подробнее о программе
Проект Яндекса
© 2026 ООО «Яндекс.Облако»
Yandex Cloud Stackland
  • Что нового
  • Установка
    • Все руководства
    • Установить Stackland на Yandex BareMetal
    • Установка Stackland на Yandex BareMetal через PXE
    • Установка Stackland на виртуальные машины в Yandex Cloud
    • Настройка внешнего доступа к поду в кластере
    • Проверка подписи собственных образов
    • Все инструкции
    • Проекты
    • Ресурсная модель
    • Масштабирование кластера
    • Лицензирование
  • Управление доступом
  • Правила тарификации
  • Диагностика и устранение неполадок

В этой статье:

  • Перед началом работы
  • Как это устроено
  • Шаг 1. Создайте пару ключей
  • Шаг 2. Подпишите образ
  • Шаг 3. Проверьте подпись локально
  • Шаг 4. Дайте Kyverno доступ к реестру
  • Шаг 5. Примените политику
  • Постепенное включение блокировки
  • Шаг 6. Проверьте работу политики
  • Ограничения
  1. Практические руководства
  2. Проверка подписи собственных образов

Проверка подписи собственных образов

Статья создана
Yandex Cloud
Обновлена 23 сентября 2026 г.
Открыть в Markdown
  • Перед началом работы
  • Как это устроено
  • Шаг 1. Создайте пару ключей
  • Шаг 2. Подпишите образ
  • Шаг 3. Проверьте подпись локально
  • Шаг 4. Дайте Kyverno доступ к реестру
  • Шаг 5. Примените политику
  • Постепенное включение блокировки
  • Шаг 6. Проверьте работу политики
  • Ограничения

Вы можете подписывать образы своих приложений и запретить кластеру запускать образы без действительной подписи. При создании пода подпись проверяет компонент Policy Manager, в основе которого лежит Kyverno. Подписи создает утилита Cosign.

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

Важно

Это руководство относится только к вашим собственным образам. У образов Stackland механизм другой: их целостность проверяет узел кластера при загрузке образа, отдельным ключом платформы. Ваш ключ, ваша политика и ваш секрет доступа к реестру никак не влияют на проверку образов платформы, а ключ платформы никогда не применяется к вашим образам.

Не добавляйте образы Stackland в свою политику: пространства имен платформы исключены из проверки, и такое правило не сработает.

Перед началом работыПеред началом работы

  1. Установите Cosign версии 3 или новее и crane.

    Команды в руководстве проверены на Cosign v3.1.3.

  2. Убедитесь, что у вас есть права на запись в реестр с вашими образами: подпись сохраняется в тот же репозиторий, что и образ.

  3. Убедитесь, что реестр доступен из кластера. Подпись проверяет Kyverno внутри кластера, поэтому он обращается в реестр сам, независимо от того, как образ загружает узел.

  4. Убедитесь, что Policy Manager включен:

    kubectl get policymanagerconfig main -o jsonpath='{.spec.enabled}'
    

    Если команда вернула false, включите компонент — см. Активировать пресет с политиками.

Как это устроеноКак это устроено

Cosign сохраняет подпись рядом с образом — отдельным тегом вида sha256-<digest>.sig в том же репозитории. Когда в кластере создается под, Kyverno перехватывает запрос, скачивает подпись из реестра и проверяет ее вашим публичным ключом. Если подписи нет или она не соответствует ключу, под не создается.

Проверка идет по цифровому отпечатку образа (digest), а не по тегу. Поэтому подписывать образ нужно тоже по digest: тег можно перезаписать, digest — нет.

Шаг 1. Создайте пару ключейШаг 1. Создайте пару ключей

  1. Задайте пароль для приватного ключа и создайте пару:

    export COSIGN_PASSWORD='<пароль приватного ключа>'
    cosign generate-key-pair
    

    Будут созданы два файла:

    • cosign.key — приватный ключ, которым вы подписываете образы;
    • cosign.pub — публичный ключ, которым Kyverno проверяет подписи.

Важно

cosign.key позволяет подписывать образы от вашего имени. Храните его в системе управления секретами или в секретах CI, не кладите в репозиторий с кодом и не создавайте из него ConfigMap. В политику Kyverno попадает только содержимое cosign.pub.

Шаг 2. Подпишите образШаг 2. Подпишите образ

  1. Получите digest образа:

    IMAGE_REPOSITORY='<адрес реестра>/<путь к образу>'
    IMAGE_TAG='<тег>'
    DIGEST=$(crane digest "${IMAGE_REPOSITORY}:${IMAGE_TAG}")
    IMAGE="${IMAGE_REPOSITORY}@${DIGEST}"
    
  2. Подпишите образ:

    cosign sign --yes \
      --key cosign.key \
      --use-signing-config=false \
      --new-bundle-format=false \
      --tlog-upload=false \
      "$IMAGE"
    

    Назначение флагов:

    • --tlog-upload=false — не отправлять запись во внешний журнал Rekor.
    • --use-signing-config=false — не использовать конфигурацию служб Sigstore. Без этого флага Cosign версии 3 запрещает --tlog-upload=false.
    • --new-bundle-format=false — сохранить подпись отдельным тегом sha256-<digest>.sig. По умолчанию Cosign версии 3 публикует подпись как артефакт OCI 1.1, который Kyverno этой версии не читает, а часть реестров отклоняет.

    Cosign выведет предупреждения о том, что --new-bundle-format и --tlog-upload объявлены устаревшими. Это ожидаемо: пока Kyverno работает с прежним форматом подписи, оба флага обязательны.

  3. Убедитесь, что подпись появилась в реестре:

    crane ls "$IMAGE_REPOSITORY" | grep '^sha256-'
    

    В выводе должен быть тег sha256-<digest>.sig, где <digest> совпадает с digest подписанного образа.

Шаг 3. Проверьте подпись локальноШаг 3. Проверьте подпись локально

Проверьте подпись прежде, чем настраивать политику, — так вы отделите ошибку подписи от ошибки в политике:

cosign verify --key cosign.pub --insecure-ignore-tlog "$IMAGE"

Для подписанного образа команда выведет результат проверки, для неподписанного — ошибку no signatures found.

Шаг 4. Дайте Kyverno доступ к рееструШаг 4. Дайте Kyverno доступ к реестру

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

kubectl create secret docker-registry my-registry-creds \
  --namespace stackland-policy-manager \
  --docker-server=<адрес реестра> \
  --docker-username=<имя пользователя> \
  --docker-password=<пароль или токен>

Примечание

Секрет должен находиться именно в пространстве имен stackland-policy-manager — Kyverno читает учетные данные только оттуда. Это не то же самое, что imagePullSecrets вашего пода: узел и Kyverno обращаются в реестр независимо друг от друга и используют разные учетные данные.

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

Шаг 5. Примените политикуШаг 5. Примените политику

Манифест ниже использует безопасный режим отчетов: failureAction: Audit, mutateDigest: false и webhookConfiguration.failurePolicy: Ignore. После применения политика регистрирует нарушения, но не блокирует создание подов. Блокировку вы включите постепенно после проверки политики и доступа к реестру.

  1. Создайте файл ресурса ClusterPolicy. Например, с помощью команды touch clusterpolicy.yaml.

  2. Откройте файл и вставьте конфигурацию ниже:

    apiVersion: kyverno.io/v1
    kind: ClusterPolicy
    metadata:
      name: verify-my-images
    spec:
      admission: true
      background: true
      webhookConfiguration:
        failurePolicy: Ignore
      rules:
      - name: verify-signature
        match:
          any:
          - resources:
              kinds:
              # Pod only: Kyverno generates rules for Deployment, StatefulSet, DaemonSet, Job, and CronJob.
              # Adding these kinds here disables autogeneration.
              - Pod
              # namespaceSelector:
              #   matchLabels:
              #     stackland.yandex.cloud/project-name: <project-name>
        exclude:
          any:
          - resources:
              namespaceSelector:
                matchLabels:
                  # Platform namespaces are verified on the node, not by this policy.
                  stackland.yandex.cloud/project-name: stackland
        verifyImages:
        - imageReferences:
          # Match only customer-owned paths. Never use * here.
          - <адрес реестра>/<путь к вашим образам>/*
          failureAction: Audit
          type: Cosign
          mutateDigest: false
          verifyDigest: true
          required: true
          useCache: true
          imageRegistryCredentials:
            secrets:
            # The Secret must exist in the stackland-policy-manager namespace.
            - my-registry-creds
          attestors:
          - count: 1
            entries:
            - keys:
                publicKeys: |-
                  -----BEGIN PUBLIC KEY-----
                  <содержимое файла cosign.pub>
                  -----END PUBLIC KEY-----
                signatureAlgorithm: sha256
                rekor:
                  ignoreTlog: true
                ctlog:
                  ignoreSCT: true
    
  3. Подставьте в параметр:

    • spec.rules[0].verifyImages[0].imageReferences — пути к вашим образам.
    • spec.rules[0].verifyImages[0].imageRegistryCredentials.secrets — имя секрета из шага 4. Если реестр не требует аутентификации, удалите блок imageRegistryCredentials.
    • spec.rules[0].verifyImages[0].attestors[0].entries[0].keys.publicKeys — содержимое файла cosign.pub.

    По умолчанию политика проверяет образы во всех пространствах имен всех проектов, кроме пространств имен платформы. Блок exclude с меткой stackland.yandex.cloud/project-name: stackland исключает пространства имен платформы независимо от их имени.

    Чтобы проверять образы только в пространствах имен одного проекта, раскомментируйте в match блок namespaceSelector и укажите название проекта:

    match:
      any:
      - resources:
          kinds:
          - Pod
          namespaceSelector:
            matchLabels:
              stackland.yandex.cloud/project-name: <название проекта>
    
  4. Примените политику в режиме отчетов:

    kubectl apply -f clusterpolicy.yaml
    
  5. Убедитесь, что политика готова:

    kubectl get clusterpolicy verify-my-images -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}'
    

    Ожидаемый результат — True.

Внимание

Не указывайте * в imageReferences. С параметром required: true политика потребует подпись у всех образов, включая служебные и сторонние, и поды перестанут создаваться. Перечисляйте только те пути, образы по которым подписываете сами.

Постепенное включение блокировкиПостепенное включение блокировки

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

  1. Убедитесь, что в консоли управления в разделе Система > События нет неожиданных нарушений, и одновременно включите блокировку неподписанных образов и замену тегов на digest. Ошибки обращения к реестру пока останутся неблокирующими:

    kubectl patch clusterpolicy verify-my-images --type=json --patch='[
      {
        "op": "replace",
        "path": "/spec/rules/0/verifyImages/0/failureAction",
        "value": "Enforce"
      },
      {
        "op": "replace",
        "path": "/spec/rules/0/verifyImages/0/mutateDigest",
        "value": true
      }
    ]'
    
  2. Убедитесь, что обращения в реестр стабильны, и включите блокировку при ошибках проверки:

    kubectl patch clusterpolicy verify-my-images --type=json --patch='[
      {
        "op": "replace",
        "path": "/spec/webhookConfiguration/failurePolicy",
        "value": "Fail"
      }
    ]'
    

    Политика перейдет в финальный режим Enforce и Fail.

Шаг 6. Проверьте работу политикиШаг 6. Проверьте работу политики

В командах ниже <имя пространства имен> — имя конкретного пространства имен из области действия политики, например team-alpha-backend.

  1. Запустите под с подписанным образом:

    kubectl run test-signed -n <имя пространства имен> --restart=Never \
      --image=<адрес реестра>/<путь к образу>:<тег>
    

    Под будет создан. Проверьте, что Kyverno заменил тег на digest и отметил проверку аннотацией:

    kubectl get pod test-signed -n <имя пространства имен> \
      -o jsonpath='{.spec.containers[0].image}{"\n"}{.metadata.annotations.kyverno\.io/verify-images}{"\n"}'
    

    Пример вывода:

    registry.example.com/myteam/app:1.0.0@sha256:7c38f24774e3cbd906d2d33c38354ccf787635581c122965132c9bd309754d4a
    {"registry.example.com/myteam/app@sha256:7c38f24774e3cbd906d2d33c38354ccf787635581c122965132c9bd309754d4a":"pass"}
    
  2. Запустите под с неподписанным образом:

    kubectl run test-unsigned -n <имя пространства имен> --restart=Never \
      --image=<адрес реестра>/<путь к образу>:<тег неподписанного образа>
    

    Под создан не будет:

    Error from server: admission webhook "mutate.kyverno.svc-fail" denied the request:
    
    resource Pod/<имя пространства имен>/test-unsigned was blocked due to the following policies
    
    verify-my-images:
      verify-signature: 'failed to verify image registry.example.com/myteam/app:unsigned:
        .attestors[0].entries[0].keys: no signatures found'
    
  3. Удалите тестовый под:

    kubectl delete pod test-signed -n <имя пространства имен>
    

ОграниченияОграничения

  • Реестр становится зависимостью при создании подов. В режиме failurePolicy: Fail недоступность реестра или просроченные учетные данные останавливают создание подов с образами, попадающими под политику. Кеш проверок и узкий список imageReferences ограничивают последствия, но не устраняют их.
  • Политика удаляется вместе с компонентом. Если отключить Policy Manager (PolicyManagerConfig.spec.enabled: false), политика и секрет с учетными данными реестра будут удалены. После повторного включения создайте их заново.

Была ли статья полезна?

Предыдущая
Настройка внешнего доступа к поду в кластере
Следующая
Все инструкции
Создавайте контент и получайте гранты!Готовы написать своё руководство? Участвуйте в контент-программе и получайте гранты на работу с облачными сервисами!
Подробнее о программе
Проект Яндекса
© 2026 ООО «Яндекс.Облако»