Что такое подпись и верификация образов?
Подпись образов – это криптографический механизм, гарантирующий, что контейнерный образ создан доверенным источником и не был изменён (не был подменён или скомпрометирован) с момента сборки.
Аналогия: подпись образа – как сургучная печать на письме. Она подтверждает отправителя и гарантирует, что содержимое не вскрывали в пути.
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, а не по тегу – это частая ошибка, которую интервьюер проверяет.