Пиков / КАПО
Как читать авторский курс и нормативные материалы

Это учебные материалы, а не заключение о соответствии конкретного продукта. Организационные модели курса отделяйте от терминов стандарта: ППК в опубликованном проекте — машиночитаемый перечень, а живой реестр его версий является практикой сопровождения. Термин OSA в разных материалах имеет разный охват. Статус и обязательность нормативного документа проверяются отдельно; проект КАПО опубликован как проект первой редакции.

container image layers

Почему это важно для SCA/OSA

Контейнерный образ — это не один файл, а стопка слоёв (OCI layers), каждый из которых хранит лишь дельту к предыдущему. SBOM, собранный по итоговой «сплющенной» файловой системе, описывает то, что видно на финальном слое, но образ физически несёт и всё, что было добавлено и затем «удалено» в промежуточных слоях. Для C/C++ это особенно болезненно: исходники, объектные файлы, статические .a, отладочные символы и приватные ключи подписи часто кладут в образ на этапе сборки и «убирают» в финальном RUN rm. Composition analysis обязан анализировать слои, а не только верхнюю проекцию, иначе SBOM пропустит реально извлекаемые артефакты и компоненты.

Как это проявляется

Удаление файла в верхнем слое не стирает его из нижнего блоба — оверлейная ФС лишь помечает его файлом-whiteout (.wh.<имя>). Файл по-прежнему лежит в tar нижнего слоя и извлекается полностью.

docker save myapp:1.4 -o myapp.tar
mkdir img && tar -xf myapp.tar -C img
# манифест: какой слой за что отвечает
cat img/manifest.json | jq '.[0].Layers'
# whiteout-маркеры удалённых файлов по всем слоям
for l in img/blobs/sha256/*; do tar -tf "$l" 2>/dev/null | grep -E '\.wh\.'; done
# извлечь предположительно «удалённый» приватный ключ из нижнего слоя
tar -xf img/blobs/sha256/<layer_digest> -C extracted/ build/signing.key

Инструмент dive показывает то же интерактивно: по слоям видно, что RUN rm -rf /build уменьшил «эффективный» размер, но блоб со статической библиотекой и ключом остался в истории образа.

Слепая зона или приём

Слепая зона: сканер по squashed-FS syft myapp:1.4 без флага охвата читает только финальную файловую систему и не видит удалённые в whiteout файлы. «Чисто» на верхнем слое не значит «чисто» в поставляемом образе — секрет и лишняя GPL-библиотека едут заказчику внутри блоба.

Приём: всегда сканировать с охватом всех слоёв (--scope all-layers) и отдельно прогонять поиск секретов и лицензий по распакованным блобам, а не по docker run-проекции.

Что делать на проекте

  1. Распаковать образ через docker save … | tar (или crane export) и пройти по manifest.json → Layers, зафиксировать, какой слой что добавляет.
  2. Найти все .wh.-маркеры и сопоставить с тем, что «удалялось» в Dockerfile (RUN rm …); каждый удалённый секрет/ключ — инцидент.
  3. Генерировать SBOM с --scope all-layers, а не по верхней ФС.
  4. Прогнать gitleaks/trufflehog и сканер лицензий по содержимому каждого слоя, а не по итоговому контейнеру.
  5. В сборке переносить секреты и build-артефакты в отбрасываемые стадии (multi-stage FROM … as build), чтобы они физически не попадали в финальные слои.
  6. Зафиксировать хеши слоёв в evidence: какой слой какой компонент внёс — это occurrences для записей SBOM.

Связь