Docker · Security · Secrets Management · DevOps
Docker Secrets: Was nie ins Image gehört
BuildKit, Swarm Secrets und sichere Credential-Flows

Passwörter in Dockerfiles, API-Keys als ENV-Variablen, Zertifikate in Image-Layern – das sind reale Sicherheitslücken in Tausenden von Container-Setups. Docker Secrets, BuildKit Mount-Secrets und ein durchdachtes Credentials-Management eliminieren diese Risiken, ohne den Entwicklungsworkflow zu belasten.

12 Min. Lesezeit BuildKit · Swarm Secrets · Vault · ENV-Sicherheit Docker 24+ · BuildKit 0.11+

1. Das Problem: Secrets in Images sind ein Dauerbrenner

Es klingt offensichtlich: Passwörter, API-Keys und private Zertifikate gehören nicht in Docker-Images. Und doch tauchen Docker Secrets-Verstöße regelmäßig in Sicherheitsaudits auf, weil der Entwicklungsalltag verführerische Abkürzungen anbietet. Ein schnelles ENV DB_PASSWORD=supersecret im Dockerfile, ein COPY .env . für den Build-Prozess, ein hartcodierter API-Key im Startskript – jede dieser Entscheidungen hinterlässt Spuren in den Image-Layern, die sich mit einfachen Werkzeugen extrahieren lassen.

Das Risiko besteht nicht nur beim absichtlichen Missbrauch. Öffentliche Registry-Pushes, Docker Hub-Leaks, kompromittierte CI-Systeme oder einfach ein falsch geteilter Image-Digest können dazu führen, dass Credentials aus Images extrahiert werden. Die Konsequenzen reichen von Datenbankzugriffen bis zu vollständig übernommenen Cloud-Accounts. Wer Docker Secrets korrekt einsetzt, schließt diese Angriffsklasse strukturell – nicht durch Richtlinien, die Menschen vergessen.

In diesem Artikel wird der gesamte Secrets-Lebenszyklus in Docker beleuchtet: Wie Secrets in Layer gelangen, wie BuildKit und Swarm Secrets das strukturell verhindern, wie Compose für lokale Entwicklung mit Docker Secrets arbeitet und wann externe Secret-Stores wie HashiCorp Vault die richtige Ergänzung sind.

2. Wie Secrets in Image-Layer gelangen – und warum das gefährlich ist

Docker-Images bestehen aus schreibgeschützten Layern, die stackartig übereinandergelegt werden. Jede Anweisung im Dockerfile – RUN, COPY, ENV – erzeugt eine neue Layer, die den Zustand des Filesystems zu diesem Zeitpunkt einfriert. Das Problem: Eine spätere RUN rm /secrets/api.key-Anweisung löscht die Datei aus der obersten Layer, aber die darunterliegende Layer mit der Datei bleibt erhalten und ist mit docker history, docker save oder Tools wie dive vollständig extrahierbar.

Selbst ENV-Variablen, die im Dockerfile mit ARG SECRET_KEY und dann --build-arg SECRET_KEY=$KEY übergeben werden, sind in der Layer-History sichtbar: docker history --no-trunc image:tag zeigt den vollständigen Build-Befehl inklusive aller Argumente. Eine weiterer, oft übersehener Pfad: COPY --from=builder /root/.ssh /tmp/ssh in Multi-Stage-Builds, bei denen der Entwickler vergisst, dass der letzte Stage die kopierten Dateien enthält. Docker Secrets als Konzept adressieren genau diese Klasse von Layer-Lecks, indem Secrets niemals als Dateisystem-Snapshot persistiert werden.

3. BuildKit Mount-Secrets: Secrets im Build ohne Layer-Spur

BuildKit, seit Docker 23 standardmäßig aktiv, führt das Konzept der --mount=type=secret-Direktive im Dockerfile ein. Ein Secret wird damit nur für die Dauer einer einzelnen RUN-Anweisung als temporäre Datei in /run/secrets/ eingeblendet – ohne in der resultierende Layer zu erscheinen. Die Datei existiert ausschließlich im Prozess-Namespace während des Build-Schritts und hinterlässt keinerlei Spur im Image. Das ist der sauberste Weg, um zum Beispiel private Composer- oder npm-Registry-Tokens während des Builds zu verwenden.

Die Übergabe des Secrets erfolgt beim Build-Befehl entweder als Datei (--secret id=composer_auth,src=$HOME/.composer/auth.json) oder als Umgebungsvariable (--secret id=npm_token,env=NPM_TOKEN). Im Dockerfile referenziert man das Secret per ID. Dieser Ansatz funktioniert zuverlässig für Build-time-Secrets wie Package-Registry-Credentials, SSH-Keys für private Git-Repositories oder interne CA-Zertifikate. Docker Secrets via BuildKit erfordern kein Refactoring des Rest der Infrastruktur – nur das Dockerfile und den Build-Befehl.


# syntax=docker/dockerfile:1.5
# Dockerfile — BuildKit secret mount for private Composer registry
FROM php:8.4-cli AS builder

WORKDIR /app

# Copy composer files first (layer caching)
COPY composer.json composer.lock ./

# Mount secret only for this RUN step — leaves NO trace in the image layer
RUN --mount=type=secret,id=composer_auth,target=/root/.composer/auth.json \
    composer install --no-dev --optimize-autoloader

COPY . .

FROM php:8.4-fpm AS runtime
WORKDIR /app
COPY --from=builder /app/vendor ./vendor
COPY --from=builder /app .

# Build command — secret is passed from local file, never stored in image
docker build \
  --secret id=composer_auth,src=$HOME/.composer/auth.json \
  --tag myapp:latest .

# Verify: secret does NOT appear in image history
docker history --no-trunc myapp:latest | grep -i auth
# (no output — secret left no trace)

# SSH agent forwarding for private Git repos during build
docker build \
  --ssh default=$SSH_AUTH_SOCK \
  --tag myapp:latest .

4. ENV-Variablen: Grenzen und sicherer Einsatz

Umgebungsvariablen sind der verbreitete Weg, Konfiguration in Container zu übergeben – und für viele nicht-sensitiven Werte die richtige Wahl. Das Problem beginnt, wenn Secrets über ENV im Dockerfile gesetzt oder über --env SECRET=value in docker inspect-sichtbarer Form übergeben werden. docker inspect container_id gibt das vollständige Env-Array zurück, inklusive aller gesetzten Werte. Jeder mit Docker-Socket-Zugriff kann diese Werte lesen.

Die sichere Verwendung von Umgebungsvariablen für Docker Secrets erfordert, dass der Wert niemals im Dockerfile steht, sondern ausschließlich zur Laufzeit über --env-file (mit einer .env-Datei, die in .gitignore und .dockerignore liegt) oder über eine Secrets-Management-Lösung injiziert wird. Für wirklich sensitive Werte wie Datenbank-Master-Passwörter oder API-Tokens mit Schreibrechten gilt: ENV-Variablen sind keine Docker Secrets. Sie sind praktisch, aber bieten keine echte Isolation.

5. Docker Swarm Secrets: Secrets für Produktions-Services

Docker Swarm bietet mit dem eingebauten Docker Secrets-Mechanismus eine Infrastruktur-native Lösung für Produktionsumgebungen. Secrets werden verschlüsselt im Raft-Log des Swarm-Managers gespeichert und nur an den Container-Prozess auf dem Worker-Node übergeben, auf dem der Service tatsächlich läuft. Dort erscheinen sie als In-Memory-Dateien in /run/secrets/ – gelesen werden sie wie normale Dateien, aber sie werden niemals auf Disk geschrieben und sind nur dem jeweiligen Container-Prozess zugänglich.

Die Verwaltung von Swarm Docker Secrets erfolgt über die CLI: Secrets werden erstellt (docker secret create), Services zugeordnet (--secret in docker service create) und können rotiert werden, ohne den Service neu zu deployen. Das Rotation-Workflow ist ein entscheidender Vorteil gegenüber ENV-basierten Ansätzen: Ein neues Secret wird erstellt, dem Service hinzugefügt, das alte entfernt – der Service-Update geschieht rollierend ohne Downtime. Für Kubernetes-Nutzer: Swarm Secrets sind konzeptuell ähnlich zu Kubernetes Secrets, aber ohne externe Komponenten.


# Create Docker Swarm secret from file (not echoed to shell history)
printf "supersecret_db_password" | docker secret create db_password -

# List existing secrets (values are NEVER shown)
docker secret ls

# Deploy service with secret mounted at /run/secrets/db_password
docker service create \
  --name myapp \
  --secret db_password \
  --secret source=api_token_v2,target=api_token \
  myapp:latest

# Inside container: read secret like a regular file
cat /run/secrets/db_password

# Rotate secret without downtime
printf "new_supersecret_password" | docker secret create db_password_v2 -
docker service update \
  --secret-rm db_password \
  --secret-add source=db_password_v2,target=db_password \
  myapp
docker secret rm db_password

6. Docker Compose Secrets für lokale Entwicklung

Auch für die lokale Entwicklung mit Docker Compose bietet Docker Secrets eine sauberere Alternative zu direkten ENV-Werten in der compose.yaml. Compose unterstützt die secrets-Top-Level-Direktive, mit der Secrets aus Dateien gelesen und als /run/secrets/-Einträge in den Container gemountet werden. Die Secret-Datei liegt lokal und wird über .gitignore vom Repository ausgeschlossen – im Repository selbst steht nur die Compose-Konfiguration, niemals der Wert.

Der praktische Vorteil: Neue Entwickler im Team klonen das Repository, legen die Secret-Dateien lokal an (aus einem Passwort-Manager oder internem Wiki) und starten ohne weitere Konfiguration. Das Compose-File ist vollständig in Git, ohne Credentials. Für CI-Pipelines werden die Secret-Dateien durch Pipeline-Variables erzeugt, bevor Docker Compose gestartet wird. Dieser Workflow macht Docker Secrets in Compose zur empfehlenswerten Praxis auch in Nicht-Swarm-Setups.

7. HashiCorp Vault und externe Secret-Stores

Für komplexere Anforderungen – Secret-Rotation, Audit-Logs, dynamisch generierte Credentials, fein granulare Access-Policies – reichen die eingebauten Docker Secrets-Mechanismen nicht aus. HashiCorp Vault ergänzt Docker, indem es als zentraler Secret-Store fungiert. Vault generiert auf Anfrage kurzlebige Credentials, rotiert Secrets nach konfigurierbaren Zeitintervallen und protokolliert jeden Zugriff. Der Container authentifiziert sich bei Vault (per AppRole, Kubernetes-Service-Account oder AWS IAM) und erhält ein kurzlebiges Token, mit dem er die benötigten Secrets aus Vault abruft.

Der Vault-Agent-Sidecar ist ein etabliertes Pattern für Kubernetes und Docker Swarm: Ein separater Vault-Agent-Container läuft neben dem Applikations-Container, authentifiziert sich bei Vault und schreibt die abgerufenen Secrets in ein gemeinsam genutztes In-Memory-Volume. Der Applikations-Container liest die Secrets aus diesem Volume – ähnlich wie bei nativen Docker Secrets, aber mit der vollen Leistungsfähigkeit von Vaults Dynamic Secrets, Lease-Management und Audit-Backend. Für Umgebungen, die regulatorische Anforderungen (SOC 2, PCI DSS) erfüllen müssen, ist dieser Ansatz oft Pflicht.

8. Secret-Scanning: Lecks erkennen bevor sie passieren

Selbst mit korrektem Docker Secrets-Management passieren Fehler: ein vergessener Debug-Commit, ein temporäres Hardcoding das nie rückgängig gemacht wurde, ein COPY . . der eine lokale .env-Datei einschließt. Secret-Scanner erkennen diese Lecks, bevor das Image in eine Registry gepusht wird. Tools wie trivy (mit --scanners secret), gitleaks und truffleHog scannen Images, Git-History und Dockerfiles auf bekannte Secret-Muster: AWS-Keys, GitHub-Tokens, Stripe-Secrets, private Schlüssel.

Die Integration in CI-Pipelines ist straightforward: trivy image --scanners secret myapp:latest schlägt den Build fehl, wenn bekannte Secret-Patterns gefunden werden. Parallel sollte gitleaks detect in Pre-Commit-Hooks laufen, um Commits mit Secrets gar nicht erst ins Repository gelangen zu lassen. Eine .dockerignore-Datei, die .env, *.key, *.pem, *.p12, .aws/ und ähnliche Dateien ausschließt, ist die letzte Verteidigungslinie für das Docker Secrets-Konzept.

9. Vergleich: Secrets-Methoden im Überblick

Die Wahl der richtigen Docker Secrets-Methode hängt vom Kontext ab: Build-time vs. Runtime, lokale Entwicklung vs. Produktion, einfaches Setup vs. Enterprise-Anforderungen. Die folgende Tabelle fasst die wichtigsten Methoden und ihren Sicherheitsstatus zusammen.

Methode Kontext Sicherheitsniveau Empfehlung
ENV im Dockerfile Build + Runtime Kritisch unsicher Niemals für Secrets
--build-arg Build-time Unsicher (History) Nicht für Secrets nutzen
BuildKit --mount=type=secret Build-time Sicher Empfohlen für Build-Secrets
Docker Swarm Secrets Runtime (Swarm) Sicher, verschlüsselt Empfohlen für Produktion
HashiCorp Vault Runtime (alle) Enterprise-Grade Für komplexe Anforderungen

Die Wahl zwischen Swarm Secrets und Vault hängt weniger von der Sicherheit ab – beide sind für den normalen Betrieb ausreichend sicher – als von den operativen Anforderungen. Vault bietet Secret-Rotation, dynamische Credentials, Audit-Logs und fein granulare Policies; Swarm Secrets sind einfacher aufzusetzen und kommen ohne externe Abhängigkeit aus. Für Teams, die bereits Kubernetes nutzen, ist Kubernetes Secrets mit externem Secret-Store-Operator (z.B. External Secrets Operator mit AWS Secrets Manager) die natürliche Weiterentwicklung des Docker Secrets-Konzepts.

Mironsoft

Docker Security, Secrets Management und sichere Container-Infrastruktur

Credentials in eurer Docker-Infrastruktur sicher verwalten?

Wir auditieren bestehende Docker-Setups auf Secrets-Lecks, migrieren ENV-basierte Credentials auf sichere Docker Secrets und integrieren Secret-Scanner in eure CI-Pipelines.

Security Audit

Systematischer Scan aller Dockerfiles und Images auf Secrets-Lecks und unsichere Muster

BuildKit-Migration

Umstellung auf BuildKit Mount-Secrets für Build-time-Credentials ohne Layer-Spur

Vault-Integration

HashiCorp Vault oder AWS Secrets Manager für dynamische, rotierende Credentials

10. Zusammenfassung

Das Kernprinzip von Docker Secrets-Management ist einfach: Credentials gehören weder in Dockerfiles noch in Image-Layer noch in Versionskontrolle. Sie werden zur Build-Zeit über BuildKit Mount-Secrets temporär bereitgestellt, zur Laufzeit über Docker Swarm Secrets oder externe Secret-Stores injiziert und niemals persistent im Container-Filesystem gespeichert. Das ist kein theoretisches Sicherheitskonzept, sondern ein praktischer Workflow, der mit den eingebauten Docker-Tools umsetzbar ist.

Der pragmatische Einstieg: .dockerignore um alle sensitiven Dateien erweitern, --build-arg für Secrets durch BuildKit Mount-Secrets ersetzen, ENV-Werte aus Dockerfiles entfernen und trivy --scanners secret in die CI-Pipeline integrieren. Swarm Secrets oder eine Vault-Integration können schrittweise folgen, wenn der Produktionsbetrieb robustere Anforderungen stellt. Docker Secrets sind kein Einmalaufwand, sondern ein laufendes Konzept, das mit dem Stack mitwächst.

Docker Secrets — Das Wichtigste auf einen Blick

BuildKit Secrets

RUN --mount=type=secret bindet Secrets nur für einen Build-Schritt ein – keine Spur in Layer-History oder Image-Filesystem.

Swarm Secrets

Verschlüsselt gespeichert, nur an den zugeordneten Service übergeben, als In-Memory-Datei in /run/secrets/ – niemals auf Disk.

ENV-Grenzen kennen

ENV im Dockerfile landet in Layer-History. docker inspect zeigt alle Env-Vars. Für echte Secrets immer Secrets-Mechanismus nutzen.

Secret-Scanning in CI

trivy --scanners secret und gitleaks als Pre-Commit-Hook. .dockerignore für *.env, *.key, *.pem. Letztes Netz gegen versehentliche Lecks.

11. FAQ: Docker Secrets

1Was sind Docker Secrets genau?
Mechanismus für sensitive Daten ohne Layer-Spur. In Swarm verschlüsselt gespeichert, als In-Memory-Datei in /run/secrets/ bereitgestellt – niemals auf Disk oder in Image-History.
2Warum ist ENV im Dockerfile unsicher?
ENV-Werte landen in der Layer-History, lesbar mit docker history --no-trunc. Zur Laufzeit zeigt docker inspect alle Env-Variablen. Kein Schutz gegen Insider-Threats oder kompromittierte Registry.
3--build-arg vs. BuildKit Mount-Secrets?
build-arg erscheint in docker history. Mount-Secrets existieren nur während eines RUN-Schritts – keine Spur in Layer oder Manifest. Einzige sichere Option für Build-time-Credentials.
4Compose Secrets ohne Swarm?
Ja. secrets-Direktive in compose.yaml liest aus lokaler Datei, mountet als /run/secrets/. Datei in .gitignore – nur Compose-Config ins Repository.
5Swarm Secrets ohne Downtime rotieren?
Neues Secret erstellen, Service-Update mit --secret-rm + --secret-add (gleiches target). Rollierender Update ohne Downtime. Altes Secret danach löschen.
6Wann brauche ich Vault?
Bei dynamisch generierten Credentials, Audit-Logs pro Zugriff, kurzlebigen Database-Secrets oder feingranularen Policies für verschiedene Services und Umgebungen.
7.env-Dateien aus Images fernhalten?
.dockerignore mit .env, *.key, *.pem, .aws/ befüllen. trivy --scanners secret als CI-Gate. Letztes Sicherheitsnetz gegen versehentliches COPY . .
8Sind Swarm Secrets wirklich verschlüsselt?
Ja. Verschlüsselt im Raft-Store des Managers. Auf Worker-Nodes nur im RAM berechtigter Container. docker secret inspect zeigt Metadaten, niemals den Wert selbst.
9SSH-Keys beim Build sicher weitergeben?
docker build --ssh default=$SSH_AUTH_SOCK. Im Dockerfile: RUN --mount=type=ssh. SSH-Agent-Socket wird temporär forwarded, private Key verlässt nie den Host.
10Was prüft trivy beim Secret-Scan?
Über 150 Secret-Typen: AWS Keys, GitHub Tokens, Stripe Keys, private RSA-Schlüssel, JWT-Tokens. Scannt alle Image-Layer, nicht nur die oberste Schicht.