8 lines
17 KiB
JSON
8 lines
17 KiB
JSON
{
|
||
"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 &&\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>"
|
||
}
|