DarkRiDDeR11 мин

Цепочка поставки без тумана: от секрета в CI до digest артефакта

БезопасностьDevOps

Проблема появляется не в момент deploy, а раньше: секрет или неподписанный артефакт проходит через CI и попадает в образ, а в журнале изменения остаётся только факт выкладки. Аудитор видит последний шаг, но не может связать его с исходной ревизией, исполнителем build и точным digest результата. Цена такого разрыва практическая: нельзя честно сказать, что нужно остановить, заменить или проверить, когда один из промежуточных фактов вызывает сомнение.

Обычная реакция — добавить в release описание «образ подписан» или «attestation приложен». Это создаёт ещё одну декларацию, а не связь доказательств. Если subject attestation не сопоставлен с digest артефакта, identity сборщика не проверена, а факт передачи секрета не отделён от его значения, текст не закрывает пробел. Команда начинает спорить о платформе вместо того, чтобы назвать отсутствующее звено и его владельца.

Сначала нарисуйте маршрут одного выпуска

Берём один узкий delivery-поток. У него есть исходная ревизия, идентичность build, граница выдачи секрета, получившийся артефакт, statement об artefact и вход deploy. Это не список продуктов и не попытка нарисовать всю инфраструктуру. Для каждой стрелки нужен один вопрос: какой факт мы ожидаем увидеть и с чем его можно сопоставить. Пока вопроса нет, стрелка остаётся предположением, даже если рядом написано знакомое имя инструмента.

Секрет в этой схеме — не строка, которую надо вывести для доказательства. Наоборот, evidence должно говорить о границе: какой этап вправе запросить ссылку на секрет, какой процесс не должен переносить значение в build output и как будет видно отсутствие разрешённого пути. Значение секрета, реальный адрес хранилища, командная политика и журналы не нужны в статье и не должны становиться артефактом расследования. Нужна различимая запись о том, что именно ещё предстоит проверить в рабочем контуре.

Карта звеньев перед техническим изменением
ЗвеноНаблюдаемый фактЧего этот факт не доказываетПервое действие
Исходная ревизияесть идентификатор выбранного исходникачто именно собрал CIсвязать revision с заявкой на build
Идентичность buildназван ожидаемый исполнительчто он действительно запускался из доверенного контекстаотделить identity от факта выполнения
Граница секретаопределена допустимая ссылка на секретчто значение не попало в outputспланировать отдельную проверку передачи
Артефактесть digest результатачто это именно то, что развёрнутосохранить digest как предмет сопоставления
Attestationесть statement о subjectчто statement подписан, проверен или правдивсверить subject с digest и определить проверку
Deployесть запись о запуске выкладкичто вход deploy равен проверенному артефактусвязать deploy input с digest
Учебная карта цепочки поставки: исходная ревизия проходит через идентичность CI и границу секрета к build, digest артефакта, декларации attestation и входу deploy; справа отмечены вопросы evidence и явно не подтверждённые факты.
Рисунок показывает, где искать отдельные evidence и trust boundary. Он не является схемой реального CI, подтверждением подписи, журналом выпуска или доказательством отсутствия секрета в образе.

Не смешивайте данные, statement и проверку

Digest — это имя конкретного результата в выбранном формате. Он удобен как ключ сопоставления: тот же digest должен быть предметом statement и входом deploy. Но digest не рассказывает, кто его собрал и откуда взялись входы. Statement attestation добавляет утверждения о subject, builder или исходнике. Оно тоже не становится доказательством автоматически: надо отдельно определить, чем и в каком контексте будет проверяться подпись, идентичность, формат и связь с ожидаемым input.

Именно здесь полезна SLSA v1.0, доступная в июне 2023: она даёт общий язык для уровней поставки и provenance, а не готовую печать качества. Sigstore и Cosign дают форматы и команды для работы с подписями и attestation. Ни один из документов не наблюдает ваш pipeline. Поэтому в change нельзя писать «SLSA закрыта» только потому, что появился файл с похожими полями. Корректная формулировка скромнее: подготовлен договор evidence, а реальная проверка перечислена отдельно.

Соберите локальный договор до подключения CI

Ниже не конфигурация CI и не шаблон для production. Это маленький fixture, который создаёт только помеченные synthetic записи в памяти. Он принимает закрытый набор полей: source label, builder label, ссылку на секрет без значения, digest и тот же subject в synthetic declaration. Неожиданное поле, включая secretValue, возвращает отказ до сборки записи. Такой тест полезен для ревью структуры: он не может прочитать секрет, запустить runner, создать certificate или увидеть развёрнутый образ.

import {
  assembleSyntheticSupplyChain,
  runSupplyChainFixture,
} from './upgrade-2023-06.mjs';

const flow = assembleSyntheticSupplyChain({
  synthetic: true,
  sourceRevision: 'synthetic-source-revision-A',
  builderIdentity: 'synthetic-builder-identity-A',
  secretLabel: 'synthetic-secret-reference-no-value',
  artifactDigest: 'synthetic-digest-artifact-A',
  attestationSubjectDigest: 'synthetic-digest-artifact-A',
  attestationDeclaration: 'synthetic-attestation-declaration',
});

const report = runSupplyChainFixture();
if (!Object.values(report.assertions).every(Boolean)) throw new Error('fixture failed');
console.log(flow.release.status); // manual-review-required

// Не создаёт secret, certificate, signature, attestation или deploy.

node web/scripts/upgrade-2023-06.mjs --verify-fixture

# PASS означает только: учебный договор непротиворечив.
# PASS не означает: secret защищён, statement подписан или deploy проверен.

Важная ветка fixture — совпадение artifactDigest и attestationSubjectDigest. Это минимальная защита от ошибки, когда красивый statement относится к другому output. Но совпадение двух строк не проверяет криптографию, доверие к builder или содержимое образа. В реальной цепочке такой результат становится лишь входом для следующей проверки. Если проект не знает, кто её выполняет и где хранится результат, лучше оставлять статус «не подтверждено», а не превращать fixture в формальный допуск.

Маршрут: симптом → причина → проверка → действие

  1. Симптом. В release виден deploy, но нельзя назвать его source revision, digest или границу работы с секретом.
  2. Причина. Последний шаг хранит событие выкладки, а evidence промежуточных звеньев не имеют общего ключа и владельца.
  3. Проверка. Для одного учебного выпуска заполните строку на каждое звено таблицы. Прогоните fixture: он обязан отклонить отсутствие builder, непомеченный input, иной subject и value-like label секрета.
  4. Действие. Выберите один общий ключ сопоставления: digest артефакта. Рядом определите, какой реальный источник позднее подтвердит source, build, secret boundary, attestation и deploy input.
  5. Проверка границы. Отдельно спросите владельца CI, кто будет проверять подпись и identity. Ответ «в declaration написано» не является шагом проверки.
  6. Следующий шаг. Добавьте контракт evidence в release design и договоритесь о минимальном безопасном запуске проверки вне этого fixture.

Что откатывать, когда цепочка неполна

Rollback здесь не означает удалить секрет, отозвать сертификат или повернуть production-трафик. Учебная функция умеет только вернуть snapshot своей записи и помечает provenance как requires-verification, release как no-system-change. В настоящем выпуске сначала решают операционный вопрос: какой deploy input надо остановить, как сохранить рабочее доказательство без чувствительных данных и какой другой артефакт разрешён как известный. Это отдельный план с владельцем и средой; его нельзя вывести из одной attestation.

Опасная ошибка — признать неполную цепочку «безопасной», потому что текущий deploy уже прошёл. Правильный статус иной: выпуск недостаточно объяснён, поэтому решение о продолжении требует явного владельца и дополнительного evidence. Такой статус не обвиняет CI и не объявляет инцидент. Он не позволяет подменить неизвестность уверенным текстом, а значит уменьшает риск сделать необратимый шаг на ложной связи.

Границы модели и следующий рабочий шаг

Эта статья не содержит настоящего секрета, токена, адреса, командной политики, CVE, scanner data, CI log, registry или deploy. Она не создаёт и не проверяет certificate, signature или attestation и не заявляет, что какой-либо артефакт имеет provenance. Отдельно важно: даже подписанная декларация может говорить только о том, что конкретный statement был подписан. До проверки subject, доверенной identity, условий builder и связи с deploy она не доказывает ни происхождение, ни факт использования артефакта.

Следующий шаг для команды — выбрать один выпуск, построить карту из шести звеньев и обозначить у каждого владельца evidence. Если на любой стрелке нельзя назвать проверяемый факт, не достраивайте его предположением. Зафиксируйте пробел и сузьте задачу до одного реального вопроса: например, как сопоставить deploy input с digest, не публикуя чувствительные данные. Так системная практика растёт из наблюдаемой связи, а не из набора терминов.

Историческая граница июня 2023

К июню 2023 уже были доступны стабильная SLSA v1.0, опубликованная 19.04.2023, и Cosign v2.0.0, опубликованный 24.02.2023; SSDF v1.1 был финальным документом NIST с февраля 2022. В статье используются только их версии и общий понятийный аппарат того периода. Поздние возможности платформ доставки, современные форматы bundle и текущие интеграции не приписываются автору 2023 года.

Проверяемые источники

  • SLSA: SLSA v1.0 is now final!, 19 апреля 2023 — официальное объявление фиксирует первый стабильный выпуск SLSA v1.0, доступный к июню 2023. Сам факт выпуска не доказывает соответствие какого-либо pipeline.
  • SLSA specification v1.0 — версионная спецификация описывает уровни и рекомендуемые форматы attestation, включая provenance. Сейчас версия помечена retired, но это сохранённая спецификация именно v1.0.
  • sigstore/cosign: Release v2.0.0, 24 февраля 2023 — официальный release проекта Sigstore, опубликованный до июня 2023. Наличие инструмента и его формата не означает, что конкретный артефакт был им подписан или проверен.
  • NIST SP 800-218 SSDF Version 1.1, Final, 3 февраля 2022 — официальное руководство NIST по практикам безопасной разработки и общему словарю для поставщиков и потребителей. Оно не заменяет evidence конкретного выпуска.