Files
progcode/editorial/agent-rewrites/164.json
T
huncode 2d914b543f
Build and deploy / deploy (push) Failing after 15s
Publish rewritten technical article archive
2026-08-02 22:19:34 +03:00

8 lines
17 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"index": 164,
"slug": "editorial-2023-06-mechanism-secrets-supply-chain",
"title": "Attestation не доказывает provenance: как связать секрет, сборку и артефакт",
"excerpt": "Файл attestation рядом с образом ещё не подтверждает его происхождение. Разбираем границы секрета, digest, builder identity и проверку, которая связывает provenance с тем, что действительно попадает в deploy.",
"contentHtml": "<p>После выкладки в системе лежит образ и файл attestation. Команда открывает файл, видит source revision и builder, затем помечает релиз как проверенный. Позже выясняется, что statement ссылается на другой digest, identity сборщика никто не проверял, а deploy получил образ по тегу <code>latest</code>. Ошибка стоит дорого: нельзя уверенно определить затронутый артефакт, выбрать безопасный rollback и объяснить аудитору, какой факт подтверждён.</p>\n<p>Проблема усиливается, когда в ту же декларацию добавляют сведения о секрете. Доступ CI к секрету не доказывает, что значение не попало в слой образа, cache, metadata или журнал. Provenance отвечает за происхождение output. Secret boundary отвечает за путь доступа к чувствительному значению. Это разные утверждения с разными проверками.</p>\n<p>Тезис статьи простой: attestation становится полезным evidence только после независимого сопоставления subject с artifact digest, проверки доверенной identity и связи digest с входом deploy. Наличие файла, подписи или знакомого названия инструмента не заменяет эти операции.</p>\n<h2>Механизм цепочки</h2>\n<p>Разложите delivery-поток на отдельные факты. <strong>Source revision</strong> обозначает вход сборки. <strong>Builder identity</strong> обозначает исполнителя, которому разрешено выпускать результат. <strong>Secret boundary</strong> задаёт этап, который может получить ссылку или значение, и этапы, которым оно недоступно. <strong>Artifact digest</strong> обозначает конкретный набор байтов. <strong>Attestation statement</strong> заявляет свойства этого output. <strong>Verification</strong> проверяет statement с заданными правилами доверия. <strong>Deploy input</strong> показывает, что именно система пыталась запустить.</p>\n<p>Нельзя вывести один факт из соседнего. Digest не рассказывает, кто собрал образ. Source revision не доказывает, что именно он попал в output. Подписанная attestation не подтверждает provenance, пока проверка не установила доверенную identity, допустимый формат, claims и тот же subject. Тег образа тоже не заменяет digest: тег может указывать на новый результат.</p>\n<table><caption>Уровень утверждения и следующий способ проверки</caption><thead><tr><th scope=\"col\">Уровень</th><th scope=\"col\">Что можно записать</th><th scope=\"col\">Чего это не доказывает</th><th scope=\"col\">Следующая проверка</th></tr></thead><tbody><tr><td>Source</td><td>Выбрана ревизия <code>abc123</code>.</td><td>Сборка использовала именно её.</td><td>Сопоставить revision с invocation build.</td></tr><tr><td>Builder</td><td>Указана identity CI.</td><td>Identity доверена и реально запускала build.</td><td>Проверить identity и контекст запуска.</td></tr><tr><td>Artifact</td><td>Известен digest образа.</td><td>Этот digest отправили в deploy.</td><td>Сверить digest с release input.</td></tr><tr><td>Attestation</td><td>Statement содержит subject.</td><td>Statement подписан и правдив.</td><td>Проверить подпись, signer и claims.</td></tr><tr><td>Secret boundary</td><td>Сборка получает секрет на названном этапе.</td><td>Значение не попало в output.</td><td>Проверить конкретный путь передачи и места хранения.</td></tr></tbody></table>\n<h2>Почему секрет нельзя смешивать с provenance</h2>\n<p>Секрет должен жить внутри ограниченной границы. Например, job получает короткоживущий токен через secret manager, использует его для чтения зависимости и не записывает значение в environment, артефакт сборки или лог. Даже такая схема описывает только ожидаемый путь. Она не доказывает отсутствие утечки без проверки конкретного pipeline и его output.</p>\n<p>Особенно опасны аргументы командной строки, переменные, которые CI печатает при ошибке, кеши package manager и Docker layers. Секрет может исчезнуть из финального файла, но остаться в промежуточном слое. Поэтому вопрос «секрет есть в образе?» слишком широк. Сначала назовите образ, digest, слой или metadata и способ проверки. Если evidence нет, статус должен быть <code>not-observed</code>, а не «утечки нет».</p>\n<figure><img src=\"/assets/editorial/2023/secrets-supply-chain-2023-attestation-contract.svg\" alt=\"Схема связи source revision, builder identity, secret boundary, artifact digest и attestation с отдельной проверкой перед deploy\" loading=\"lazy\" /><figcaption>Учебная схема разделяет declaration и verification. Она не является журналом CI, результатом подписи или доказательством отсутствия секрета в образе.</figcaption></figure>\n<h2>Минимальный пример сопоставления</h2>\n<p>Ниже учебный пример. Он работает только с заранее заданными строками, не читает CI, registry или secret manager и не выполняет deploy. Его задача — показать отрицательный путь: statement про другой subject нельзя принять.</p>\n<pre><code>const artifact = {\n digest: 'sha256:artifact-a',\n deployInput: 'sha256:artifact-a',\n};\n\nconst statement = {\n subjectDigest: 'sha256:artifact-b',\n builder: 'ci.example/build',\n};\n\nconst sameArtifact =\n artifact.digest === statement.subjectDigest &amp;&amp;\n artifact.digest === artifact.deployInput;\n\nif (!sameArtifact) {\n throw new Error('manual review: subject is not the deploy artifact');\n}</code></pre>\n<p>Проверка выше не устанавливает, что builder доверенный, подпись действительна или сборка использовала указанную ревизию. Она ловит только несоответствие subject и deploy input. В рабочей системе нужен проверяемый формат attestation, доверенная политика identity, источник digest и результат запуска verifier. Если хотя бы одно звено не наблюдалось, не повышайте статус до <code>verified</code>.</p>\n<h2>Симптом → причина → проверка → действие</h2>\n<table><caption>Карта диагностики разрыва в цепочке поставки</caption><thead><tr><th scope=\"col\">Симптом</th><th scope=\"col\">Причина</th><th scope=\"col\">Проверка</th><th scope=\"col\">Действие</th></tr></thead><tbody><tr><td>Attestation есть, но deploy использует тег.</td><td>Релиз не сохранил digest как вход.</td><td>Найти фактический digest, переданный в deploy.</td><td>Остановить вывод о provenance и привязать release к digest.</td></tr><tr><td>Subject statement не равен digest образа.</td><td>Statement собран для другого output или перепутан.</td><td>Сравнить subject, digest registry и deploy input.</td><td>Не использовать statement; запросить корректное evidence.</td></tr><tr><td>Builder указан, но signer не проверен.</td><td>Identity смешали с результатом verification.</td><td>Проверить signer, trust policy и контекст запуска.</td><td>Оставить статус <code>not-verified</code> до отдельной проверки.</td></tr><tr><td>Секрет доступен build, но нет сведений о слоях.</td><td>Граница доступа описана общо.</td><td>Проверить command line, logs, cache и layers выбранного output.</td><td>Сузить исследование до одного digest и не публиковать значение секрета.</td></tr><tr><td>Локальная декларация выглядит полной.</td><td>Текст приняли за наблюдаемый факт среды.</td><td>Для каждого поля найти источник и время проверки.</td><td>Отделить declaration от evidence и назначить владельца проверки.</td></tr><tr><td>Нужен срочный rollback.</td><td>Неизвестно, какой output был применён.</td><td>Связать release record с digest и известным кандидатом.</td><td>Сначала остановить следующий шаг; rollback выполнять только при известном безопасном кандидате.</td></tr></tbody></table>\n<h2>Порядок действий</h2>\n<ol><li><strong>Зафиксируйте симптом.</strong> Запишите конкретный разрыв: тег вместо digest, другой subject, непроверенная identity или неизвестный путь секрета.</li><li><strong>Назовите предмет проверки.</strong> Укажите source revision, builder, artifact digest и deploy input. Не копируйте в задачу секреты, токены и полные журналы.</li><li><strong>Сверьте артефакт.</strong> Сравните digest из registry, statement и release record. Любое расхождение переводит решение в ручной review.</li><li><strong>Проверьте attestation.</strong> Установите формат, subject, signer, trust policy и обязательные claims. Отметьте отдельно, что действительно проверил verifier.</li><li><strong>Проверьте границу секрета.</strong> Назовите job, этап, разрешённый способ доступа и места, где значение могло сохраниться. Не заменяйте проверку списком общих запретов.</li><li><strong>Проверьте отрицательный путь.</strong> Для другого subject, неизвестной identity или не подтверждённой secret boundary должно быть понятное действие: остановка, ручной review или безопасный отказ.</li><li><strong>Свяжите решение с deploy.</strong> Разрешайте выпуск только для digest, который прошёл требуемые проверки и совпадает с фактическим входом релиза.</li><li><strong>Сохраните минимальное evidence.</strong> Зафиксируйте версии, идентификаторы, время, результат проверки и владельца. Чувствительные значения оставьте в контролируемом хранилище.</li></ol>\n<h2>Ограничения</h2>\n<p>Provenance не доказывает отсутствие уязвимостей, добросовестность исходного кода или безопасность всех зависимостей. Она описывает происхождение и условия получения output в пределах выбранной модели. Если builder записывает неверные сведения, downstream-проверка должна учитывать доверие к builder и его identity.</p>\n<p>Attestation не заменяет сканирование, review зависимостей, контроль доступа, ротацию секретов, тесты и наблюдение после выпуска. Подпись подтверждает целостность statement относительно ключа или identity. Она не делает claims истинными сама по себе. Digest связывает байты, но не объясняет, почему эти байты допустимы.</p>\n<p>Учебный код и таблица не запускались против production и не сообщают результат конкретного pipeline. Источники ниже дают официальные модели и спецификации, но не доказывают соответствие вашего проекта. При отсутствии реального verifier корректная формулировка — «не проверено».</p>\n<h2>Проверяемый критерий готовности</h2>\n<p>Цепочка готова к решению о выпуске, когда source revision, builder identity, artifact digest и deploy input связаны конкретными записями; subject attestation совпадает с digest; signer и claims проверены по названной trust policy; путь секрета ограничен и проверен для выбранного output; отрицательные случаи переводят решение в ручной review. Если есть только файл attestation, зелёный CI или тег образа, доказательство не завершено.</p>\n<h2>Проверяемые источники</h2>\n<ul><li><a href=\"https://slsa.dev/spec/v1.2/\" target=\"_blank\" rel=\"noopener noreferrer\">SLSA specification v1.2</a> — официальная спецификация уровней supply-chain security и форматов attestation, включая provenance.</li><li><a href=\"https://slsa.dev/spec/v1.2/provenance\" target=\"_blank\" rel=\"noopener noreferrer\">SLSA: Provenance</a> — официальное описание verifiable information о том, где, когда и как создан software artifact.</li><li><a href=\"https://csrc.nist.gov/pubs/sp/800/218/final\" target=\"_blank\" rel=\"noopener noreferrer\">NIST SP 800-218 SSDF v1.1</a> — официальная рамка практик безопасной разработки и управления риском software supply chain.</li></ul>"
}