Docker Security für produktive Umgebungen: Risiken, Hardening und Audit-Checkliste

Docker Security für produktive Umgebungen: Risiken, Hardening und Audit-Checkliste

Updated

Docker Security Guide

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.

DevOps & Administration
Niveau: Mittel–Fortgeschritten
Production-Fokus

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.

Container
kompromittiert
Rechte im
Container
Zugriff auf
den Host
Zugriff im
Netzwerk
Secrets
Lateral
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:

Dockerfile
# 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 USER gesetzt.
Prüfung
docker inspect --format '{{.Config.User}}' <container> sowie docker top <container> -o user,pid,comm zeigen, mit welchem User Prozesse tatsächlich laufen.
Maßnahme
USER im Dockerfile setzen, wo möglich fertige Non-root-Base-Images verwenden, in Compose/Runtime zusätzlich user: explizit definieren.
Verifikation
Nach dem Rebuild erneut docker top prü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
Docker API
Neuer priv.
Container
Host

„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.sock filtern: 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?

Benötigte
Operation
Erforderliche
Capability
Minimale
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 kann
  • CAP_NET_ADMIN — nötig für Netzwerkkonfiguration innerhalb des Containers, selten für normale Anwendungen erforderlich
  • CAP_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
--privileged wird 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> und docker inspect --format '{{.HostConfig.CapAdd}}' <container>.
Maßnahme
--privileged entfernen, benötigte Capability einzeln über --cap-add ergänzen, alle Default-Capabilities, die nicht benötigt werden, über --cap-drop entfernen, no-new-privileges setzen.
Verifikation
Anwendung nach der Umstellung funktional testen und erneut per docker inspect prü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=unconfined zu 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 unconfined lä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.

Shell / Compose — Ressourcenlimits
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:

Dockerfile — unsicher
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 inspect und 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?“.

PrüfungImage auf gebackene Secrets prüfen: docker history --no-trunc <image> und docker inspect --format '{{.Config.Env}}' <container> auf Klartext-Credentials durchsuchen.
MaßnahmeSecrets aus Dockerfile/Image entfernen, auf Datei-basierte Secrets oder externen Secret Manager umstellen, Rotation definieren.
RestrisikoEin Runtime-Zugriff mit legitimen Anwendungsrechten kann das Secret weiterhin auslesen — Rotationsgeschwindigkeit nach einem Vorfall bleibt entscheidend.

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
Dockerfile — Digest-Pinning statt beweglichem Tag
# 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.

PrüfungFür laufende Container das exakt verwendete Image feststellen: docker inspect --format '{{.Image}}' <container> und mit der erwarteten Digest/Version abgleichen.
MaßnahmeBase Images pinnen, Multi-Stage Builds nutzen, Scanning in die CI-Pipeline einbauen, Rebuild-Prozess statt einmaligem Build etablieren.
RestrisikoScanning erkennt bekannte Schwachstellen in erfassten Komponenten — nicht Fehler in der eigenen Anwendungslogik oder unentdeckte Schwachstellen.

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.

Developer
CI
Registry
Production

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.

Shell — Prüfung eingebundener Pfade
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.

Internet
Reverse Proxy
Application
Database

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
Shell — veröffentlichte Ports auditieren
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.

Base-Image-
Update
Rebuild
Scan
Test
Deployment
Rollback-
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

Läuft der Prozess als Root?
Wird --privileged verwendet?
Welche zusätzlichen Capabilities besitzt der Container?
Ist no-new-privileges sinnvoll gesetzt?
Welche Host-Verzeichnisse sind eingebunden?
Sind CPU-, Memory- und PID-Limits gesetzt?

Docker API

Ist docker.sock in einem Container gemountet?
Wer besitzt Zugriff auf den Docker Daemon bzw. die API?
Ist Remote-Zugriff auf den Daemon erforderlich, und ist er abgesichert?

Images

Woher stammen die verwendeten Base Images?
Werden Images reproduzierbar gebaut?
Werden bekannte Schwachstellen regelmäßig geprüft?
Lässt sich jedes verwendete Image eindeutig identifizieren (Tag/Digest)?
Existiert ein definierter Rebuild-Prozess?

Secrets

Befinden sich Secrets im Dockerfile?
Befinden sich Secrets im gebauten Image?
Wer kann die verwendeten Secrets lesen?
Wie und wie oft werden Secrets rotiert?

Netzwerk

Welche Ports sind veröffentlicht?
Müssen diese tatsächlich vom Host bzw. Internet erreichbar sein?
Sind interne Services unnötig exponiert?

Registry

Wer darf Images pushen?
Wer darf Production-Images verändern?
Gibt es getrennte Credentials für unterschiedliche Zugriffsebenen?
Ist nachvollziehbar, welches konkrete Image aktuell deployt ist?

Host

Sind Docker Engine und Host-Betriebssystem aktuell?
Wer besitzt administrative Rechte auf dem Host?
Werden Docker-Events und -Logs überwacht?

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.

docker-compose.yml — vorher (unsicher)
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_ADMIN ist eine sehr breite Capability, die die Anwendung mit hoher Wahrscheinlichkeit nicht in diesem Umfang benötigt
  • latest als Tag macht nicht nachvollziehbar, welche konkrete Version aktuell läuft

Hardening

docker-compose.yml — nachher (gehärtet)
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

Shell
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.

Docker Schulungen ansehen →

Dieser Guide ersetzt keine individuelle Sicherheitsbewertung Ihrer Infrastruktur und ist kein Ersatz für ein vollständiges Security-Audit durch qualifiziertes Personal.

avatar