Secrets in Docker Compose richtig übergeben - nicht als Umgebungsvariable
Secrets in Docker Compose richtig übergeben - nicht als Umgebungsvariable
Umgebungsvariablen für Secrets wirken bequem — sind aber ein bekanntes Sicherheitsproblem, das sich mit wenig Aufwand vermeiden lässt.
Warum ENV-Vars für Secrets problematisch sind
docker inspect myapp # Zeigt alle ENV-Variablen im Klartext
docker exec myapp env # Jeder mit exec-Rechten sieht alle Variablen
ps aux # Unter manchen Systemen in /proc sichtbar
Außerdem erben alle Kindprozesse im Container die Umgebungsvariablen — das ist ein unnötig breiter Zugriffsbereich. Logs können ENV-Variablen unbeabsichtigt ausgeben. Crash-Dumps enthalten sie oft vollständig.
Compose Secrets: Dateien statt Variablen
Docker Compose unterstützt Secrets als gemountete Dateien unter /run/secrets/:
services:
app:
image: myapp
secrets:
- db_password
- api_key
environment:
# Nur nicht-sensitive Konfiguration hier
DB_HOST: db
APP_ENV: production
secrets:
db_password:
file: ./secrets/db_password.txt # Datei auf dem Host
api_key:
file: ./secrets/api_key.txt
Die Secret-Dateien:
mkdir secrets
echo -n "supersecretpassword" > secrets/db_password.txt
echo -n "sk-abc123..." > secrets/api_key.txt
chmod 600 secrets/*.txt
echo "secrets/" >> .gitignore
Im Container sind die Secrets verfügbar als:
/run/secrets/db_password
/run/secrets/api_key
Secrets in der Anwendung lesen
Die Anwendung liest den Dateiinhalt zur Laufzeit:
# Python
with open('/run/secrets/db_password', 'r') as f:
db_password = f.read().strip()
// PHP
$dbPassword = trim(file_get_contents('/run/secrets/db_password'));
# Shell
DB_PASSWORD=$(cat /run/secrets/db_password)
Secrets mit Umgebungsvariablen kombinieren
Manche Tools kennen keine Secret-Dateien, erwarten aber eine ENV-Variable. Schlankes Wrapper-Pattern im Entrypoint:
#!/bin/sh
# entrypoint.sh
if [ -f /run/secrets/db_password ]; then
export DB_PASSWORD=$(cat /run/secrets/db_password)
fi
exec "$@"
Das Secret liegt auf Disk und wird nur für den eigentlichen Prozess in die ENV geladen — ein brauchbarer Kompromiss.
Docker Swarm: verschlüsselte Secrets
In Docker Swarm werden Secrets verschlüsselt gespeichert und nur den Containern bereitgestellt, die sie brauchen:
echo "supersecret" | docker secret create db_password -
docker secret ls
docker secret inspect db_password
# Swarm Stack
services:
app:
image: myapp
secrets:
- db_password
secrets:
db_password:
external: true # Existiert bereits in Swarm
Secrets werden im Swarm verschlüsselt übertragen und nur im RAM der berechtigten Container entpackt — nie auf Disk.
HashiCorp Vault als Alternative
Für komplexere Setups: Vault speichert und rotiert Secrets zentral:
# Secret lesen via Vault Agent Sidecar (mount in Container)
vault agent -config=/etc/vault-agent.hcl
# Schreibt Secret in Datei → App liest aus Datei
Vault kann Secrets automatisch rotieren, alle Zugriffe loggen und zeitlich begrenzen — weit über das hinaus, was ENV-Variablen bieten.
Checkliste
.env-Dateien mit Secrets: in.gitignoredocker inspectauf Prod-Container: keine Passwörter sichtbar- Secret-Dateien: Permissions
600, Eigentümer root oder App-User .env.example: alle Keys ohne Werte, versioniert
Secrets in ENV-Vars sind nicht das Ende der Welt — aber es gibt keinen guten Grund, es nicht besser zu machen.