Как читать авторский курс и нормативные материалы
Это учебные материалы, а не заключение о соответствии конкретного продукта. Организационные модели курса отделяйте от терминов стандарта: ППК в опубликованном проекте — машиночитаемый перечень, а живой реестр его версий является практикой сопровождения. Термин OSA в разных материалах имеет разный охват. Статус и обязательность нормативного документа проверяются отдельно; проект КАПО опубликован как проект первой редакции.
П14. Подпись SBOM через Sigstore
Что именно решает эта практика SBOM сам по себе — обычный JSON-файл, который кто угодно может подменить между сборкой и проверкой. Подпись через Sigstore привязывает SBOM к конкретному образу как attestation (in-toto DSSE-конверт), фиксирует, кто и в каком pipeline его выпустил (OIDC-identity вместо приватного ключа), и заносит факт подписи в публичный transparency log Rekor. Без этого этапа любой downstream-потребитель доверяет SBOM «на слово».
Цель
Получить верифицируемую привязку CycloneDX SBOM к контейнерному образу: образ подписан keyless-подписью Sigstore, SBOM приложен как attestation типа cyclonedx, а cosign verify-attestation возвращает корректный DSSE-конверт с проверенным OIDC-identity и записью в Rekor. Проверяемый результат — это пара «образ + attestation», которую можно скачать из реестра на другой машине и заново верифицировать без секретов.
Команда или действие
Подготовка: образ уже в реестре (например, ghcr.io/org/app@sha256:...), SBOM сгенерирован (см. П38. Честный SBOM контейнерного образа) в файл bom.cdx.json.
# 1. Авторизация в реестре (cosign использует те же креды, что docker)
cosign login ghcr.io -u <user> --password-stdin <<< "$GHCR_TOKEN"
# 2. Прикрепить SBOM как attestation. В cosign v2 keyless-режим включён по умолчанию:
# Fulcio выдаёт короткоживущий сертификат на OIDC-identity, Rekor логирует факт.
cosign attest \
--predicate bom.cdx.json \
--type cyclonedx \
--yes \
ghcr.io/org/app@sha256:<digest>
# 3. Проверка attestation с привязкой к ожидаемому identity и issuer
GITHUB_REPOSITORY='<github-owner>/<repository>'
EXPECTED_CERT_IDENTITY="^https:\/\/github\.com\/${GITHUB_REPOSITORY}\/.+$"
cosign verify-attestation \
--type cyclonedx \
--certificate-identity-regexp "$EXPECTED_CERT_IDENTITY" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
ghcr.io/org/app@sha256:<digest> | jq -r '.payload' | base64 -d | jq .
https://token.actions.githubusercontent.com здесь не справочная страница, а значение OIDC issuer в сертификате Fulcio. Если нужно проверить саму конфигурацию issuer, смотрите https://token.actions.githubusercontent.com/.well-known/openid-configuration.
Адресуйте образ по digest, а не по тегу Подпись и attestation в Sigstore привязываются к digest (
@sha256:...), а не к тегу. Тег:latestможно переназначить на другой образ — и ваша подпись «отвалится». В CI всегда получайте digest сразу после push (docker inspect --format '{{index .RepoDigests 0}}') и работайте с ним.
Что вы должны увидеть
При cosign attest в терминал выводится подтверждение публикации в Rekor:
Generating ephemeral keys...
Retrieving signed certificate...
...
tlog entry created with index: 148203715
cosign verify-attestation сначала печатает блок верификации, затем выдаёт DSSE-конверт. После декодирования payload вы увидите in-toto statement с вашим SBOM внутри predicate:
{
"_type": "https://in-toto.io/Statement/v0.1",
"predicateType": "https://cyclonedx.org/bom",
"subject": [
{ "name": "ghcr.io/org/app", "digest": { "sha256": "<digest>" } }
],
"predicate": {
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"components": [
{
"type": "library",
"name": "zlib",
"version": "1.3.1"
}
]
}
}
Ключевой признак успеха в выводе verify: строки Certificate subject, соответствующие шаблону ^https:\/\/github\.com\/<github-owner>\/<repository>\/.+$, и Certificate issuer URL: https://token.actions.githubusercontent.com — они подтверждают, что подписал именно ваш CI-pipeline, а не посторонний.
Если не получилось
Типичные ошибки и как их распознать -
Error: no matching attestationsпри verify — либо вы проверяете другой digest (тег уехал на новый образ), либо attestation так и не загрузился в реестр. Сверьте digest и убедитесь, что шагattestотработал без ошибок. -error verifying certificate: ... no matching subject—--certificate-identity-regexp/--certificate-oidc-issuerне совпали с тем, кто реально подписал. Это не баг, а сработавшая проверка: либо ошиблись в regexp, либо образ подписан не тем pipeline. Никогда не «чините» это, убрав флаги identity — verify без них принимает любую подпись. -getting signer: getting key from Fulcio: ... 401— в CI нет валидного OIDC-токена (например, в GitLab не заданid_tokens/SIGSTORE_ID_TOKEN, в GitHub Actions не выставленpermissions: id-token: write). Keyless-подпись без OIDC невозможна. - Подпись прошла локально с браузерной авторизацией, но падает в CI — локально вы прошли interactive OIDC-flow, а в pipeline токена нет. Проверяйте именно CI-окружение, ради которого gate и делается.
Критерий зачёта
Показать преподавателю:
1. Лог шага cosign attest с непустым tlog entry created with index.
2. Вывод cosign verify-attestation с зелёной верификацией и видимыми Certificate subject + Certificate issuer URL.
3. Декодированный in-toto statement, где subject.digest.sha256 совпадает с digest проверяемого образа, а predicateType = https://cyclonedx.org/bom.
4. Устно: почему verify с привязкой к identity/issuer — это контроль, а verify без них — фикция доверия.
Нормативная связка
- SLSA — подпись и attestation образа покрывают требования provenance (build L2+); следующий шаг — П15. SLSA и in-toto provenance.
- in-toto — attestation Sigstore хранится именно как in-toto DSSE-конверт; модель statement/predicate описана здесь.
- NIST SP 800-218 SSDF — PS.2 (защита целостности артефактов) и PO.3 (доверенная toolchain): keyless-подпись и Rekor — машинный evidence под эти практики.
- ГОСТ Р 56939-2024 — управляемость и контролируемость артефактов цепочки поставки.
- CycloneDX ECMA-424 — формат SBOM, который мы подписываем; качество самого BOM проверяется в П34. SBOM quality gate.
- Требования к CI security gate — шаблон требований к gate, в который встраивается обязательная проверка подписи перед публикацией.
- Смежные практики: П38. Честный SBOM контейнерного образа (откуда берём BOM), П16. GitLab CI security gate (где подпись становится обязательным шагом gate), П08. Dependency-Track как портфель SBOM (куда складываем верифицированные SBOM).
- Модуль: М08. Защита цепочки поставки и OSA.