cosign: подпись и проверка образов Docker перед запуском

0
7
Обложка статьи: cosign: подпись и проверка образов Docker перед запуском

Trivy отвечает на вопрос «есть ли в образе известные уязвимости». Отдельный вопрос — тот ли это вообще образ, который собрала ваша сборка, или кто-то подменил его в реестре или по дороге. cosign закрывает именно это: подписывает образ при публикации и проверяет подпись перед запуском. Ниже порядок и результаты проверки.

Статья опирается на логику направления «Управление уязвимостями» из методики зрелости Группы Сбер (источник); это методика для крупных компаний, мы используем её как ориентир и пересказываем своими словами. Проверка выполнена с cosign 2.4.1 на тестовом реестре в контейнере, после неё всё удалено.

Что должно получиться

Уровень Что это значит на практике
2. Гигиенический Образы, собираемые конвейером, подписываются, а при развёртывании проверяется, что образ подписан известным ключом и не подменён

Критерии сформулированы нами по мотивам методики, это ориентир, а не оценка соответствия.

Ключи и подпись

cosign generate-key-pair
# Private key written to cosign.key
# Public key written to cosign.pub

Приватный ключ (cosign.key) хранится у сборочного конвейера (в хранилище секретов, не в репозитории), публичный (cosign.pub) распространяется всем, кто проверяет образы — секретности он не требует. Подпись при публикации:

cosign sign --key cosign.key --yes РЕЕСТР/образ:тег

Команда требует доступа к реестру (та же авторизация, что для docker push) и пишет подпись туда же, рядом с образом, отдельным объектом. Для своего приватного реестра без публичного журнала прозрачности добавляйте --yes для автоматизации и, при необходимости, ключ хранения пароля через переменную окружения COSIGN_PASSWORD.

Проверка перед запуском

cosign verify --key cosign.pub РЕЕСТР/образ:тег

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

Результат проверки

Сценарий Результат
Проверка подписанного образа верным ключом Успех: «The signatures were verified against the specified public key»
Проверка тем же образом, подписанным другим ключом Отказ: «no matching signatures: invalid signature when validating ASN.1 encoded signature»
Проверка образа, который не подписывали вовсе (другое содержимое под тем же именем) Отказ: «no signatures found»
Публикация без изменения содержимого под новым тегом Проверка нового тега проходит успешно без повторной подписи

Последняя строка — не ошибка, а важная деталь устройства: cosign привязывает подпись к цифровому отпечатку (digest) содержимого образа, а не к тегу. Если под новым тегом оказался байт-в-байт тот же образ, у него тот же отпечаток, и ранее сделанная подпись к нему по-прежнему относится. А вот тег с действительно другим содержимым подписи не наследует: проверка на нём честно возвращает «no signatures found», даже если имя образа и тег выглядят знакомо.

Порядок внедрения

  1. Создайте ключевую пару для конвейера сборки, приватный ключ — в хранилище секретов CI, не в репозитории.
  2. Подписывайте образ последним шагом сборки, после прохождения проверок (статический анализ, сканирование уязвимостей) — подпись удостоверяет «этот образ прошёл наш конвейер», а не просто «мы его собрали».
  3. Распространите публичный ключ на все площадки, где образы разворачиваются.
  4. Добавьте обязательную проверку перед развёртыванием, с остановкой при отказе, а не предупреждением в журнале.
  5. Сверяйте по отпечатку, а не только по тегу, если нужна максимальная строгость: тег можно переставить на другой образ, отпечаток — нет.

Диагностика

Симптом Причина и что делать
permission denied при записи ключей или подписи Образ cosign запускается от непривилегированного пользователя (контейнер без прав root). Дайте процессу право записи в рабочий каталог или запускайте с подходящим пользователем
Предупреждение про тег вместо отпечатка при подписи Это ожидаемое предупреждение cosign: подписывать лучше по отпечатку (образ@sha256:…), чтобы точно знать, что именно подписано
Проверка проходит для образа, который вы не подписывали Образ под новым тегом оказался байт-в-байт тем же, что уже подписанный (одинаковый отпечаток). Это не ошибка, а свойство адресации по содержимому
Проверка без --insecure-ignore-tlog уходит в публичный журнал прозрачности По умолчанию cosign пишет запись в публичный Rekor. Для приватных образов без публичного журнала используйте отдельный приватный журнал или заведомо офлайн-режим — обычное использование сигнатур поверх своего реестра этого не требует

Ограничения

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

Где это в модели зрелости

Материал относится к направлению «Управление уязвимостями» (материалы направления, карта зрелости). Уровень 2 требует контроля над тем, что реально развёртывается: подпись образов закрывает конкретный риск — подмену образа между сборкой и запуском, — который сканирование уязвимостей само по себе не ловит.

Как проверить

  1. Каждый образ, выходящий из конвейера сборки, подписан ключом конвейера.
  2. Развёртывание проверяет подпись и останавливается при её отсутствии или несовпадении.
  3. Приватный ключ хранится в защищённом хранилище секретов, а не в репозитории и не в журналах сборки.
  4. Есть процедура на случай компрометации ключа: немедленная замена пары и пересборка затронутых образов.

Источники

  • Методика оценки уровня зрелости кибербезопасности компании, Группа Сбер: sberbank.ru.
  • Документация cosign (проект Sigstore): docs.sigstore.dev; исходный код: github.com/sigstore/cosign.

Комментарии закрыты.