Перейти к содержимому

Supply Chain Security

SolarWinds (2020), Codecov (2021), 3CX (2023), xz-utils (2024) — атака на software supply chain сместилась с runtime на build и distribution. Я наблюдаю, что многие команды думают про безопасность цепочки поставок только в категории «прогнать сканер уязвимостей», а это лишь финальный слой. Настоящая защита — контролируемая цепочка артефактов с криптографически проверяемым provenance: signed commits → controlled build → SBOM → signed release → verify-on-deploy. Четвёртый лист под L1 Secure Development. Граница с Vulnerability Management чёткая: тот лист про реакцию на известные CVE, то есть на уже сломанное. Этот — про защиту самого процесса, где будущая уязвимость не успеет стать известной CVE, а приедет в прод через скомпрометированный конвейер.

Главный навык на уровне L5 — проектировать конвейер под конкретные track, level и версию SLSA. В утверждённой спецификации v1.2 есть Build и Source tracks. Build L1 требует provenance, Build L2 — сборку на управляемой платформе и подписанный provenance, Build L3 — усиленную платформу сборки. Старая единая шкала SLSA 1–4 относится к спецификации до 1.0; говорить просто «SLSA Level 3» без track и version теперь недостаточно точно.

L4

  • Понимает границы понятия software supply chain: это не только внешние зависимости, а вся цепочка — репозиторий, раннер сборки, реестр артефактов, деплой, рантайм.
  • Применяет signed commits (GPG / Sigstore gitsign) и branch protection (signed-only merge в protected branches).
  • Держит конвейер как код в репозитории, а не в веб-интерфейсе; секреты CI выдаёт через федерацию OIDC короткоживущими токенами, а не долгоживущими PAT. Шаги сборки закреплены по digest (@sha256:...), а не по изменяемому тегу.

L5

  • Проектирует конвейер под выбранный уровень SLSA Build и версию спецификации; отдельно учитывает требования Source track.
  • Генерирует и публикует SBOM (Software Bill of Materials) — SPDX или CycloneDX, генерация в CI каждого артефакта (Syft / cdxgen), attestation подписан.
  • Подписывает и проверяет артефакты: Sigstore cosign для образов и релизов, подпись без ключей через OIDC, политики допуска в Kubernetes, проверяющие подпись прямо на деплое.
  • Защищается от подмены зависимостей и опечаточных пакетов: внутренние пакеты с зарезервированным пространством имён в публичном реестре, строгая конфигурация резолвера без отката с приватного на публичный, белый список во внутреннем зеркале.

L6+

  • Внедряет программу на уровне организации: план по SLSA для каждого сервиса, централизованная инфраструктура подписи, проверка через политики как код, процедура оценки поставщиков, сопоставление с регуляторикой (EO 14028, EU CRA, NIST SSDF).
  • Принимает стратегические решения: писать своё или брать чужое для критичных открытых зависимостей, что с этим делать по страховке, как планировать реагирование на компрометацию цепочки — в частности, какого масштаба отзыв и ротацию она за собой потянет.
  • SLSA specification v1.2 (OpenSSF). Первичный источник для Build и Source tracks. При ссылке на level я бы всегда указывал track и version, чтобы требование можно было проверить.
  • The Update Framework (TUF) (CNCF graduated). Спецификация безопасных систем обновления, устойчивая к компрометации ключа, компрометации реестра и повторной отправке старых обновлений. Лежит в основе Sigstore, Notary v2 и агента Datadog.
  • in-toto framework. Спецификация свидетельств по всей цепочке поставок. SLSA использует их как формат.
  • NIST SSDF (SP 800-218). Федеральные требования США к поставщикам ПО, появившиеся после указа EO 14028.
  • The xz-utils backdoor (CVE-2024-3094) — Andres Freund’s discovery. Главный публичный кейс — см. ниже.
  • SolarWinds: рекомендации CISA пострадавшим сетям (Alert AA21-008A). Переломный инцидент: атакующие вошли через систему сборки и подписали вредоносное обновление легитимным сертификатом. Читать, чтобы понять, почему целостность среды сборки критична — и заодно чтобы оценить масштаб зачистки, которая требуется после такого класса компрометации.
  • Codecov Bash Uploader Compromise. Компрометация конвейера через подменённый образ Docker: секреты из CI клиентов утекли наружу.
  • Reproducible Builds. Движение и инструменты за побитовую воспроизводимость сборки — основа для проверяемых свидетельств о ней.
  • OpenSSF Scorecard. Автоматическая оценка открытых репозиториев по практикам безопасности.
  • The State of the Software Supply Chain (Sonatype, ежегодно). Отраслевые данные о вредоносных пакетах и сроках починки.

Главный публичный кейс — xz-utils backdoor (CVE-2024-3094), обнаруженный Andres Freund в марте 2024. Атакующий под именем Jia Tan несколько лет вёл социальную инженерию против критичного открытого проекта, у которого был один сопровождающий: выстроил доверие, стал вторым мейнтейнером, постепенно протащил закладку в релизы. Нашли случайно. Freund заметил, что рукопожатие ssh на его личной машине стало есть заметно больше процессора, и пошёл разбираться. Главный урок: даже безупречный конвейер не спасёт от закладки наверху цепочки, если скомпрометирован сам этот верх. Защита лежит в гигиене зависимостей — не тащить в критичный путь библиотеку с единственным сопровождающим, смотреть на дату последнего коммита и на отзывчивость мейнтейнера, требовать нескольких сопровождающих там, где цена ошибки высока, и добиваться воспроизводимых сборок: закладка в xz работала именно потому, что сборка воспроизводимой не была.

Отсюда же граница применимости всей практики, и она узкая. Подписи, provenance и admission policies закрывают цепочку от вашего репозитория до кластера. Но подпись не спасает от того, что вы сами втянули в цепочку скомпрометированный upstream: это лечится гигиеной зависимостей, а не криптографией.

База, ниже которой опускаться незачем, — подписанные коммиты и подписанные релизы. Подпись коммита (GPG, SSH или Sigstore gitsign) с проверкой в branch protection закрывает целый класс атак через украденные учётки разработчика, подпись релиза даёт потребителю гарантию, что артефакт собрал легитимный процесс. Настраивается один раз на разработчика и один раз в CI.

Дальше — фиксация всего по digest, а не по тегу. FROM node:18, uses: actions/checkout@v4, pip install foo==1.2.3 без хеша: теги изменяемы, и атакующему достаточно опубликовать под тем же тегом другой образ. Digest неизменяем, а Renovate и Dependabot обновляют его сами, так что после автоматизации это стоит ноль.

И третье: проверять подпись на деплое, а не на сборке. Между build и deploy артефакт можно подменить — через компрометацию registry или MITM. Admission controller проверяет подпись в момент запуска, и неподписанный образ просто не стартует. Граница доверия проходит по deploy time.

Среда сборки — это поверхность атаки: одноразовые раннеры, федерация OIDC, никаких долгоживущих секретов. Раннер — машина с доступом ко всему сразу. Постоянный собственный раннер с вечным токеном в переменных окружения отдаёт атакующему все будущие сборки разом. Федерация OIDC выдаёт короткоживущий токен на конкретный запуск, привязанный к репозиторию, ветке и workflow, — украденный, он бесполезен где-либо ещё. Одноразовые раннеры (у GitHub из коробки, у себя — чистое состояние на каждую задачу) начинают каждую сборку с нуля. Это самый дешёвый и самый действенный сдвиг во всей теме.

SBOM — базовый артефакт: собирается на каждую сборку, подписывается, хранится. «Сгенерируем, когда аудит попросит» — это уже поздно. Через полгода после релиза выходит CVE, и единственный вопрос, на который нужно ответить за час, звучит так: в каких именно версиях наших артефактов лежал уязвимый пакет и куда они уехали. Без исторических SBOM ответа нет. Поэтому SBOM собирается в CI на каждый build (Syft, cdxgen), прикладывается к релизу и хранится не меньше года, в формате SPDX или CycloneDX.

Подмена зависимостей — реальный риск, лечится резервированием имён. Атака обидно простая. Внутренний пакет mycompany-utils живёт только во внутреннем реестре, публичный никто не проверял. Атакующий публикует mycompany-utils@99.0.0 в публичном npm или PyPI, и резолвер, у которого есть откат на публичный реестр, берёт именно его: версия-то выше. Защита — зарезервировать пространство имён в публичном реестре (@mycompany/utils), настроить резолвер строго (registry=https://internal/, никакого отката) либо держать белый список во внутреннем зеркале. Класс атак открыл Алекс Бирсан в феврале 2021: он выпустил пакеты с именами внутренних библиотек в публичные реестры и получил выполнение кода внутри Apple, Microsoft, PayPal, Shopify, Netflix, Tesla, Uber и ещё трёх десятков компаний, заработав на этом больше 130 тысяч долларов bug bounty. Обратите внимание, что от него не потребовалось ни одной уязвимости в обычном смысле слова — только имена внутренних пакетов, утёкшие в публичные артефакты.

  • Vulnerability Management — граница: тот лист реагирует на известные CVE, то есть на уже сломанное, этот защищает процесс, в котором будущая уязвимость не успеет стать CVE. Оба опираются на SBOM.
  • Secrets Management — пересечение по федерации OIDC и по управлению ключами подписи. Централизованная инфраструктура подписи — та же дисциплина работы с секретами, только применённая к ключам.
  • Threat Modeling — цепочка поставок — одна из границ доверия на схеме потоков данных. Track и level SLSA выбираются с оглядкой на модель угроз сервиса.
  • CI/CD — конвейер и есть основная поверхность для компрометации цепочки. SLSA Build L2 требует, чтобы сборка шла на управляемой платформе.
  • Progressive Delivery — политики допуска, проверяющие подпись на деплое, встроены в тот же конвейер выкатки.
  • Infrastructure as Code — модули Terraform, чарты Helm и роли Ansible — та же цепочка поставок. Практики те же: подписанные релизы, закреплённые версии, SBOM.
  • Incident Response — компрометация цепочки — особый класс инцидентов: огромный blast radius, а починка означает отзыв и ротацию всего, до чего атакующий мог дотянуться.
  • Vendor Reliability — здесь на зависимости смотрят со стороны безопасности, там — со стороны надёжности; практики соседние и опираются на общий список поставщиков.
  • Workload Identity — федерация OIDC в CI убирает долгоживущие учётные данные из сборки; связка «подписанный артефакт — identity того, кто его собрал» и есть часть цепочки SLSA.
  • Compliance Frameworks — требования SOC 2 и ISO 27001 к рискам поставщиков плюс европейский Cyber Resilience Act — первое регуляторное требование с конкретикой по цепочке поставок. Регламент вступил в силу 10 декабря 2024, но основные обязанности производителей начинают действовать только с 11 декабря 2027, а требования по отчётности об уязвимостях — с сентября 2026. То есть время подготовиться формально есть, и именно поэтому большинство команд к нему ещё не приступало.

Workload Identity и Compliance Frameworks отсюда уже уехали в отдельные листья, ссылки выше.

  • Экономика bug bounty (TBD) — когда запускать, какие ставить границы, как устроены выплаты. Тот же вопрос уже висит в Vulnerability Management, так что это соседний лист, а не подраздел этого.
  • Reproducible Builds (TBD) — линия Bazel, Nix и Guix; побитовый детерминизм; сложности, когда языков в проекте несколько. Может быть отдельным листом под Programming / Scripting; в SLSA v1.2 это не «Level 4».

Чего я не знаю — какой SLSA baseline разумно рекомендовать по умолчанию. Без threat model и требований к конкретному артефакту любая рекомендация превращается в карго-культ. Честнее фиксировать выбранные track + level + version вместе с обоснованием, чем объявлять один level нормой для всех.