Docker Compose Secrets: Как да спрем да пишем пароли директно в docker-compose.yml

Всички сме го правили. Стартираш нов проект, трябва ти база данни, и пишеш нещо такова:
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: mysupersecretpassword123
Работи. Правиш commit. Пускаш го в GitHub.
И ето — паролата ти за базата данни вече е публична. Завинаги. Дори да я изтриеш по-късно, тя живее в git историята.
В тази статия ще покажа три правилни начина за работа с чувствителни данни в Docker Compose — от простото към production-ready — за да не се налага никога повече да hardcode-ваш credentials.
Защо това е реален проблем
Преди да преминем към решенията, нека изясним за какво точно говорим.
Hardcode-натите secrets в docker-compose.yml са опасни, защото:
- Git историята не забравя. Дори да премахнеш паролата в следващия commit, всеки с достъп до репото може да я намери в историята.
- Мащабира се лошо. Един и същ файл се използва в dev, staging и production — с едни и същи credentials.
- Нарушава 12-factor app принципа за строго разделение между конфигурация и код.
- Е основният източник на изтичане на credentials в публични репозитории. GitHub сканира за подобни шаблони автоматично и ще те предупреди — но щетата вече е нанесена.
Метод 1: .env файлове (Бърза победа за разработка)
Най-простото подобрение. Вместо да hardcode-ваш стойности директно, ги реферираш като променливи.
Стъпка 1 — Създай .env файл:
# .env
POSTGRES_USER=myapp
POSTGRES_PASSWORD=много-по-сигурна-парола
POSTGRES_DB=production_db
Стъпка 2 — Реферирай го в docker-compose.yml:
services:
db:
image: postgres:16
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
Docker Compose автоматично чете .env от същата директория — без допълнителна конфигурация.
Стъпка 3 — Най-важната стъпка. Добави .env в .gitignore:
echo ".env" >> .gitignore
Предостави безопасен шаблон за екипа:
# .env.example ← този файл commit-вай
POSTGRES_USER=
POSTGRES_PASSWORD=
POSTGRES_DB=
✅ Предимства: Просто, без зависимости, работи навсякъде. ⚠️ Недостатъци: .env файлът все още стои като plaintext на диска. Добре за разработка, не е идеално за production.
Метод 2: Docker Secrets (Production-Ready)
Docker има вградена система за управление на secrets. Те се съхраняват криптирани в паметта и никога не се записват на диска или излагат като environment variables.
⚠️ Забележка: Docker Secrets в тази форма изискват инициализиран Docker Swarm mode. При single-node setup пак можеш да го използваш — просто изпълни
docker swarm initведнъж.
Стъпка 1 — Създай secret-а:
# От низ
echo "моята-супер-секретна-парола" | docker secret create db_password -
# Или от файл
docker secret create db_password ./password.txt
Стъпка 2 — Реферирай го в docker-compose.yml:
services:
db:
image: postgres:16
environment:
POSTGRES_USER: myapp
POSTGRES_DB: production_db
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
external: true
Secret-ът се монтира като файл вътре в контейнера на /run/secrets/db_password. Много официални Docker images (PostgreSQL, MySQL, MariaDB) поддържат суфикса _FILE специално за този шаблон.
Стъпка 3 — Деплойни:
docker stack deploy -c docker-compose.yml myapp
✅ Предимства: Secrets са криптирани в покой, никога не са в environment variables, идеално за production. ⚠️ Недостатъци: Изисква Swarm mode. Малко по-сложна настройка.
Метод 3: Secrets като локални файлове (Алтернатива без Swarm)
Ако не искаш да използваш Swarm mode, но все пак искаш secrets извън docker-compose.yml, можеш да монтираш файлове директно.
Стъпка 1 — Създай директория за secrets:
mkdir -p ./secrets
echo "моята-db-парола" > ./secrets/db_password.txt
echo "моята-redis-парола" > ./secrets/redis_password.txt
Стъпка 2 — Добави secrets директорията в .gitignore:
echo "secrets/" >> .gitignore
Стъпка 3 — Монтирай като read-only файлове в docker-compose.yml:
services:
db:
image: postgres:16
environment:
POSTGRES_USER: myapp
POSTGRES_DB: production_db
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
volumes:
- ./secrets/db_password.txt:/run/secrets/db_password:ro
redis:
image: redis:7-alpine
command: sh -c 'redis-server --requirepass "$$(cat /run/secrets/redis_password)"'
volumes:
- ./secrets/redis_password.txt:/run/secrets/redis_password:ro
✅ Предимства: Без Swarm, работи с обикновено docker compose up, secrets извън YAML. ⚠️ Недостатъци: Secret файловете все още стоят на диска — увери се, че хост машината е защитена.
Бонус: Провери дали не изтичаш secrets
Преди всеки commit, провери дали случайно не са попаднали secrets в YAML файла:
# Търси общи шаблони в compose файла
grep -Ei '(password|secret|key|token)\s*[:=]\s*[^\$\{]' docker-compose.yml
Ако тази команда върне резултат — имаш hardcode-нат secret. Оправи го преди да commit-ваш.
Можеш да добавиш това и като pre-commit hook, който автоматично блокира commit-а:
# .git/hooks/pre-commit
#!/bin/sh
if grep -Ei '(password|secret|key|token)\s*[:=]\s*[^\$\{]' docker-compose.yml; then
echo "❌ Открит е възможен hardcoded secret в docker-compose.yml. Commit отменен."
exit 1
fi
Направи го изпълним:
chmod +x .git/hooks/pre-commit
Кой метод да изберете?
| Сценарий | Препоръчан метод |
|---|---|
| Локална разработка | .env файл + .gitignore |
| Production на един сървър | Локални secret файлове (Метод 3) |
| Multi-node / оркестриран production | Docker Secrets (Метод 2) |
| CI/CD pipeline | Environment variables инжектирани от CI системата (GitHub Actions Secrets, GitLab CI Variables и др.) |
Бърз чеклист преди да push-неш
- Без plaintext пароли в
docker-compose.yml .envе в.gitignore.env.exampleсъществува и е commit-нат (с празни стойности)secrets/директорията е в.gitignore- Pre-commit hook-ът е настроен
Заключение
Hardcode-ването на пароли в docker-compose.yml е навик, в който лесно се попада и е трудно да се поправи след като репото е публично. Добрата новина е, че и трите метода по-горе са лесни за имплементиране — дори в съществуващ проект.
Започни с .env файлове още днес, ако не си го направил. Отнема пет минути и веднага елиминира най-честия източник на случайно изтичане на credentials.
Намерихте материала за полезен?
Съдържанието на itpraktika.com е безплатно и ще остане такова.
Ако статията ти е помогнала — можеш да подкрепиш сайта с малка доброволна сума.
Всяко дарение помага за поддръжката и развитието на портала.
