Как читать авторский курс и нормативные материалы
Это учебные материалы, а не заключение о соответствии конкретного продукта. Организационные модели курса отделяйте от терминов стандарта: ППК в опубликованном проекте — машиночитаемый перечень, а живой реестр его версий является практикой сопровождения. Термин OSA в разных материалах имеет разный охват. Статус и обязательность нормативного документа проверяются отдельно; проект КАПО опубликован как проект первой редакции.
П37. Контейнерный образ: слои, секреты, удалённые файлы
Цель
Доказать на собственноручно собранном образе, что файл, удалённый инструкцией RUN rm, физически остаётся в нижнем слое и извлекается из tar-архива. Проверяемый результат — извлечённое из слоя содержимое файла, которого нет в финальной файловой системе контейнера.
Почему так происходит Каждая инструкция Dockerfile создаёт отдельный слой (overlay).
RUN rm key.apiне стирает байты из предыдущего слоя — он лишь добавляет в новый слой whiteout-маркер.wh.key.api, который прячет файл при сборке union-FS. Исходные байты остаются в blob нижнего слоя и видны любому, кто распакует образ. Multi-stage build сCOPY --from— единственный надёжный способ не тащить секрет дальше.
Команда или действие
Соберите учебный образ с «секретом», который потом якобы удаляется:
mkdir layers-demo && cd layers-demo
# 1. фейковый секрет (НЕ настоящий ключ)
printf -- '-----BEGIN OPENSSH PRIVATE KEY-----\nFAKEKEYdoNotUse123456789\n-----END OPENSSH PRIVATE KEY-----\n' > key.api
# 2. Dockerfile, который «прячет» секрет в нижнем слое
cat > Dockerfile <<'EOF'
FROM busybox:latest
COPY key.api .
RUN rm key.api
EOF
docker build -t secrets-test .
# 3. в финальной ФС файла нет — RUN rm «сработал»
docker run --rm secrets-test ls -la /key.api # No such file or directory
# 4. но он лежит в слое: распаковываем образ и ищем секрет
docker save secrets-test:latest | tar -x -C .
find blobs/sha256/ -type f -exec sh -c 'tar -tf "$1" 2>/dev/null | grep -q "^key.api$" && echo "FOUND in $1"' _ {} \;
Дополнительно — два инструмента, которые делают это автоматически:
# послойный аудит: dive показывает, что добавил/удалил каждый слой
dive secrets-test:latest
# поиск секретов сразу по всем слоям образа
trivy image --scanners secret secrets-test:latest
Что вы должны увидеть
В пункте 4 find выводит blob, внутри которого лежит «удалённый» файл, а распаковка показывает реальный секрет:
FOUND in blobs/sha256/b00389...f17b98
$ tar xvf blobs/sha256/b00389...f17b98 key.api && cat key.api
-----BEGIN OPENSSH PRIVATE KEY-----
FAKEKEYdoNotUse123456789
-----END OPENSSH PRIVATE KEY-----
trivy image --scanners secret находит не меньше 1 секрета и помечает слой, в котором он лежит:
secrets-test (busybox 1.x)
Total: 1 (HIGH: 1)
key.api AsymmetricPrivateKey HIGH AsymmetricPrivateKey
В dive слой с RUN rm key.api отображается с положительным «вкладом» (добавлен whiteout), а не как удаление байтов — на левой панели видно, что размер образа от удаления не уменьшился.
Если не получилось
findничего не находит, секрета «нет». Скорее всего, BuildKit включён и собрал образ в новом формате —docker saveдаёт OCI-layout, blob'ы лежат вblobs/sha256/, но имена не совпадают с тем, что вmanifest.json. Откройтеmanifest.json/index.jsonи идите по ссылкам на слои; либо соберите сDOCKER_BUILDKIT=0 docker build ...для классического формата.dive: command not found. Это отдельный инструмент (github.com/wagoodman/dive), его нет в составе Docker. Поставьте бинарь и запускайтеdive <image>; на CI используйтеCI=true dive <image>.trivyне видит секрет. Проверьте версию (trivy --version): флаг--scanners secret— текущее написание (в старых версиях было--security-checks secret). Без явного указания сканера секретов trivy сканирует только уязвимости и секреты не ищет. Учтите, что trivy фильтрует часть тестовых паттернов — для учебного OpenSSH-ключа он срабатывает.- Файл удалён «по-настоящему». Если вы собрали образ так, что
COPYиrmоказались в одномRUN(RUN ... && rm ...), секрет не попадёт в отдельный слой и в финальную ФС, но всё равно останется в build-кэше. Для демонстрации слоёв инструкции должны быть раздельными.
Критерий зачёта
Покажите преподавателю: (1) вывод docker run ... ls, подтверждающий, что в финальной ФС файла нет; (2) содержимое key.api, извлечённое из blob'а слоя; (3) находку trivy --scanners secret с указанием слоя. Сформулируйте письменно, почему RUN rm не является способом удалить секрет и какой приём (multi-stage / --mount=type=secret) решает задачу.
Не превращайте демо в реальную утечку Используйте только фейковый ключ. Реальный секрет, попавший в слой и уехавший в реестр, считается скомпрометированным с момента push — ротация обязательна, «удаление тега» не помогает.
Нормативная связка
- Модуль М16 — честный состав образа.
- Смежные практики: П38. Честный SBOM контейнерного образа, П40. Огнестойкость РБПО и SCA процесс.
- Шаблон: Чек-лист честного SBOM контейнерного образа (зоны «Слои» и «Секреты»).
- Нормативка: ГОСТ Р 56939-2024 (управление секретами и конфигурацией сборки), проект ГОСТ Р по КАПО.