Как читать авторский курс и нормативные материалы
Это учебные материалы, а не заключение о соответствии конкретного продукта. Организационные модели курса отделяйте от терминов стандарта: ППК в опубликованном проекте — машиночитаемый перечень, а живой реестр его версий является практикой сопровождения. Термин 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-проекции.
Что делать на проекте
- Распаковать образ через
docker save … | tar(илиcrane export) и пройти поmanifest.json→Layers, зафиксировать, какой слой что добавляет. - Найти все
.wh.-маркеры и сопоставить с тем, что «удалялось» вDockerfile(RUN rm …); каждый удалённый секрет/ключ — инцидент. - Генерировать SBOM с
--scope all-layers, а не по верхней ФС. - Прогнать gitleaks/trufflehog и сканер лицензий по содержимому каждого слоя, а не по итоговому контейнеру.
- В сборке переносить секреты и build-артефакты в отбрасываемые стадии (multi-stage
FROM … as build), чтобы они физически не попадали в финальные слои. - Зафиксировать хеши слоёв в evidence: какой слой какой компонент внёс — это occurrences для записей SBOM.
Связь
- Модуль: М16. SBOM for AI и честный SBOM контейнерных образов.
- Практики: П37. Контейнерный образ слои секреты и удаленные файлы, П38. Честный SBOM контейнерного образа.
- Нормативка: CISA Minimum Elements, BSI TR-03183-2.
- Смежные заметки: container image obfuscation, honest SBOM, stripped binaries, containerized build.