Gymterview
middle

Что такое подпись и верификация образов?

Подпись образов – это криптографический механизм, гарантирующий, что контейнерный образ создан доверенным источником и не был изменён (не был подменён или скомпрометирован) с момента сборки.

Аналогия: подпись образа – как сургучная печать на письме. Она подтверждает отправителя и гарантирует, что содержимое не вскрывали в пути.

Docker Content Trust (DCT)

DCT использует Notary для подписи тегов образов:

Пример
# Включить обязательную верификацию подписей
export DOCKER_CONTENT_TRUST=1

# При push Docker автоматически подпишет образ
docker push registry.bank.local/banking-service:1.0.0

# При pull Docker откажется скачивать неподписанный образ
docker pull registry.bank.local/banking-service:1.0.0

При первом использовании DCT генерируются два ключа: root key (хранить в офлайн-хранилище, например HSM) и repository key (используется для подписи конкретного репозитория).

Cosign (Sigstore) – современный стандарт

Cosign – более современный инструмент, активно вытесняющий DCT благодаря простоте и поддержке keyless-подписи через OIDC.

Пример
# Генерация ключевой пары
cosign generate-key-pair

# Подпись образа (всегда по digest, не по тегу!)
cosign sign --key cosign.key registry.bank.local/banking-service@sha256:abc123...

# Верификация подписи
cosign verify --key cosign.pub registry.bank.local/banking-service@sha256:abc123...

# Keyless-подпись через OIDC/Fulcio (без локальных ключей)
cosign sign registry.bank.local/banking-service@sha256:abc123...

Верификация в Kubernetes с помощью Kyverno

Kyverno – policy engine, который может блокировать запуск подов с неподписанными образами:

Пример ClusterPolicy для верификации подписей
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image-signature
spec:
  validationFailureAction: Enforce
  background: false
  rules:
  - name: check-cosign-signature
    match:
      any:
      - resources:
          kinds:
          - Pod
    verifyImages:
    - imageReferences:
      - "registry.bank.local/*"
      attestors:
      - count: 1
        entries:
        - keys:
            publicKeys: |-
              -----BEGIN PUBLIC KEY-----
              MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
              -----END PUBLIC KEY-----

Эта политика запретит запуск любого пода с образом из registry.bank.local, если образ не подписан соответствующим ключом. Альтернативный admission controller – Connaisseur.

Интеграция подписи в CI/CD

Пример GitHub Actions с Cosign
- name: Sign image with Cosign
  run: |
    cosign sign \
      --key env://COSIGN_PRIVATE_KEY \
      --yes \
      registry.bank.local/banking-service@${{ steps.build.outputs.digest }}
  env:
    COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_KEY }}
    COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}

Подпись по digest vs по тегу

Способ ссылки Пример Безопасность
По тегу registry/app:1.0.0 Тег можно переназначить на другой образ
По digest registry/app@sha256:abc123... Неизменная ссылка на конкретный контент

Всегда подписывать по digest (@sha256:...), а не по тегу.

Вывод

Подпись образов – обязательная практика для production-окружений. Cosign (Sigstore) стал де-факто стандартом. В связке с Kyverno или Connaisseur в Kubernetes можно гарантировать, что ни один неподписанный образ не попадёт в кластер.

На собеседовании: объясните разницу между DCT и Cosign, упомяните keyless-подпись через OIDC. Обязательно скажите, что подписывать нужно по digest, а не по тегу – это частая ошибка, которую интервьюер проверяет.