open atlas
↑ К треку
CI/CD-пайплайны CICD · 05 · 01

SBOM, build provenance и подпись: докажи, что отгружаешь

SBOM инвентаризирует каждую зависимость, чтобы ответить «затронуты ли мы CVE-X?» за минуты; provenance и SLSA доказывают, кто и как собрал артефакт; keyless-подпись cosign плюс аттестация, проверенная на деплое, превращают всё это из бумажки в шлагбаум.

CICD Senior ◷ 17 min
Уровень
ОсновыJuniorMiddleSenior

В пятницу выходит CVE: бэкдор в широко используемой библиотеке сжатия, из тех, что активируются только внутри сборки. Руководство задаёт единственный важный вопрос — «мы отгружаем затронутую версию?». Команда тратит выходные на grep по lock-файлам в сорока репозиториях и ssh в работающие контейнеры, чтобы проверить, что реально установлено, потому что по памяти никто не ответит. Команда, у которой был SBOM на каждый выпущенный образ, ответила за восемь минут одним запросом. Разница не в таланте. Разница — машиночитаемый инвентарь, сгенерированный во время сборки, и дисциплина его хранить.

SBOM: машиночитаемый инвентарь для запросов, а не PDF для архива

Когда появится следующий xz-utils, ты хочешь ответить «мы затронуты?» одним запросом, а не за выходные grep-ом. Это требует, чтобы SBOM (Software Bill of Materials — машиночитаемый список всех компонентов артефакта) уже существовал, хранился и был доступен для запроса на каждый выпущенный образ — то есть генерировался при сборке автоматически.

Software Bill of Materials — это полный машиночитаемый список каждого компонента артефакта: прямые и транзитивные зависимости, версии, лицензии и хэши, которые их пиннят. Два формата, которые важны, — CycloneDX (OWASP, заточен под безопасность и корреляцию уязвимостей) и SPDX (Linux Foundation / ISO 5962, естественный выбор для отчётности по лицензиям и комплаенсу). SBOM не пишут руками. Его генерируют в CI из собранного артефакта инструментом вроде syft или cdxgen, который проходит по базам пакетов образа и манифестам языков и выдаёт инвентарь.

Выигрыш — пятничный вопрос, на который отвечают за минуты. Когда выходит CVE, ты не делаешь grep по сорока репозиториям — ты запрашиваешь SBOM-ы, уже сохранённые на каждый релиз, и получаешь точное множество образов с затронутой версией и диапазоном. Свяжи syft со сканером вроде grype, и SBOM становится постоянной поверхностью CVE-корреляции: инвентарь генерируется один раз, а каждое новое уведомление автоматически сверяется с ним. Бэкдор xz-utils (CVE-2024-3094) — каноническая мотивация: build-time инъекция в liblzma, готовившаяся два года, — и индустриальный урок был прямым: нельзя защищать дерево зависимостей, которого не видишь, особенно транзитивные пакеты единственного мейнтейнера, о добавлении которых никто не помнит.

# Сгенерировать SBOM из собранного образа, в CycloneDX JSON
syft your-registry/app:1.4.2 -o cyclonedx-json=sbom.cdx.json

# Позже, когда выходит CVE-2024-3094 — ответить «затронуты ли мы?» из SBOM
grype sbom:sbom.cdx.json --fail-on high

Provenance и SLSA: доказать, как собран артефакт

SBOM говорит, что внутри. Build provenance (доказательство происхождения сборки) — это проверяемая запись того, как артефакт появился на свет: какой билдер его произвёл, из какого коммита исходника, с какими параметрами и входами сборки. Фреймворк, который это градирует, — SLSA (Supply-chain Levels for Software Artifacts — уровни безопасности цепочки поставок); его Build-трек идёт от L0 до L3:

УровеньЧто гарантируетЧто делаешь, чтобы достичь
L0Ничего — provenance не существует.По умолчанию. Локальный docker build без записи.
L1Provenance существует и описывает, как шла сборка, — но может быть неполным или неподписанным.Эмитить provenance из процесса сборки. Документация, ещё не гарантия от подделки.
L2Сборка идёт на хостируемой платформе, которая подписывает provenance — заметна для подмены.Перенести сборки в управляемый CI (GitHub Actions и т.п.), который подписывает provenance за тебя.
L3Закалённый, изолированный билдер; provenance невозможно подделать даже тому, кто контролирует определение сборки.Использовать изолированный эфемерный билдер (например, SLSA reusable workflow), где ключ подписи недостижим из шагов сборки.

Скачок, который важен, — это L2 → L3. На L2 подпись доказывает, что provenance не изменили задним числом, но разработчик, контролирующий шаги сборки, всё ещё может заставить сборку врать о себе. L3 изолирует среду сборки и выносит генерацию provenance за пределы досягаемости кода самой сборки, так что метаданные точны даже против инсайдера, владеющего определением пайплайна. Это и есть планка для кода, которому ты реально доверяешь на деплое.

Sigstore и cosign: keyless-подпись, записанная в публичный лог

Provenance и SBOM-ы хороши ровно настолько, насколько хороша подпись, связывающая их с конкретным артефактом, — а подпись всегда умирала на хранении ключа. Sigstore убирает долгоживущий ключ целиком. С keyless-подписью cosign твой CI-workflow аутентифицируется по OIDC (OpenID Connect — протокол получения токена идентичности от доверенного провайдера; его workload-идентичность — «джоба release.yml в репозитории X на теге v1.4.2»), CA Sigstore Fulcio выпускает сертификат, связывающий эту идентичность с эфемерным ключом и самоуничтожающийся примерно за десять минут, ты подписываешь, а событие подписи пишется в Rekor — публичный, только-дополняемый лог прозрачности. Нет приватного ключа, который можно слить, ротировать или хранить в волте.

Артефакт связывается со своим provenance и SBOM через аттестацию — подписанное утверждение (формат in-toto) вида «для артефакта с дайджестом sha256:… вот его provenance / вот его SBOM». Action GitHub attest-build-provenance производит именно это для собранного образа и подписывает keyless через OIDC-идентичность workflow. Весь смысл Rekor в том, что подписант мониторит лог на свою собственную идентичность: неожиданная запись, подписанная как ты, — это обнаруженная компрометация, а не тихая.

# Keyless-подпись образа — OIDC-идентичность, эфемерный сертификат, лог в Rekor
COSIGN_EXPERIMENTAL=1 cosign sign your-registry/app@sha256:abcd...

# Привязать SBOM к дайджесту образа как подписанную аттестацию
cosign attest --predicate sbom.cdx.json --type cyclonedx \
  your-registry/app@sha256:abcd...

# На ДЕПЛОЕ — отвергнуть всё, что не подписано ожидаемой идентичностью workflow
cosign verify your-registry/app@sha256:abcd... \
  --certificate-identity-regexp 'https://github.com/acme/app/.github/workflows/release.yml@.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com
Почему это работает

В GitHub Actions обычно пропускают сырой cosign и используют actions/attest-build-provenance@v1, который генерирует provenance в стиле SLSA для артефакта и подписывает его keyless OIDC-токеном джобы — без установки cosign, без управления ключами. Ему нужны permissions: id-token: write и attestations: write. Аттестация привязана к дайджесту образа, никогда к изменяемому тегу, — в этом весь смысл: тег вроде :latest можно перенаправить после проверки, поэтому подписывай и проверяй по дайджесту от начала до конца.

Режим отказа: генерируешь доказательство, которое никогда не проверяешь

Каждый артефакт этого урока бесполезен, пока что-то не откажется деплоить без него. Доминирующий реальный отказ — не отсутствующий SBOM, а SBOM, сгенерированный в CI и ни разу не запрошенный; подпись, произведённая и ни разу не проверенная; аттестация, приложенная, и шаг деплоя, который её игнорирует. Подпись без проверки на деплое — это театр безопасности: ты заплатил за церемонию и не купил ни грамма гарантии. Шлагбаум — это cosign verify в пайплайне или admission-контроллер (Kyverno / Sigstore policy-controller), который отвергает любой образ, чья подпись и provenance не совпадают с ожидаемой идентичностью workflow, — запиненный по дайджесту, никогда по изменяемому тегу.

Другой тихий отказ — доверие изменяемому базовому образу: ты подписываешь свои слои, но FROM someimage:latest переразрешается в другие байты между сборкой и деплоем, так что твой подписанный артефакт стоит на непроверенном, заменяемом фундаменте. Пинни базовые образы по дайджесту и проверяй их тоже, иначе в цепочке доверия дыра в самом низу.

Выбери лучший вариант

Команда на хостируемом GitHub Actions хочет подписывать релизные образы и гейтить деплои. Выбери модель подписи и доверия.

Викторина

Твой пайплайн генерирует SBOM и подписывает каждый образ keyless cosign, но шаг деплоя просто тянет и запускает образ. Подменённый образ запушен скомпрометированным токеном. Что произойдёт?

Викторина

В чём ключевая разница между SLSA Build L2 и L3?

Вспомните перед уходом
  1. 01
    Пройди шаги генерация → подпись → аттестация → проверка и назови, что делает каждый шаг доверенным.
  2. 02
    Почему «мы генерируем SBOM и подписываем каждый образ» недостаточно и какие два пробела обычно остаются?
Итог

Защита цепочки поставок ПО — это три раздельных утверждения, и только последнее — применение. SBOM — машиночитаемый инвентарь каждой прямой и транзитивной зависимости, сгенерированный в CI из собранного артефакта через syft или cdxgen в формате CycloneDX или SPDX, так что когда выходит CVE вроде бэкдора xz-utils, ты отвечаешь «затронуты ли мы?» запросом к сохранённым SBOM за минуты, а не grep’ом по репозиториям. Build provenance — проверяемая запись того, как собран артефакт: какой билдер, какой коммит, какие параметры, — градируемая SLSA от L1 (provenance существует) через L2 (хостируемая платформа его подписывает) до L3 (изолированный билдер делает provenance неподделываемым даже тем, кто контролирует определение сборки). cosign от Sigstore подписывает keyless: workflow аутентифицируется по OIDC, Fulcio выпускает ~10-минутный сертификат, привязанный к этой workload-идентичности, а Rekor записывает подпись в публичный только-дополняемый лог, так что нет долгоживущего ключа для хранения. In-toto аттестация связывает SBOM и provenance с неизменяемым дайджестом артефакта. Но режим отказа, который бьёт команды, — сгенерировать всё это и никогда не проверить: подпись без шлагбаума проверки на деплое или доверие изменяемому базовому образу или тегу, который можно перенаправить между подписью и проверкой. Шлагбаум — cosign verify или admission-политика, запиненная к ожидаемой идентичности workflow и дайджесту, — единственный шаг, превращающий бумажку в гарантию. Теперь, когда видишь зелёную галочку «образ подписан» в CI, задай следующий вопрос: что именно в пути деплоя верифицирует эту подпись и откажет, если её нет?

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 5 завершено

Что-то непонятно?

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

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources4
expand
  1. 01
  2. 02
  3. 03
  4. 04

Trademarks belong to their respective owners. Editorial reference only.