Вступление
В мире контейнеризации мы часто беспокоимся о портах, сетях и версиях образов. Но есть один момент, который раз за разом приводит к утечкам данных — секреты.
Я видел Dockerfile, где разработчики писали:
dockerfile
ENV DB_PASSWORD="admin123"
Или, что еще хуже, команды в docker-compose.yml:
yaml
environment: - API_KEY=sk_live_1234567890
Поздравляю! Вы только что подарили злоумышленнику ключи от квартиры, где деньги лежат. 🔓
Docker предоставляет встроенный механизм — Docker Secrets. Но как использовать его правильно, а не «для галочки»? Давайте разберем лучшие практики защиты чувствительной информации.
1. Помните главное правило: Secrets работают только в Swarm
Это самый большой камень преткновения. docker secret не работает в изолированном режиме (docker run) или в обычном Docker Compose (без --compatibility).
Плохо:
bash
docker run -e MYSQL_ROOT_PASSWORD=mysecret db
Хорошо (инициализируем Swarm, даже если у вас одна нода):
bash
docker swarm init
Теперь мы можем создавать секреты безопасно.
2. Никогда не передавайте секрет через переменную окружения (даже через secret)
Внимание, парадокс! Старые руководства советуют:
yaml
services:
app:
secrets:
- db_password
environment:
- DB_PASSWORD=/run/secrets/db_password # Так делать НЕ НАДО
Почему это плохо?
Любое приложение, которое делает printenv или падает с ошибкой (stack trace), может вывести реальное значение секрета в логи. Переменные окружения наследуются дочерними процессами, они видны в /proc и легко дискаверятся.
Лучшая практика: Читайте файл /run/secrets/secret_name напрямую в коде приложения.
Пример на Python (хорошо):
python
with open('/run/secrets/db_password', 'r') as file:
password = file.read().strip()
3. Инструмент «слепого ввода» для Compose (без Swarm)
Если у вас еще нет Swarm-кластера, используйте связку docker-compose + .env. Но не храните .env в Git!
Практика «Secrets via Bind Mounts» (только для dev):
yaml
services:
web:
image: nginx
secrets:
- my_secret_key
secrets:
my_secret_key:
file: ./secrets/my_secret_key.txt
Файл ./secrets/my_secret_key.txt добавьте в .gitignore.
Важно: В production используйте настоящий Swarm, а этот трюк — только для локального тестирования.
4. Ротация секретов без перезапуска контейнера
Классическая ошибка: удалить старый секрет и создать новый — контейнер упадет.
Swarm поддерживает docker secret update? Нет (до недавнего времени). Но есть трюк:
Если ваше приложение умеет перечитывать файлы на лету (inotify), вы можете:
- Создать новый секрет с другим именем (
db_password_v2). - Обновить сервис:
docker service update --secret-rm db_password --secret-add db_password_v2 my_app - Приложение должно следить за папкой
/run/secretsи переподключиться.
Лучшая практика: Не хардкодьте имена секретов. Пусть приложение читает переменную окружения SECRET_NAME, которая содержит имя текущего активного секрета.
5. Используйте внешнюю систему управления секретами (но не как костыль)
Docker Secrets хорош, но он не умеет:
- Автоматическую ротацию по расписанию.
- Аудит (кто и когда смотрел секрет).
- Интеграцию с Vault или AWS Secrets Manager.
Архитектурная практика:
- Используйте Docker Secrets для базовой изоляции внутри контейнера.
- Используйте HashiCorp Vault с драйвером
docker secret(например, черезvault-agent) для сложных сценариев.
Простой пример бокс-кара (sidecar) с Vault:
Ваше приложение не знает пароль. Оно спрашивает Vault, а Vault динамически генерирует пароль к БД на 1 час.
6. Шифрование на диске (ваша страховка)
Секреты Docker хранятся в Raft-логе Swarm менеджеров. По умолчанию они зашифрованы не всегда, а только при передаче по сети.
Практика: Включите шифрование логов:
bash
docker swarm init --autolock
Если кто-то украдет ваш диск с /var/lib/docker, без ключа расшифровки он не прочитает секреты.
При рестарте Docker Daemon потребуется разблокировка:
bash
docker swarm unlock
7. Реальное правило для CI/CD
Никогда не передавайте docker secret create через переменные в CI скриптах.
Плохо (GitHub Actions / GitLab CI):
yaml
- echo ${{ secrets.MY_PASSWORD }} | docker secret create db_pass -
Любой, кто имеет доступ к логам (или просто set -x), увидит пароль.
Хорошо:
Используйте файлы-артефакты, которые удаляются после сборки, или внешний Secrets Manager (например, HashiCorp Vault + vault read).
8. Контроль доступа: меньше секретов — лучше
Один сервис = один минимальный набор секретов. Не делайте:
yaml
services:
nginx:
secrets:
- master_db_password # nginx не нужен доступ к БД!
- aws_root_key
Практика: Создавайте отдельные секреты для каждого сервиса, используя принцип «наименьших привилегий» (PoLP).
Заключение: Чек-лист аудита безопасности
Проверьте свой проект сегодня:
✅ Я инициализировал docker swarm init (даже для одной ноды).
✅ Мои секреты монтируются как файлы в /run/secrets/, а не как ENV.
✅ Мое приложение читает файл секрета, а не переменную окружения.
✅ Файлы *.secret, .env и ./secrets/ добавлены в .gitignore.
✅ Включен --autolock для Swarm.
✅ В CI/CD пароль не проскакивает в аргументах командной строки.
✅ Nginx не знает пароль от PostgreSQL.
Docker Secrets — это мощный инструмент, но как и отмычка, он превращается в лом в неправильных руках. Используйте его осознанно, и ваши контейнеры станут крепостью. 🔒
Обсудить статью можно в комментариях. Какие лучшие практики используете вы? Расскажите о вашем опыте с секретами в Kubernetes или Nomad.
А что насчет Podman? Как работают Podman Secrets
Вы можете подумать: «Окей, Docker Swarm — это круто, но у меня на сервере Podman (без daemon’а, rootless, systemd-интеграция)».
Хорошая новость: Podman поддерживает секреты «из коробки», начиная с версии 3.1.0, и делает это очень похожим на Docker образом . Более того, разработчики Podman специально обеспечивают совместимость с Docker в этом вопросе .
Как это работает в Podman?
В Podman есть две параллельные вселенные для секретов (и это важно не путать):
А. Нативные Podman secrets (для podman run и Quadlet)
Это прямой аналог Docker secrets, но без необходимости инициализировать Swarm.
Создание секрета:
bash
# Из файла echo "SuperSecret123" > ./db_pass.txt podman secret create db_password ./db_pass.txt # Из stdin (прямо из консоли) printf "SuperSecret123" | podman secret create db_password -
Использование в контейнере:
bash
# Как файл (по умолчанию монтируется в /run/secrets/) podman run --secret db_password alpine cat /run/secrets/db_password # Как переменную окружения (НЕ рекомендуется по тем же причинам, что и в Docker) podman run --secret db_password,type=env,target=DB_PASS alpine printenv DB_PASS
Фишки Podman:
- Можно настраивать права доступа к файлу секрета (
uid,gid,mode) - Поддерживаются разные драйверы хранения:
file,pass(GPG-шифрование!),shell(кастомные скрипты) - Максимальный размер секрета — до 512 КБ
Б. Kubernetes-совместимые secrets (через podman kube play)
Это для тех, кто использует Podman как локальное окружение для Kubernetes.
Вы пишете обычный Kubernetes Secret в YAML:
yaml
apiVersion: v1 kind: Secret metadata: name: my-kube-password data: password: R3I4UEBzc3dvcmQh # base64 encoded "Gr8P@ssword!"
И применяете через Podman:
bash
podman kube play secret.yml
Внимание, подвох! Если вы попытаетесь использовать Kubernetes-секрет как нативный Podman secret (через --secret в podman run), то в переменную окружения попадет весь YAML, а не значение ключа password . Используйте такие секреты только внутри podman kube play или Quadlet .kube файлов.
Сравнение: Docker vs Podman
Нюанс с docker-compose → podman-compose
Если вы мигрируете с Docker Compose на Podman Compose, будьте внимательны: на момент написания статьи Podman Compose имеет ограниченную поддержку Build secrets (секретов на этапе сборки образа). Проблема известна, патчи уже в работе .
Временное решение: собирайте образ напрямую через podman build, а затем вручную указывайте тег при запуске через Compose.
Безопасность в Podman: а что насчет подмана?
Все техники «подмана», описанные в разделе 9, отлично работают и в Podman:
- Фейковые секреты с
inotify-ловушками - Переменные окружения-пустышки
- Модификация прав доступа к
/run/secrets/
Более того, в Podman вы можете дополнительно защититься с помощью драйвера pass, который хранит секреты в GPG-шифрованном виде на диске . Даже если злоумышленник получит доступ к файловой системе хоста, просто так прочитать секрет не выйдет.
Итог по Podman
Podman не просто догоняет Docker по функционалу секретов — он предлагает более гибкую архитектуру:
- ✅ Не требует Swarm (работает сразу)
- ✅ Rootless по умолчанию (безопаснее)
- ✅ Шифрование секретов на диске (GPG)
- ✅ Совместимость с Kubernetes через
kube play
Когда выбирать Podman? Если у вас:
- Одиночные серверы без оркестрации (не нужен Swarm/K8s)
- Строгие требования к безопасности (rootless + GPG)
- Желание использовать systemd для управления контейнерами
Чего ждать в ближайшем будущем? Поддержка Build secrets в Podman Compose уже в разработке и появится в следующих релизах . А пока что можно использовать костыли с ручным билдом или дождаться патча.