Перейти к содержимому
Главная страница » Docker Secrets: Лучшие практики для защиты токенов, паролей и ключей в контейнерах

Docker Secrets: Лучшие практики для защиты токенов, паролей и ключей в контейнерах

Вступление

В мире контейнеризации мы часто беспокоимся о портах, сетях и версиях образов. Но есть один момент, который раз за разом приводит к утечкам данных — секреты.

Я видел 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), вы можете:

  1. Создать новый секрет с другим именем (db_password_v2).
  2. Обновить сервис: docker service update --secret-rm db_password --secret-add db_password_v2 my_app
  3. Приложение должно следить за папкой /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:

  • Можно настраивать права доступа к файлу секрета (uidgidmode
  • Поддерживаются разные драйверы хранения: filepass (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 SecretsPodman Secrets
Требует Swarm/initДа (docker swarm init)Нет
Работает rootlessОграниченноДа (из коробки) 
Типы экспортаmount (только)mount + env 
Драйверы шифрованияНетЕсть (GPG pass) 
K8s-совместимостьЧерез сторонние тулыВстроенная (kube play
Макс. размер секрета500 КБ512 КБ 

Нюанс с 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 уже в разработке и появится в следующих релизах . А пока что можно использовать костыли с ручным билдом или дождаться патча.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *