SBOM и происхождение артефактов
Чтобы защищать ПО, нужно сначала точно знать, из чего оно состоит и кто его собрал.
SBOM (Software Bill of Materials, спецификация состава ПО) — это машиночитаемый список всех компонентов внутри артефакта: библиотек, версий, лицензий и хешей. По сути — «состав» на этикетке вашего релиза.
Когда выходит новый громкий CVE, первый вопрос — «а он у нас вообще есть?». Без описи состава ответ ищут вручную по десяткам сервисов и часто ошибаются. SBOM превращает этот вопрос в запрос по списку. А подпись и происхождение (provenance) отвечают на второй вопрос: «можно ли вообще доверять этому артефакту?».
Зачем это знать защитнику
SBOM и provenance — это два столпа доверия к артефакту. SBOM отвечает на «ЧТО внутри», provenance — на «КАК и КЕМ это собрано». Вместе они позволяют: мгновенно находить уязвимые компоненты, обнаруживать подмену артефакта, отличать ваш настоящий релиз от поддельного и выполнять требования регуляторов (во многих странах SBOM уже обязателен для поставок ПО).
SBOM: опись состава
SBOM генерируется автоматически на этапе сборки инструментами вроде Syft, Trivy или CycloneDX-плагинов. Есть два распространённых формата: SPDX и CycloneDX. Упрощённо запись об одном компоненте выглядит так:
{
"bomFormat": "CycloneDX",
"components": [
{
"type": "library",
"name": "lodash",
"version": "4.17.21",
"purl": "pkg:npm/[email protected]",
"hashes": [{ "alg": "SHA-256", "content": "a1b2c3..." }],
"licenses": [{ "license": { "id": "MIT" } }]
}
]
}
Поле purl (package URL) — каноническое имя компонента, по которому SBOM связывается с базами уязвимостей. Имея SBOM, на выход нового CVE отвечают одной командой:
# Сгенерировать SBOM образа и сразу проверить на уязвимости
syft myapp:1.4.0 -o cyclonedx-json > sbom.json
grype sbom:sbom.json # сверка состава с базами CVE
Подпись артефактов и происхождение
SBOM говорит, что внутри, но не доказывает, что артефакт настоящий. Это задача цифровой подписи. Сборка подписывается приватным ключом, а потребитель проверяет подпись публичным. Если артефакт подменили после подписи, проверка не пройдёт.
Современный подход (например, проект Sigstore с инструментом cosign) использует keyless-подпись: вместо хранения долгоживущего приватного ключа подпись привязывается к удостоверённой личности (OIDC-токену CI) и записывается в публичный прозрачный журнал. Это снимает риск утечки ключа.
# Подписать образ (keyless, личность берётся из CI-токена)
cosign sign myregistry/myapp:1.4.0
# Потребитель проверяет: кто подписал и каким workflow
cosign verify myregistry/myapp:1.4.0 \
--certificate-identity-regexp 'github.com/acme/.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
Provenance (происхождение) идёт дальше подписи и фиксирует как собран артефакт: какой коммит исходника, какой пайплайн, какие входные данные, какой билдер. Стандарт для этого — in-toto attestation: подписанное утверждение «артефакт X с хешем H собран из коммита C пайплайном P». Проверив provenance, потребитель убеждается, что бинарник действительно собран из заявленного исходника, а не подменён по дороге.
Уровни SLSA
SLSA (Supply-chain Levels for Software Artifacts, произносится «салса») — это рамка зрелости, описывающая, насколько защищён процесс сборки. Уровни нарастают:
| Уровень | Что гарантирует |
| Build L1 | Сборка автоматизирована и генерирует provenance (есть запись о происхождении) |
| Build L2 | Сборка идёт на управляемой платформе, provenance подписан сервисом |
| Build L3 | Сборка изолирована и защищена от вмешательства; provenance невозможно подделать изнутри сборки |
Смысл уровней — давать потребителю измеримую гарантию. «Собрано по SLSA L3» означает не просто «есть подпись», а «процесс сборки был изолирован, и происхождению можно доверять».
Как это работает под капотом
В основе всего — криптографические хеши и подписи. Артефакт сводится к одному хешу (digest), например sha256:abc.... SBOM, подпись и provenance ссылаются именно на этот хеш, а не на изменяемый тег вроде :latest. Цепочка доверия выглядит так: исходник → сборка фиксирует digest артефакта → provenance подписывает утверждение про этот digest → подпись кладётся в прозрачный журнал. Потребитель пересчитывает digest скачанного артефакта и проверяет всю цепочку. Любая подмена меняет хеш и рушит проверку — именно поэтому привязка к тегу опасна, а к digest надёжна.
Как защититься
- Генерируйте SBOM автоматически на каждой сборке и храните рядом с артефактом. Тогда вопрос «затрагивает ли нас новый CVE» решается запросом по описи, а не паникой.
- Подписывайте артефакты и проверяйте подпись при развёртывании. Кластер/раннер должен принимать только подписанные доверенным workflow образы.
- Прикрепляйте provenance и сверяйте, что артефакт собран из ожидаемого репозитория и пайплайна, а не «откуда-то».
- Ссылайтесь на артефакты по digest, а не по тегу. Тег можно переназначить на другой образ; digest однозначно идентифицирует содержимое.
- Стремитесь к более высокому уровню SLSA поэтапно: сначала автоматизация и provenance (L1), затем подписанный provenance (L2), затем изоляция сборки (L3).
Итоги
- SBOM — машиночитаемая опись состава ПО (компоненты, версии, хеши, лицензии); отвечает на «ЧТО внутри» и ускоряет реакцию на новые CVE.
- Подпись артефактов доказывает подлинность, а keyless-подход (Sigstore/cosign) снимает риск утечки ключа.
- Provenance (in-toto) фиксирует, КАК и из какого исходника собран артефакт; SLSA задаёт уровни зрелости этого процесса (L1–L3).
- Вся цепочка доверия держится на хешах: ссылайтесь на артефакты по digest, а не по изменяемому тегу.