Дайджесты новостей
Инфографическая взрыв-схема слоев OCI-образа Docker с сохранением удаленного секретного файла в нижнем слое под whiteout-маркером OverlayFS.

Секреты в Docker никуда не исчезают: ловушка команды RUN rm

Сколько раз ты видел подобный паттерн в чужих репозиториях или ловил себя на желании сделать так же: во время сборки контейнера нужно скачать приватный пакет из закрытого репозитория npm, стянуть бинарник по API или авторизоваться в защищенной базе. Разработчик копирует SSH-ключ или файл с токеном внутрь образа, запускает сборку, а в следующей строке заботливо пишет RUN rm -f /root/.ssh/id_rsa или объединяет команды через амперсанды.

Логика кажется кристально ясной: файл был, файл удалили. Запускаем контейнер командой docker run, проверяем каталог через ls -la — чистота, секрета нет. Можно смело пушить готовый образ в публичный реестр Docker Hub или корпоративный GitHub Packages.

Но в реальности ты только что подарил злоумышленникам свои боевые ключи доступа на блюдечке.

Анатомия whiteout-файлов в OverlayFS

Чтобы понять масштаб катастрофы, нужно заглянуть под капот слоистой файловой системы OCI-образов (Union File System, в подавляющем большинстве случаев это OverlayFS).

Образ Docker — это не монолитный жесткий диск, а стопка неизменяемых (immutable) слоев, каждый из которых физически представляет собой обычный tar-архив с дельтой изменений файловой системы. Инструкции COPY или ADD создают слой, куда упаковывается твой приватный ключ.

Когда в следующей строке ты вызываешь RUN rm, движок OverlayFS физически не может стереть байты из уже зафиксированного нижнего слоя. Вместо этого в новый верхний слой записывается крошечный системный маркер — так называемый whiteout-файл с префиксом .wh.<имя_файла>. При сборке слоев в единое дерево виртуальной файловой системы драйвер видит этот маркер и просто скрывает файл из вывода пользовательских команд.

В своем исследовании инженер Лука Кларич наглядно показал, как элементарно извлекаются подобные «удаленные» секреты. Любой пользователь, скачавший образ, делает следующее:

# Сохраняем образ в локальный архив и распаковываем слои
docker save my-company-app:latest -o image.tar
tar -xf image.tar

# Ищем наш файл в tar-архивах каждого исторического слоя
find . -name "layer.tar" -exec tar -tf {} \; | grep -E "id_rsa|token|secret"

И секрет всплывает в открытом виде за доли секунды. Популярные утилиты анализа образов вроде dive или сканеры Trivy подсвечивают такие скрытые файлы мгновенно.

Безопасная сборка с Docker BuildKit Secrets

Единственный надежный способ использовать конфиденциальные данные на этапе сборки — не допускать их попадания в слои образов вообще. Современный бэкенд сборки Docker BuildKit предоставляет для этого нативный механизм: директиву монтирования секретов --mount=type=secret.

Секрет монтируется во временную файловую систему в оперативной памяти (tmpfs) по пути /run/secrets/<id> исключительно на время выполнения конкретной команды RUN:

# syntax=docker/dockerfile:1
FROM alpine:3.20

RUN apk add --no-cache curl ca-certificates

# Монтируем токен доступа без сохранения в историю слоев образа
RUN --mount=type=secret,id=api_token,required=true \
    TOKEN=$(cat /run/secrets/api_token) && \
    curl -f -H "Authorization: Bearer $TOKEN" \
         -o /usr/local/bin/private-tool \
         https://internal.example.com/bin/private-tool && \
    chmod +x /usr/local/bin/private-tool

CMD ["/usr/local/bin/private-tool"]

При вызове команды docker build значение секрета передается напрямую из переменной окружения хоста или из локального файла, не оставляя следов в кэше сборки:

# Передача секрета из переменной окружения рабочей станции или CI-раннера
export API_TOKEN="ghp_my_super_secret_deployment_token"
docker build --secret id=api_token,env=API_TOKEN -t my-company-app:latest .

В результате в итоговом образе нет ни самого файла, ни белых маркеров OverlayFS, ни упоминания токена в команде docker history. Память tmpfs мгновенно очищается ядром сразу после завершения команды RUN. Это простое правило сборки экономит компаниям сотни часов расследования инцидентов утечки инфраструктурных доступов.