Все записи

8 мин чтения

Как привязать свидетельства сборки CI/CD к публичной метке времени?

Конвейер CI/CD может вычислить хеши артефактов сборки, SBOM, логов и манифестов релиза, упаковать их в один корень Merkle и опубликовать одно подтверждение Label 309 — независимую публичную точку фиксации во времени для будущих аудитов.

Да — конвейер CI/CD может опубликовать подтверждение того, что и когда он собрал. Подход такой: вычислить хеши важных результатов (артефактов, SBOM, логов, манифестов релиза), свернуть эти хеши в один корень Merkle и опубликовать одну запись Label 309 для сборки, релиза или временного окна. Позже любой сможет подтвердить, что конкретный артефакт или манифест входил в этот зафиксированный пакет, и что сам пакет существовал не позднее некоторого публичного времени блока.

Это не заменяет SLSA, Sigstore, GitHub Artifact Attestations или in-toto. Это дополняет их тем, чего ни один из них не даёт напрямую: независимой, публичной точкой фиксации во времени без привязки к издателю, которую не контролирует ни один вендор.

Что на самом деле должен подтверждать конвейер CI/CD?

Начните с тех свидетельств, которые вам может потребоваться предъявить через год.

Подтверждение CI/CD может фиксировать:

  • артефакты релиза;
  • дайджесты образов контейнеров;
  • файлы SBOM (software bill of materials);
  • аттестации происхождения SLSA;
  • метаданные связей in-toto;
  • логи сборки;
  • отчёты о тестах;
  • манифесты развёртывания;
  • снимки changelog;
  • ссылки на исходные коммиты;
  • lock-файлы зависимостей;
  • подписанные контрольные суммы;
  • примечания к релизу.

Не нужно хешировать всё подряд только потому, что оно существует. Вычисляйте хеши тех артефактов, которые важны для безопасности, аудита, реагирования на инциденты, доверия клиентов или целостности релиза.

Хорошее подтверждение отвечает на один конкретный вопрос, который может возникнуть в будущем: «Был ли именно этот артефакт или манифест частью свидетельств релиза, которые мы зафиксировали в тот момент?»

Как работает подход с пакетированием Merkle?

Для одного артефакта достаточно подтверждения на основе одного хеша.

Для релиза артефактов обычно много, и публиковать каждый отдельной транзакцией расточительно. Эту задачу решает корень Merkle. Вы вычисляете хеш каждого элемента свидетельств, превращая его в лист, сворачиваете упорядоченные листья в один 32-байтовый корень и публикуете только корень — одну запись в блокчейне, покрывающую весь релиз.

Конвейер:

  1. Собирает артефакты.
  2. Генерирует или собирает SBOM, аттестации, логи и манифесты.
  3. Вычисляет хеш каждого элемента свидетельств, превращая его в лист.
  4. Формирует упорядоченный список листьев.
  5. Строит дерево Merkle и вычисляет корень.
  6. Публикует одну запись Label 309 с этим корнем.
  7. Сохраняет список листьев и доказательства включения рядом со свидетельствами релиза.

Позже верификатор берёт один файл или дайджест, проверяет его доказательство включения и подтверждает, что элемент принадлежит корню в записи Label 309. Размер доказательства включения растёт лишь как логарифм размера пакета, поэтому корень над тысячами листьев всё равно проверяется за миллисекунды — полностью офлайн, без шлюза и без сети. Полную механику смотрите в статье одна запись для тысяч файлов.

Почему не положиться просто на существующие аттестации?

Используйте существующие аттестации — а затем закрепите их.

Происхождение по SLSA описывает, где, когда и как был создан программный артефакт. GitHub Artifact Attestations устанавливают происхождение сборки для артефактов вроде бинарных файлов и образов контейнеров. Sigstore записывает подписанные метаданные цепочки поставок в публичный лог прозрачности, открытый только для добавления, под названием Rekor. in-toto — это фреймворк для проверки того, что каждый шаг в цепочке поставок выполнен как запланировано, нужной стороной и над нужными входными данными.

Каждый из них решает реальную задачу. Label 309 решает другую: публикацию закреплённого в Cardano, независимо проверяемого подтверждения того, что определённый набор свидетельств существовал к определённому публичному времени. Зрелый конвейер не выбирает между «аттестациями» и «подтверждением существования». Он использует и то, и другое:

  • SLSA или аттестации GitHub — для происхождения сборки;
  • Sigstore — для подписи и работы с логом прозрачности;
  • in-toto — для проверки шагов цепочки поставок;
  • Label 309 — для публичной точки фиксации во времени над всем набором свидетельств.

Что добавляет Label 309 сверху?

Он добавляет долговечное публичное обязательство в Cardano.

Это обязательство может покрывать один манифест релиза или корень Merkle над множеством элементов свидетельств. Его может подписать идентичность проекта или компании. И его можно проверить, имея лишь метаданные транзакции и публичный обозреватель блокчейна Cardano — без аккаунта, без входа в систему и без зависимости от того, останется ли онлайн панель исходного CI-провайдера.

Эта независимость важнее всего, когда команде нужно подтвердить, что свидетельства существовали до некоторого более позднего события:

  • раскрытия уязвимости;
  • инцидента безопасности;
  • проверки безопасности со стороны клиента;
  • закупочного аудита;
  • дедлайна по комплаенсу;
  • спора о релизе;
  • расследования по цепочке поставок.

Подтверждение даёт временной линии точку опоры, которую никто из участников не сможет незаметно сдвинуть.

Что стал бы проверять аудитор?

Аудитор должен иметь возможность пройти всю цепочку от отдельного артефакта обратно к записи в блокчейне:

  1. Взять проверяемый артефакт или SBOM.
  2. Вычислить его хеш.
  3. Проверить доказательство включения по корню Merkle для релиза.
  4. Убедиться, что корень присутствует в записи Label 309.
  5. Найти транзакцию Cardano и прочитать её время блока.
  6. Проверить подпись над записью, если она есть.
  7. Проверить сопутствующее происхождение или аттестацию по их собственным правилам.

Это чётко разделяет два вопроса. Подтверждение Label 309 отвечает: были ли эти свидетельства зафиксированы к этому публичному времени? Слой SLSA, Sigstore, GitHub или in-toto отвечает: что эти свидетельства говорят о том, как артефакт был собран, подписан или распространён? Ни один из них не пытается делать работу другого.

Что должно входить в манифест релиза?

Манифест релиза должен быть скучным и полным. В него могут входить:

  • имя и версия релиза;
  • URL репозитория;
  • исходный коммит;
  • идентификатор рабочего процесса сборки;
  • идентификатор запуска сборки;
  • имена и дайджесты артефактов;
  • дайджесты образов контейнеров;
  • дайджесты файлов SBOM;
  • дайджесты файлов аттестаций;
  • дайджесты отчётов о тестах;
  • дайджест лога сборки;
  • метка времени, сообщённая системой CI;
  • ссылка на транзакцию Label 309, добавленная после публикации.

Сам манифест можно хешировать и включить как лист. Он же служит читаемым человеком указателем, который объясняет каждый другой лист в пакете. Поддерживайте стабильный формат: подтверждение проверять проще, когда структура свидетельств предсказуема от релиза к релизу.

Должен ли конвейер подписывать запись?

Как правило, да.

Корень Merkle подтверждает, что некоторый список был зафиксирован. Подпись дополнительно показывает, что проект, компания, система релизов или утверждённая идентичность поручились за это обязательство. В Label 309 это необязательная подпись уровня записи — авторство никогда не требуется для того, чтобы утверждение о существовании прошло проверку, но оно доступно, когда вам нужна подотчётность.

Управляйте ключом подписи осознанно. Не разбрасывайте долгоживущие сиды идентичности по произвольным CI-раннерам. В зависимости от вашей модели угроз используйте выделенную идентичность для релизов, контролируемый сервис подписи, рабочий процесс с аппаратной поддержкой или self-hosted раннер с жёстким контролем доступа. Открытый cardanowall CLI создан именно для этого — он не привязан к шлюзу и работает с сырыми сидами, поэтому встраивается в автоматизацию без участия сайта. Сквозной процесс смотрите в статье использование CLI в автоматизации.

Подпись добавляет подотчётность. Но сама по себе она не делает слабый конвейер сборки безопасным.

Где должен храниться список листьев?

Храните его вместе со свидетельствами релиза.

Список листьев и доказательства включения — это то, что позволяет позже подтвердить отдельные элементы. Если вы опубликуете только корень, а затем потеряете список листьев, вы всё ещё сможете подтвердить, что какой-то список существовал — но, возможно, уже не сможете подтвердить, что в нём был конкретный артефакт.

Подходящие варианты хранения зависят от рабочего процесса:

  • приложить его к архиву релиза;
  • хранить его в репозитории артефактов;
  • держать его во внутреннем хранилище свидетельств;
  • запечатать его как зашифрованное содержимое для конфиденциальных свидетельств;
  • опубликовать его через контентно-адресуемое хранилище, когда его безопасно сделать публичным.

Корень — это точка фиксации. Список листьев — это карта.

Как часто конвейер должен публиковать?

Подбирайте частоту подтверждений под частоту релизов. Распространённые варианты:

  • одно подтверждение на релиз;
  • одно подтверждение на сборку;
  • одно подтверждение на развёртывание;
  • одно подтверждение в день для непрерывных логов;
  • одно подтверждение на каждое значимое для безопасности событие.

Слишком редкая публикация ослабляет временную линию; слишком частая добавляет затрат и операционного шума. Пакетирование Merkle позволяет выбрать частоту под бизнес-вопрос. Если клиент спрашивает «что именно вошло в версию 2.3.1?», одного подтверждения на релиз вполне достаточно. Если регулятор или аудитор спрашивает, был ли мониторинг непрерывным, лучше подойдут ежедневные или ежечасные обязательства.

Публикация стоит денег, потому что шлюз платит реальные комиссии за транзакции Cardano плюс хранение — так что частота публикации — это настоящий компромисс между затратами и свидетельствами, а не бесплатный регулятор.

Чего подтверждение CI/CD не доказывает?

Оно не доказывает, что сборка была безопасной.

Подтверждение существования может показать, что артефакт, SBOM, лог или манифест существовал к публичному времени; что элемент был включён в зафиксированный пакет; и что некий ключ подписал запись. Это всё, что оно удостоверяет.

Оно не доказывает, что исходный код был безопасен. Оно не доказывает, что раннер не был скомпрометирован. Оно не доказывает, что зависимости были свободны от уязвимостей. Оно не доказывает, что SBOM полон. И оно не доказывает, что той или иной аттестации можно доверять, пока не пройдут её собственные правила проверки. Именно поэтому Label 309 стоит рядом с инструментами безопасности цепочки поставок, а не заменяет их — об общих ограничениях смотрите в статье чего подтверждение не доказывает.

С чего лучше начать?

Начните с подтверждения релиза. Для каждого релиза:

  1. Сгенерируйте свои обычные артефакты.
  2. Сгенерируйте или соберите SBOM и аттестации.
  3. Создайте манифест релиза.
  4. Вычислите хеш каждого файла свидетельств, превратив его в лист.
  5. Постройте корень Merkle.
  6. Опубликуйте подписанную запись Label 309.
  7. Сохраните ссылку на транзакцию в примечаниях к релизу.
  8. Сохраните манифест, список листьев и доказательства включения вместе с релизом.

Это даёт вам практичный след свидетельств, не требуя перестраивать систему сборки с первого дня. Дальше можно расширяться на ежедневные логи, манифесты развёртывания или автоматизацию большего объёма.

Коротко

Подтверждение CI/CD — это обязательство с меткой времени над свидетельствами релиза.

Вычислите хеши важных артефактов, SBOM, логов, аттестаций и манифестов. Упакуйте их в один корень Merkle. Опубликуйте этот корень в записи Label 309. Подпишите запись, если хотите, чтобы за неё поручилась идентичность проекта или компании.

Оставьте SLSA, Sigstore, GitHub Artifact Attestations и in-toto для происхождения и метаданных цепочки поставок. Добавьте Label 309 как независимую публичную точку фиксации во времени, которая привязывает весь набор свидетельств к моменту, который не сдвинет ни один вендор.

Что почитать дальше

ci-cdmerklesoftware-supply-chain