Eine Bewertungslogik statt einer weiteren Best-Practices-Liste: Wie sich Angriffsflächen in produktiven Docker-Umgebungen identifizieren, absichern und überprüfen lassen — inklusive priorisierter Audit-Checkliste und einem gehärteten Beispiel-Setup.
Docker Security beginnt mit dem Threat Model
Ein universelles „sicheres Docker-Setup“ gibt es nicht. Was geschützt werden muss und wie viel Aufwand angemessen ist, hängt davon ab, was in den Containern läuft, wer Zugriff hat und was im Kompromittierungsfall auf dem Spiel steht. Bevor einzelne Maßnahmen sinnvoll sind, lohnt sich deshalb ein kurzer, konkreter Blick auf das Bedrohungsmodell.
Was schützen wir?
In einer typischen Docker-Umgebung verteilen sich die schützenswerten Werte auf mehrere Ebenen, die selten gleich behandelt werden:
- Docker Host (Betriebssystem, Kernel, Dateisystem)
- Container-Laufzeitumgebung
- Die Anwendung selbst
- Credentials und Secrets
- Images
- Registry
- Persistente Daten (Volumes)
- CI/CD-Pipeline
- Docker API / Daemon
- Netzwerk
Vor wem schützen wir?
Statt eines akademischen Bedrohungskatalogs helfen die Szenarien, die in der Praxis tatsächlich zu Vorfällen führen:
- Eine kompromittierte Anwendung (z. B. über eine ausgenutzte Schwachstelle im Code)
- Ein bösartiges oder kompromittiertes Image
- Gestohlene Credentials
- Fehlkonfigurationen, die in produktiven Umgebungen regelmäßig zu unnötigen Angriffsflächen führen
- Ein interner Benutzer mit mehr Rechten, als für seine Aufgabe nötig sind
- Supply-Chain-Risiken über Base Images oder Dependencies
- Eine bekannte, aber ungepatchte Schwachstelle in einer Abhängigkeit
Was passiert, wenn ein Container kompromittiert wird?
Das ist die zentrale Frage, auf die dieser gesamte Guide letztlich antwortet: Wie groß ist der Blast Radius? Ein kompromittierter Container ist selten das eigentliche Problem — entscheidend ist, was von dort aus erreichbar wird.
kompromittiert
Container
den Host
Netzwerk
Movement
Jeder folgende Abschnitt dieses Guides adressiert einen Punkt in dieser Kette — mit dem Ziel, sie an einer möglichst frühen Stelle zu unterbrechen. Dieselbe Bewertungslogik — Risiko, Ursache, Prüfung, Maßnahme, Restrisiko — nutzen wir auch als Grundlage unserer Docker-Schulungen, weil sie sich in der Praxis besser überträgt als eine reine Regelliste.
Die wichtigsten Angriffsflächen
Eine Risikolandkarte statt einer langen Textliste. Die Priorität ist eine grobe Orientierung — keine universelle CVSS-Bewertung. Wie kritisch ein Punkt tatsächlich ist, hängt immer von der konkreten Architektur ab.
| Angriffsfläche | Typisches Risiko | Priorität |
|---|---|---|
| Docker Socket | Vollständige Kontrolle über Docker und potenziell den Host | Kritisch |
| Privileged Container | Weitreichende Host-Rechte ohne echte Notwendigkeit | Kritisch |
| Secrets | Credential Leakage über Image, Logs oder Environment | Hoch |
| Images | Supply-Chain-Risiken, bekannte Schwachstellen | Hoch |
| Host Mounts | Zugriff auf sensible Host-Daten | Hoch |
| Capabilities | Unnötige Kernel-Rechte über Default hinaus | Hoch |
| Registry | Manipulierte oder ungeprüfte Images gelangen in Production | Hoch |
| Veraltete Images | Bekannte, längst gepatchte Schwachstellen | Hoch |
| Netzwerk | Unnötig erreichbare interne Services | Mittel–Hoch |
Container nicht unnötig als Root ausführen
Drei Begriffe werden hier regelmäßig vermischt, obwohl sie technisch unterschiedliche Dinge bedeuten: Root innerhalb eines Containers, ein Non-root-Container und Rootless Docker. Diese Unterscheidung ist Voraussetzung für alles Weitere in diesem Abschnitt.
Non-root Container
Die USER-Anweisung im Dockerfile sorgt dafür, dass der Hauptprozess im Container nicht mit UID 0 läuft:
# System-User statt Root anlegen und verwenden
RUN addgroup --system app && adduser --system --ingroup app app
USER app
Das reduziert, was ein kompromittierter Prozess innerhalb des Containers anrichten kann — es sagt aber nichts darüber aus, welche Rechte der Docker-Daemon oder der Host dem Container insgesamt einräumen.
Rootless Docker
Rootless Mode betrifft eine andere Ebene: Hier läuft der Docker-Daemon selbst ohne Root-Rechte auf dem Host. Das verringert die möglichen Folgen bestimmter Angriffsklassen, weil weder Daemon noch Container von sich aus über Root-Rechte auf dem Host verfügen — es ist jedoch keine generelle Garantie gegen jede Form von Container Escape und ersetzt die übrigen Maßnahmen in diesem Guide nicht. Non-root-Container und Rootless Docker lösen unterschiedliche Probleme und schließen sich nicht gegenseitig aus.
Wann Root trotzdem benötigt wird
„Root ist per se schlecht“ ist keine brauchbare Regel. Manche Prozesse benötigen beim Start tatsächlich erhöhte Rechte — etwa um an einem privilegierten Port zu binden oder Dateiberechtigungen zu setzen — und wechseln danach kontrolliert zu einem eingeschränkten User. Entscheidend ist nicht die Abwesenheit von Root, sondern die Minimierung der Zeit und des Umfangs, in dem erhöhte Rechte tatsächlich vorliegen.
Kontrolle: Root-Prozesse im Container
Hoch
- Risiko
- Ein kompromittierter Root-Prozess im Container hat innerhalb des Containers uneingeschränkte Rechte und ist die Ausgangsbasis für eskalierende Angriffe — etwa in Kombination mit Capabilities, Host-Mounts oder dem Docker Socket.
- Ursache
- Viele Base Images starten standardmäßig als Root, und in Dockerfiles wird häufig einfach kein
USERgesetzt. - Prüfung
docker inspect --format '{{.Config.User}}' <container>sowiedocker top <container> -o user,pid,commzeigen, mit welchem User Prozesse tatsächlich laufen.- Maßnahme
USERim Dockerfile setzen, wo möglich fertige Non-root-Base-Images verwenden, in Compose/Runtime zusätzlichuser:explizit definieren.- Verifikation
- Nach dem Rebuild erneut
docker topprüfen und sicherstellen, dass die Anwendung mit eingeschränktem User weiterhin fehlerfrei läuft (Dateirechte, Ports <1024). - Trade-off
- Manche Legacy-Anwendungen erwarten Root-Rechte für bestimmte Operationen und benötigen zusätzliche Anpassung.
- Restrisiko
- Ein Non-root-Prozess mit unnötigen Capabilities oder Zugriff auf sensible Host-Mounts bleibt weiterhin riskant — Non-root allein ist keine vollständige Absicherung.
Docker Socket: warum /var/run/docker.sock besonders kritisch ist
Der Docker Socket ist kein „gefährliches File“, sondern der direkte Zugang zur Docker API. Wer ihn kontrolliert, kann im Zweifel jeden beliebigen Container starten — inklusive eines privilegierten Containers mit vollem Host-Zugriff.
Container
„Docker Socket niemals mounten“ ist als Regel richtig, aber als alleinige Aussage zu wenig, weil sie nicht erklärt, warum Teams es trotzdem tun: Monitoring-Tools, CI-Runner und Deployment-Automatisierung greifen häufig bewusst auf den Socket zu, um selbst Container zu steuern. Ein :ro-Mount löst das Problem dabei nicht zuverlässig — lesender Zugriff auf die Docker API reicht bereits aus, um Container-Definitionen, Images und teils auch Secrets auszulesen, und viele API-Operationen sind über einen „read-only“ gemounteten Socket weiterhin ausführbar, da :ro nur den Mount, nicht die API-Berechtigungen einschränkt.
Kontrolle: Docker Socket im Container
Kritisch
- Risiko
- Voller oder lesender Zugriff auf die Docker API aus einem Container heraus, faktisch gleichbedeutend mit weitreichender Kontrolle über den Host.
- Ursache
- Tooling, das Container orchestriert oder überwacht (CI-Runner, Deployment-Agenten, manche Monitoring-Stacks), benötigt scheinbar direkten Zugriff auf den Daemon.
- Prüfung
- Für alle laufenden Container Name, Mount-Quelle und -Ziel auflisten und auf
docker.sockfiltern:for c in $(docker ps -q); do docker inspect --format '{{.Name}}: {{range .Mounts}}{{.Source}} -> {{.Destination}} {{end}}' "$c"; done | grep docker.sock. - Maßnahme
- Zugriff auf einen dedizierten, mit minimalen Rechten ausgestatteten Proxy vor der Docker API beschränken (z. B. ein Socket-Proxy, der nur bestimmte API-Endpunkte erlaubt), oder die Notwendigkeit des Socket-Zugriffs architektonisch hinterfragen.
- Verifikation
- Nach der Umstellung erneut prüfen, welche API-Endpunkte über den Proxy erreichbar sind, und testen, dass nicht benötigte Operationen tatsächlich blockiert werden.
- Trade-off
- Ein Proxy erhöht die Komplexität der Infrastruktur und muss selbst gepflegt und aktualisiert werden.
- Restrisiko
- Auch ein eingeschränkter Proxy bleibt ein sensibler Angriffspunkt; die Kompromittierung des Proxy-Containers selbst ist weiterhin relevant.
Privileged Container und Linux Capabilities
--privileged und --cap-add werden oft synonym behandelt, sind aber sehr unterschiedlich weitreichend: --privileged hebt praktisch alle Einschränkungen auf, während einzelne Capabilities gezielt zusätzliche, klar abgegrenzte Kernel-Rechte vergeben.
Die passende Frage ist nicht „Brauchen wir --privileged?“, sondern: Welche konkrete Operation benötigt die Anwendung, welche Capability deckt genau diese Operation ab, und welches ist die minimale Berechtigung dafür?
Operation
Capability
Berechtigung
Drei Capabilities tauchen in der Praxis besonders häufig — und häufig unnötig breit vergeben — auf:
CAP_SYS_ADMIN— eine sehr breite Sammelrechte-Capability, die in vielen Fällen durch spezifischere Capabilities ersetzt werden kannCAP_NET_ADMIN— nötig für Netzwerkkonfiguration innerhalb des Containers, selten für normale Anwendungen erforderlichCAP_SYS_PTRACE— erlaubt das Debuggen fremder Prozesse und wird oft nur für Entwicklungs-/Debug-Zwecke temporär benötigt
Zusätzlich verhindert die Option no-new-privileges, dass ein Prozess zur Laufzeit zusätzliche Rechte erlangt, etwa über SUID-Binaries — ein einfacher, oft übersehener Baustein des Least-Privilege-Prinzips.
Kontrolle: Privileged Mode & Capabilities
Kritisch
- Risiko
- Weitreichender Host-Zugriff über Kernel-Rechte, die für den eigentlichen Anwendungszweck nicht erforderlich sind.
- Ursache
--privilegedwird häufig als schnelle Problemlösung für ein einzelnes Berechtigungsproblem eingesetzt, statt die konkrete Capability zu identifizieren.- Prüfung
docker inspect --format '{{.HostConfig.Privileged}}' <container>unddocker inspect --format '{{.HostConfig.CapAdd}}' <container>.- Maßnahme
--privilegedentfernen, benötigte Capability einzeln über--cap-addergänzen, alle Default-Capabilities, die nicht benötigt werden, über--cap-dropentfernen,no-new-privilegessetzen.- Verifikation
- Anwendung nach der Umstellung funktional testen und erneut per
docker inspectprüfen, welche Capabilities tatsächlich aktiv sind. - Trade-off
- Das Identifizieren der exakt benötigten Capability erfordert Testaufwand und ist nicht immer aus der Dokumentation ersichtlich.
- Restrisiko
- Auch einzelne Capabilities können in Kombination mit anderen Faktoren (z. B. Host-Mounts) ausnutzbar bleiben — Capabilities sind ein Baustein, keine vollständige Lösung.
Zusätzliche Isolation: seccomp, AppArmor und SELinux
Capabilities regeln, welche Rechtekategorien ein Prozess besitzt — sie sagen nichts darüber aus, welche konkreten Systemaufrufe (Syscalls) er nutzen darf. Genau hier setzen Linux Security Modules an, als zusätzliche Schicht im Sinne von Defense in Depth:
- Docker aktiviert standardmäßig ein seccomp-Profil, das eine große Zahl selten benötigter oder riskanter Syscalls blockiert. Dieses Profil ohne konkreten, geprüften Grund über
--security-opt seccomp=unconfinedzu deaktivieren, hebt genau diesen Schutz vollständig auf. - AppArmor oder SELinux ergänzen dies auf vielen Distributionen um Mandatory-Access-Control-Profile, die zusätzlich einschränken, auf welche Dateien und Ressourcen ein Container zugreifen darf — unabhängig von den im Container selbst gesetzten Berechtigungen.
- Ein Container, der mit
unconfinedläuft, sollte dafür eine dokumentierte, fachliche Begründung haben — nicht, weil ein Fehler beim Debuggen schneller verschwunden ist.
Für die meisten Anwendungen ist die richtige Maßnahme hier keine Konfiguration, sondern eine Unterlassung: die Standardprofile aktiviert lassen, statt sie bei der ersten Berechtigungsfehlermeldung leichtfertig zu deaktivieren.
Ressourcenlimits: wenn Verfügbarkeit zum Sicherheitsthema wird
Nicht jedes Risiko ist Privilege Escalation. Ein kompromittierter, fehlerhafter oder schlicht schlecht geschriebener Container kann CPU, Arbeitsspeicher oder Prozess-IDs des Hosts erschöpfen und damit andere Container auf demselben Host beeinträchtigen — ein klassisches Denial-of-Service- bzw. „Noisy Neighbor“-Szenario.
docker run --memory=512m --cpus=1 --pids-limit=200 shop-app
# in docker-compose.yml äquivalent:
deploy:
resources:
limits:
cpus: "1"
memory: 512M
pids: 200
Memory- und CPU-Limits begrenzen, wie stark ein einzelner Container die Host-Ressourcen belasten kann; ein PID-Limit verhindert, dass ein Container über Fork-Bomben oder ausufernde Prozesserzeugung die gesamte Prozesstabelle des Hosts füllt. Für produktive Umgebungen mit mehreren Containern auf demselben Host sind solche Limits ein einfacher, aber häufig ausgelassener Baustein — sie ersetzen keine der zuvor beschriebenen Maßnahmen, adressieren aber ein Risiko, das keine davon abdeckt.
Secrets sicher in Docker verwenden
Der häufigste Fehler ist schnell benannt:
ENV DB_PASSWORD=hunter2
Ein im Image gebackenes Secret bleibt in jedem Layer und jeder Kopie des Images bestehen — auch nach einer nachträglichen Löschung. Sinnvollere Optionen, mit unterschiedlichem Schutzniveau:
- Environment Variables zur Laufzeit (nicht im Image) — besser als ENV im Dockerfile, aber weiterhin über
docker inspectund Prozessumgebung einsehbar - .env-Dateien — praktisch für lokale Entwicklung, für Production ungeeignet, wenn sie versioniert oder unverschlüsselt abgelegt werden
- Docker Compose Secrets — Dateien, die als
/run/secrets/<name>in den Container gemountet werden, nicht Teil des Images - Gemountete Secret-Dateien — vom Orchestrator oder Secret Manager zur Laufzeit bereitgestellt
- Externe Secret Manager — zentrale Verwaltung, Rotation und Audit-Log außerhalb von Docker selbst
- CI/CD-Secrets — für Build- und Deployment-Zeitpunkt, mit eigenem Schutzbedarf
Sind Environment Variables für Secrets sicher?
Weder pauschal ja noch nein. Zur Laufzeit gesetzte Environment Variables sind deutlich besser als im Image gebackene Werte, bleiben aber über docker inspect, Prozessumgebung (/proc/<pid>/environ) und teils in Logging- oder Monitoring-Tools sichtbar, die Environment-Daten automatisch mit erfassen. Für einzelne, wenig kritische Konfigurationswerte ist das oft ein akzeptables Risiko — für Datenbank-Credentials oder API-Keys in produktiven Umgebungen in der Regel nicht.
Was passiert mit einem Secret nach der Kompromittierung des Containers?
Ein Punkt, der in den meisten Best-Practices-Listen fehlt: Secret Management schützt ein Credential nicht davor, dass ein kompromittierter Laufzeitprozess, der legitimen Zugriff auf dieses Credential hat, es einfach ausliest. Ein extern verwalteter, rotierter Secret ist sicherer gegen Diebstahl aus dem Image oder aus Logs — er ist nicht automatisch sicher gegen einen Angreifer, der bereits im Container mit denselben Rechten wie die Anwendung agiert. Das verschiebt die relevante Frage von „Wo liegt das Secret?“ zu „Wie schnell lässt es sich rotieren, wenn ein Container kompromittiert war?“.
docker history --no-trunc <image> und docker inspect --format '{{.Config.Env}}' <container> auf Klartext-Credentials durchsuchen.Sichere Docker Images und Supply Chain
Jedes Image ist eine Kette: Base Image, Dependencies, Build-Prozess, Registry, Deployment. Ein Fehler an irgendeinem Punkt dieser Kette wirkt sich auf alles aus, was daraus gebaut wird.
- Minimale Base Images verwenden — weniger installierte Software bedeutet eine kleinere Angriffsfläche
- Nur Images aus vertrauenswürdigen, bekannten Quellen als Basis nutzen
- Statt veränderlicher Tags (
latest) feste, idealerweise per Digest referenzierte Versionen verwenden - Unnötige Pakete und Build-Tools nicht ins finale Image übernehmen
- Multi-Stage Builds nutzen, um Build-Abhängigkeiten vom Runtime-Image zu trennen
- Images regelmäßig auf bekannte Schwachstellen scannen — als ein Signal unter mehreren, nicht als Freigabe-Garantie
- Einen definierten Rebuild-Prozess statt einmalig gebauter, dauerhaft laufender Images etablieren
# statt: FROM node:20-slim
FROM node:20-slim@sha256:1a2b3c4d... # exakte, unveränderliche Version
Warum ein Image mit null bekannten CVEs nicht automatisch sicher ist
Ein Scan-Ergebnis von null Treffern bedeutet: Zum Zeitpunkt des Scans waren keine bekannten Schwachstellen in den erfassten Komponenten registriert. Es sagt nichts über unentdeckte Schwachstellen, Fehlkonfiguration, unsichere Anwendungslogik oder Schwachstellen in Komponenten aus, die der Scanner nicht erfasst. Ein sauberer Scan ist ein Datenpunkt, kein Sicherheitsnachweis.
docker inspect --format '{{.Image}}' <container> und mit der erwarteten Digest/Version abgleichen.Docker Registry absichern
„Private Registry statt Docker Hub“ ist ein Anfang, keine vollständige Antwort. Entscheidend ist, wer entlang der Kette vom Build bis zum Deployment welches Recht besitzt.
An jedem Übergang lohnt sich dieselbe Frage: Wer darf welches Image erstellen, verändern und deployen? Konkret relevant sind dabei:
- Authentifizierung und Autorisierung pro Repository, nicht nur pro Registry-Instanz
- TLS-verschlüsselte Verbindungen zur Registry, auch intern
- Nachvollziehbare Herkunft (Provenance) der Images, wo technisch umsetzbar
- Unveränderliche Tags in Production, um nachträgliches Überschreiben eines bereits deployten Images zu verhindern
- Definierte Retention- und Löschregeln statt unbegrenzt wachsender Image-Historie
- Eigene, eingeschränkte Service-Accounts für automatisierte Push-/Pull-Vorgänge statt persönlicher Zugangsdaten
- Ein klarer Credential-Lifecycle inklusive Rotation für Registry-Zugänge
Volumes und Bind Mounts sicher konfigurieren
Ein Docker-Volume wird von Docker selbst verwaltet und ist vom Host-Dateisystem entkoppelt; ein Bind Mount bindet einen konkreten Host-Pfad direkt in den Container ein. Sicherheitstechnisch ist dieser Unterschied wichtig: Bind Mounts auf sensible Host-Verzeichnisse — etwa Konfigurationsdateien, SSH-Keys oder Cloud-Credentials des Hosts — verlängern den Blast Radius eines kompromittierten Containers direkt auf diese Daten.
Reicht :ro bei einem Bind Mount?
Teilweise. Ein :ro-Mount verhindert, dass der Container den Host-Pfad verändert — er verhindert nicht, dass der Inhalt gelesen wird. Wenn der eingebundene Pfad Credentials, private Keys oder andere sensible Inhalte enthält, bleibt ein rein lesender Zugriff für einen Angreifer oft bereits ausreichend. :ro ist damit ein sinnvoller zusätzlicher Schutz gegen Manipulation, aber kein Ersatz für die grundsätzliche Frage, ob dieser Pfad überhaupt eingebunden werden muss.
docker inspect --format \
'{{ range .Mounts }}{{ .Source }} -> {{ .Destination }} ({{ .Mode }}){{println}}{{ end }}' \
<container>
Docker Netzwerk absichern
„Nur notwendige Ports öffnen“ beschreibt das Ziel, nicht den Weg dorthin. Relevant ist die Unterscheidung zwischen dem, was auf dem Host veröffentlicht wird, und dem, was Container untereinander erreichen können.
In diesem Muster wird ausschließlich der Reverse Proxy auf dem Host veröffentlicht (-p bzw. ports:); Application und Database kommunizieren ausschließlich über ein internes Container-Netzwerk und benötigen selbst keine veröffentlichten Ports. Weitere relevante Punkte:
- Custom Networks statt der Default-Bridge nutzen, um Kommunikation gezielt zu segmentieren
- Nicht jeder Service, der einen Port öffnet, muss vom Host oder Internet erreichbar sein
- Host-Networking-Mode umgeht die Netzwerkisolation vollständig und sollte die Ausnahme, nicht der Standard sein
- Backend-Services wie Datenbanken in der Regel nur intern erreichbar machen
docker port <container>
docker network inspect <network>
Docker Host und Daemon absichern
Docker Security endet nicht auf Container-Ebene.
Ein sicher konfigurierter Container kann einen schlecht abgesicherten Docker Host nicht kompensieren.
- Docker Engine und Host-Betriebssystem regelmäßig aktualisieren
- Zugriff auf den Daemon eng begrenzen — Mitgliedschaft in der
docker-Gruppe ist faktisch gleichbedeutend mit Root-Rechten auf dem Host, da der Daemon mit Root-Rechten läuft - SSH- und administrativen Zugang zum Host absichern und auf die tatsächlich benötigten Personen begrenzen
- Dateisystemrechte für Docker-relevante Verzeichnisse (u. a. Volumes, Zertifikate) prüfen
- Aufgabentrennung zwischen Build-, Deployment- und Administrationsrechten etablieren, statt eines einzelnen Admin-Zugangs für alles
- Docker-Events und Logs aktiv beobachten, nicht nur Anwendungslogs
- Unnötige zusätzliche Software auf dem Host vermeiden, um die Angriffsfläche des Hosts selbst klein zu halten
Updates ohne Blindflug: Images patchen und neu bauen
Ein häufiges Muster in gewachsenen Umgebungen: Ein Image wurde einmal gebaut, läuft seitdem unverändert und wird als „stabil“ betrachtet — tatsächlich veraltet es dabei unbemerkt.
Update
Option
docker pull ist für sich genommen keine Update-Strategie — ohne Rebuild-Prozess bleibt unklar, welche Version tatsächlich läuft und wann sie zuletzt aktualisiert wurde. Bewegliche Tags wie latest verschärfen das zusätzlich, weil sich der Inhalt hinter demselben Namen unbemerkt ändern kann. Ein sinnvoller Rebuild-Turnus richtet sich nach dem tatsächlichen Risiko der Anwendung und ihrer Abhängigkeiten — eine feste Regel wie „alle sieben Tage“ ist willkürlich und weder für jede Anwendung nötig noch für jede ausreichend. Wichtiger als der Takt ist, dass Rebuild, Scan, Test und die Möglichkeit eines Rollbacks als zusammenhängender Prozess existieren.
Logging, Monitoring und Audit
Security besteht nicht nur aus Prävention, sondern auch aus der Fähigkeit zu erkennen, dass etwas passiert ist. Im Docker-Kontext relevant, ohne den Anspruch, ein vollständiges SIEM-Konzept zu ersetzen:
- Container-Logs zentral sammeln statt nur lokal auf dem Host vorzuhalten
- Docker-Daemon-Events (
docker events) beobachten — insbesondere unerwartete Container-Starts - Authentifizierungs-Events an Registry und Daemon protokollieren
- Änderungen an laufenden Images oder Konfigurationen erkennen (Configuration Drift)
- Neu auftretende privilegierte Container oder ungewöhnliche Capability-Kombinationen als Alarmsignal behandeln
Docker Security Audit: praktische Checkliste
Konkrete, prüfbare Fragen statt einer allgemeinen Aufforderung, „Docker sicher zu konfigurieren“.
Container
--privileged verwendet?no-new-privileges sinnvoll gesetzt?Docker API
docker.sock in einem Container gemountet?Images
Secrets
Netzwerk
Registry
Host
Docker Security Audit: Prioritäten nach Risiko
Eine lange Checkliste ohne Reihenfolge führt selten zu Handlung. Diese Einteilung gibt eine Orientierung, womit sinnvollerweise begonnen wird.
Sofort prüfen
- Docker Socket in Containern
- Privileged Containers
- Sensible Host-Mounts
- Exponierte Docker API
- Secrets im Image
- Unnötig veröffentlichte Services
Danach
- Non-root / Rootless umsetzen
- Capabilities reduzieren
- Registry-Berechtigungen ordnen
- Image-Lifecycle definieren
- Netzwerksegmentierung
Kontinuierlich
- Updates & Rebuilds
- Scanning
- Credential-Rotation
- Logging & Monitoring
- Regelmäßiges Config-Review
Diese Reihenfolge lässt sich für ein Erstaudit allein durcharbeiten. Sie dauerhaft im Team umzusetzen — als gemeinsamer Standard für Images, Rechte und Deployments, nicht als einmalige Aktion — ist meist der eigentlich schwierige Teil und genau der Punkt, an dem unsere Docker Security & Production Schulung ansetzt.
Beispiel: Unsicheres Docker-Setup Schritt für Schritt härten
Ein realistisches, bewusst unsicheres Ausgangsszenario: eine Web-Anwendung mit PostgreSQL, betrieben über Docker Compose, Images aus einer privaten Registry.
Ausgangszustand
Die Anwendung läuft als Root, der Docker Socket ist in einen Hilfs-Container gemountet, das Datenbank-Passwort steht als Environment-Variable direkt im Compose-File, der Datenbank-Port ist auf dem Host veröffentlicht, der App-Container besitzt breite zusätzliche Capabilities, und das Image referenziert einen beweglichen Tag ohne Pinning.
services:
app:
image: registry.example.com/shop-app:latest
ports:
- "3000:3000"
environment:
- DB_PASSWORD=hunter2
cap_add:
- SYS_ADMIN
volumes:
- /var/run/docker.sock:/var/run/docker.sock
db:
image: postgres:14
ports:
- "5432:5432"
environment:
- POSTGRES_PASSWORD=hunter2
Risikoanalyse
- Datenbank direkt vom Host/Internet aus erreichbar, obwohl nur die Anwendung sie benötigt
- Datenbank-Passwort im Klartext im Compose-File und in der Prozessumgebung sichtbar
- Docker Socket im App-Container ermöglicht bei Kompromittierung vollen Zugriff auf die Docker API
SYS_ADMINist eine sehr breite Capability, die die Anwendung mit hoher Wahrscheinlichkeit nicht in diesem Umfang benötigtlatestals Tag macht nicht nachvollziehbar, welche konkrete Version aktuell läuft
Hardening
services:
app:
image: registry.example.com/shop-app@sha256:9f1c2e...
user: app
ports:
- "3000:3000"
environment:
- DB_PASSWORD_FILE=/run/secrets/db_password
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
secrets:
- db_password
networks:
- internal
- edge
db:
image: postgres:14@sha256:7a3b1f...
environment:
- POSTGRES_PASSWORD_FILE=/run/secrets/db_password
secrets:
- db_password
networks:
- internal
secrets:
db_password:
external: true
networks:
internal:
internal: true
edge:
Der Docker Socket wurde entfernt, der Datenbank-Port wird nicht mehr veröffentlicht, das Passwort liegt als Secret statt als Klartext-Environment-Variable vor, beide Images sind per Digest fixiert, Capabilities wurden auf ALL entfernt und nur bei nachgewiesenem Bedarf gezielt wieder ergänzt, und der App-Container läuft als eingeschränkter User.
Zum Secret im Beispiel
external: true setzt voraus, dass db_password bereits außerhalb dieser Compose-Datei existiert — je nach Betriebsmodell z. B. als Docker Swarm Secret oder über einen externen Secret Manager, der die Datei zur Laufzeit bereitstellt. Das Beispiel zeigt bewusst nur die Übergabe des Secrets an den Container als Datei unter /run/secrets/, nicht dessen sicheren Speicherort. Welches konkrete Secret-Backend dafür infrage kommt, hängt vom Betriebsmodell ab und muss separat definiert werden — Compose allein löst die Frage der sicheren Aufbewahrung nicht automatisch.
Verification
docker inspect --format '{{.Config.User}}' shop-app
docker inspect --format '{{.HostConfig.CapAdd}}' shop-app
docker port shop-app
docker inspect --format '{{.Mounts}}' shop-app | grep docker.sock # sollte leer sein
Restrisiko
Diese Maßnahmen reduzieren konkrete, benannte Risiken — sie beseitigen nicht automatisch Schwachstellen in der Anwendungslogik selbst, kompromittierte CI/CD-Zugänge, mit denen ein neues Image gepusht werden könnte, oder eine unzureichende IAM-Struktur rund um die Registry. Das gehärtete Setup ist eine deutliche Verbesserung gegenüber dem Ausgangszustand, kein Beleg vollständiger Sicherheit.
Wo Docker Hardening nicht ausreicht
Ein sauber gehärtetes Docker-Setup löst nicht jedes Sicherheitsproblem. Realistische Grenzen, die in diesem Guide bewusst nicht versprochen werden:
- Eine Schwachstelle in der Anwendung selbst
- Eine kompromittierte CI/CD-Pipeline
- Gestohlene Production-Credentials außerhalb von Docker
- Eine Kernel-Schwachstelle auf dem Host
- Eine unzureichende IAM-/Berechtigungsstruktur im Unternehmen
- Fehlendes Monitoring, das einen Vorfall unbemerkt lässt
- Eine kompromittierte Dependency in der Supply Chain
Wann Docker Security komplexer wird
Bei wenigen Docker-Hosts lassen sich die meisten der hier beschriebenen Kontrollen direkt auf Host-, Container- und Registry-Ebene umsetzen. Mit wachsender Zahl von Hosts, Services und Teams verschiebt sich ein Teil des Problems in Richtung Orchestrierung, zentraler Policy Enforcement und zentralisiertem Secret- und Identity-Management — Themen, die über den Rahmen von Docker allein hinausgehen.
Häufige Fragen zur Docker Security
Ist Docker sicher für Production?
Docker selbst bringt sinnvolle Standardmechanismen mit (u. a. ein aktives seccomp-Profil, Namespace-Isolation). Ob eine konkrete Umgebung produktionstauglich sicher ist, hängt jedoch von der Konfiguration ab — Rechte, Socket-Zugriff, Secrets, Netzwerk und Image-Herkunft entscheiden mehr als Docker als Technologie.
Sollten Docker Container als Root laufen?
Im Regelfall nicht. Ein Prozess sollte nur dann mit Root-Rechten im Container laufen, wenn dafür ein konkreter, geprüfter Grund besteht — etwa das Binden an einen privilegierten Port beim Start.
Ist Rootless Docker sicherer?
Rootless Docker verringert die möglichen Folgen bestimmter Angriffsklassen, weil der Daemon selbst ohne Host-Root-Rechte läuft. Es ist kein genereller Schutz gegen jede Form von Container Escape und ersetzt Maßnahmen wie Non-root-User oder Capability-Reduktion nicht.
Warum ist der Docker Socket gefährlich?
Der Docker Socket ist der direkte Zugang zur Docker API. Wer ihn erreicht, kann in vielen Fällen neue — auch privilegierte — Container starten und damit effektiv Host-Zugriff erlangen. Ein :ro-Mount schränkt dabei nur den Mount ein, nicht die API-Rechte.
Sind Environment Variables für Docker Secrets sicher?
Besser als Secrets im Image, aber nicht ohne Restrisiko: Sie bleiben über docker inspect und die Prozessumgebung einsehbar. Für unkritische Konfigurationswerte oft vertretbar, für Datenbank-Credentials oder API-Keys in Production meist nicht ausreichend.
Wie prüft man die Sicherheit einer Docker-Umgebung?
Mit einer konkreten, nach Risiko priorisierten Checkliste statt einer allgemeinen Einschätzung — beginnend bei Docker Socket, privilegierten Containern und exponierten Secrets, danach Rechte, Registry und Netzwerksegmentierung.
Docker Security nicht nur prüfen, sondern im Team beherrschen
Wenn Docker bereits produktiv eingesetzt wird, entstehen Sicherheitsprobleme selten durch eine einzelne falsche Einstellung, sondern durch unterschiedliche Arbeitsweisen im Team: Images werden unterschiedlich gebaut, Rechte unterschiedlich vergeben, Secrets unterschiedlich behandelt. In der Docker Security & Production Schulung arbeitet Ihr Team genau an diesen Zusammenhängen — von Container-Rechten und Images bis zu Registry, Secrets und Production Hardening.
Dieser Guide ersetzt keine individuelle Sicherheitsbewertung Ihrer Infrastruktur und ist kein Ersatz für ein vollständiges Security-Audit durch qualifiziertes Personal.
