защитить конвейер сборки от зависимости до подписанного деплоя
Безопасность цепочки поставок ПО в DevOps: от реестра компонентов до подписи образов
14 минут
Промышленное ПО собирается из сотен зависимостей, базовых образов и инструментов сборки. Без SBOM, подписей и admission-политик команда не докажет, что выкатила, и не остановит подменённый артефакт до попадания в кластер.
Почему атаки на цепочку поставок обгоняют защиту на уровне приложения
Современные сервисы собираются, а не пишутся с нуля. Один контейнерный образ тянет сотни транзитивных библиотек, мутабельный тег базового образа, сторонние build actions и манифесты деплоя из Git. Инциденты SolarWinds, Log4Shell и бэкдор в xz Utils показывают: противник бьёт по системам сборки и зависимостям, а не только по прикладному коду. Платформенные команды часто не могут перечислить все пакеты в образе, доказать, что бинарник в продакшене совпадает с выходом CI, и восстановить provenance, когда аудитор спрашивает, кто собрал компонент. EO 14028 и EU Cyber Resilience Act проталкивают SBOM и обработку уязвимостей в закупки и compliance даже вне госсектора. Решение — не один сканер, а видимость через SBOM, целостность через подпись, обнаружение через гейты в CI и принуждение через admission в Kubernetes.
Четыре столпа: SBOM, подпись, сканирование и политики
Зрелая позиция строится на четырёх слоях, которые усиливают друг друга. SBOM — машиночитаемый инвентарь в SPDX или CycloneDX каждого компонента артефакта сборки. Подпись привязывает криптографическую идентичность к образу или бинарнику, чтобы реестр и кластер проверили: артефакт создан ожидаемым пайплайном и не изменён по пути. Сканирование уязвимостей на этапе сборки сопоставляет пакеты SBOM с базами CVE до push, когда исправление дешевле всего. Политики в кластере отклоняют неподписанные образы, образы выше порога severity или без обязательных attestations. Типичный поток: push в Git, сборка и тесты в CI, параллельно SBOM, скан Grype или Trivy, подпись Cosign через OIDC CI-провайдера, push в реестр с SBOM и provenance, затем Kyverno или OPA Gatekeeper проверяют подпись и политики уязвимостей при admission.
Генерация и публикация SBOM через Syft на каждой сборке
Ручной или квартальный экспорт SBOM бесполезен во время инцидента. Генерируйте SBOM для каждого образа в CI, храните как артефакт сборки и прикрепляйте к записи реестра рядом с образом. Syft от Anchore инвентаризирует пакеты ОС и зависимости приложения и отдаёт SPDX или CycloneDX JSON. Зафиксируйте версию sbom-action, сканируйте digest собранного образа — не мутабельный тег — и выгружайте SBOM в хранилище артефактов для аудиторов. OCI-совместимые реестры принимают SBOM через Cosign referrers, чтобы сканеры непрерывно связывали digest образа со списком компонентов.
permissions:
contents: read
packages: write
id-token: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: |
docker build -t "${REGISTRY}/${IMAGE}:${GITHUB_SHA}" .
docker push "${REGISTRY}/${IMAGE}:${GITHUB_SHA}"
- name: Generate SBOM
uses: anchore/sbom-action@v0
with:
image: "${{ env.REGISTRY }}/${{ env.IMAGE }}:${{ github.sha }}"
format: cyclonedx-json
output-file: sbom.cdx.json
- name: Upload SBOM artifact
uses: actions/upload-artifact@v4
with:
name: sbom
path: sbom.cdx.json# Mutable tags change under you; pin digest for reproducible builds
FROM python:3.12-slim@sha256:abc123def456...
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
USER 10001
CMD ["python", "-m", "app.main"]Подпись образов Cosign keyless через OIDC и прикрепление SBOM
Долгоживущие ключи подписи — операционный риск. Keyless-подпись Sigstore использует короткоживущие сертификаты, привязанные к OIDC-идентичности CI — GitHub Actions, GitLab CI или облачный OIDC, — и пишет события в transparency-лог Rekor для аудита. Выдайте permission id-token write, установите Cosign, подпишите digest образа после push и прикрепите SBOM или опубликуйте CycloneDX attestation. Перед включением enforcement в кластере проверьте локально через cosign verify. В изолированных или регулируемых средах используйте пары ключей через KMS вместо keyless.
- uses: sigstore/cosign-installer@v3
- name: Sign container image
run: |
cosign sign --yes \
"${REGISTRY}/${IMAGE}@${DIGEST}"
- name: Attach SBOM to image
run: |
cosign attach sbom --sbom sbom.cdx.json \
"${REGISTRY}/${IMAGE}@${DIGEST}"
- name: Verify signature in CI
run: |
cosign verify \
--certificate-identity-regexp "https://github.com/${GITHUB_REPOSITORY}/.*" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
"${REGISTRY}/${IMAGE}@${DIGEST}"Гейт CVE через Grype и принудительная проверка подписи в Kubernetes
Сканируйте digest образа в CI до промоушена. Grype и Trivy сопоставляют содержимое SBOM с CVE; прерывайте пайплайн на critical severity или по allow list принятых рисков. При деплое не полагайтесь на ручную проверку подписи разработчиками. Kyverno verifyImages валидирует подписи Cosign и может требовать SLSA- или vulnerability-attestations. Сначала ограничьте политики паттернами приватного реестра, затем расширяйте. Тестируйте в режиме audit до enforce, чтобы не заблокировать системные namespace.
- name: Scan image for vulnerabilities
uses: anchore/scan-action@v3
with:
image: "${REGISTRY}/${IMAGE}:${GITHUB_SHA}"
fail-build: true
severity-cutoff: critical
# Alternative: Grype CLI
- name: Grype scan
run: |
grype "${REGISTRY}/${IMAGE}@${DIGEST}" \
--fail-on criticalapiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-signed-images
spec:
validationFailureAction: Enforce
background: true
rules:
- name: verify-image-signature
match:
any:
- resources:
kinds:
- Pod
exclude:
any:
- resources:
namespaces:
- kube-system
verifyImages:
- imageReferences:
- "registry.example.com/*"
mutateDigest: true
required: true
attestors:
- entries:
- keyless:
issuer: "https://token.actions.githubusercontent.com"
subject: "https://github.com/your-org/your-repo/.github/workflows/build.yml@refs/heads/main"
rekor:
url: https://rekor.sigstore.devОперационные практики: SLSA, provenance, hardening CI и гигиена зависимостей
Внедряйте уровни SLSA постепенно: сначала attestation provenance сборки, затем изолированные hardened builders, затем нефальсифицируемый provenance для релизных артефактов. Используйте GitHub attest-build-provenance или cosign attest с in-toto predicates, где платформа это поддерживает. Фиксируйте базовые образы и GitHub Actions по digest или неизменяемым тегам версий. Автоматизируйте обновление зависимостей через Renovate или Dependabot и гоняйте тесты на каждый bump. Относитесь к CI-раннерам как к продакшен-инфраструктуре: least-privilege IAM, контроль исходящего трафика, защита веток и аудит изменений workflow. Периодически просматривайте записи Rekor на неожиданные идентичности подписи. Храните SBOM и отчёты сканирования с тем же сроком, что и релизные артефакты, чтобы при инциденте ответить, что выкатилось в конкретную дату. Безопасность цепочки поставок — практика на весь жизненный цикл: видимость без enforcement деградирует, enforcement без SBOM оставляет слепые зоны при раскрытии CVE.
Admission-политики дополняют hardening кластера из практического гайда по безопасности Kubernetes в продакшене.
Идентичности подписи и учётные данные реестра зависят от того, как секреты проходят через CI — это разобрано в гайде по управлению секретами в DevOps и CI/CD.
