Docker Hardening: So schützt du Images, Secrets und User im Alltag
Docker macht Anwendungen portabel und schnell einsatzbereit. Genau diese Stärke bringt Verantwortung mit sich, denn Container teilen sich den Kernel des Hosts. Ein kleiner Fehler in der Konfiguration kann sich daher groß auswirken. Die Lösung ist kein einzelnes Tool, sondern eine klare Sicherheitsroutine, die schon beim Bauen des Images beginnt und sich bis in den Betrieb zieht.
In diesem Leitfaden bekommst du praxisnahe Schritte, die du sofort anwenden kannst. Du lernst, sichere Images zu bauen, Secrets sauber zu handhaben und Container ohne Root-Rechte zu betreiben. Außerdem siehst du, wie Netzwerkisolation, Updates und Laufzeitkontrollen zusammenspielen. Ziel ist ein stabiles Grundniveau, das du später erweitern kannst.
Grundlagen: Was Container sicher oder unsicher macht
Container sind leichtgewichtig, weil sie den Kernel des Hosts mitnutzen. Das ist effizient, bedeutet aber: Unsichere Images, zu weit gefasste Rechte oder offene Ports erhöhen dein Risiko. Sicherheit beginnt beim Image und setzt sich über Runtime-Optionen, Netzwerk, Secret-Management und kontinuierliche Updates fort. Denke in kleinen, klaren Schritten, statt alles auf einmal zu ändern.
Sichere Images bauen
Schlanke Basisimages wählen
Je weniger Pakete im Image liegen, desto kleiner die Angriffsfläche. Nutze alpine oder distroless, sofern kompatibel. Entferne Build-Werkzeuge aus dem finalen Image, damit keine unnötigen Tools zurückbleiben.
Reproduzierbare Builds und Versionen
Pinne Versionen in der Dockerfile, damit Builds reproduzierbar bleiben. So verhinderst du, dass bei jedem Build ungetestete Pakete einfließen. Dokumentiere außerdem, welche Ports die App wirklich benötigt.
Mehrstufige Builds nutzen
Trenne Build und Runtime. Im ersten Schritt baust du, im zweiten läuft nur das Nötige.
# Build
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Runtime
FROM gcr.io/distroless/nodejs22
WORKDIR /app
COPY --from=build /app/dist ./dist
USER 10001
CMD ["dist/server.js"]
.dockerignore korrekt pflegen
Schließe .git, node_modules, .env und andere sensible oder unnötige Artefakte aus. So landen keine Geheimnisse und kein Ballast im Image.
Images scannen und signieren
Integriere Image-Scanning in deine CI, um bekannte Schwachstellen früh zu finden. Erzeuge eine SBOM und signiere Images, damit du ihre Integrität und Herkunft nachweisen kannst.
Container ohne Root betreiben
Dedizierten Benutzer verwenden
Starte Prozesse nicht als root. Lege in der Dockerfile einen nicht privilegierten User an und setze Eigentümerrechte korrekt.
RUN adduser --disabled-password --gecos "" app && \
mkdir -p /app && chown -R app:app /app
USER app
Linux-Capabilities reduzieren
Container brauchen selten alle Fähigkeiten. Cap-Drop entfernt Überflüssiges, Cap-Add gibt gezielt zurück, was wirklich nötig ist.
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE myapp
Schreibzugriffe minimal halten
Nutze ein Read-Only Dateisystem und schreibe nur in explizite Volumes. Das erschwert Manipulationen und macht Verhalten vorhersehbarer.
docker run --read-only -v app-data:/data myapp
Zusätzliche Isolation aktivieren
Setze Seccomp, AppArmor oder SELinux ein. Standardprofile blockieren riskante Syscalls und begrenzen die Wirkung von Exploits. Nutze, was dein Host sauber unterstützt.
Secrets richtig handhaben
Keine Secrets im Code oder Image
Passwörter, API-Keys und Zertifikate gehören nicht in Dockerfiles, Images oder Git-Repos. Umgebungsvariablen sind bequem, aber oft zu weit lesbar.
Geeignete Secret-Backends verwenden
Mit Docker Swarm, Kubernetes oder externen Managern wie Vault übergibst du Secrets nur zur Laufzeit und gezielt an den Dienst, der sie braucht. Plane Rotation und Audit gleich mit ein.
Prinzip der minimalen Rechte
Jeder Dienst erhält nur das eine Secret, das er wirklich benötigt. So begrenzt du die Folgen, falls ein Container kompromittiert wird.
Netzwerk und Isolation
Eingehende Verbindungen strikt öffnen
Öffne nur Ports, die wirklich extern erreichbar sein müssen. Interne Dienste bleiben intern.
docker run -p 8080:8080 myapp
Eigene Netzwerke nutzen
Lege benutzerdefinierte Netzwerke an. So steuerst du, welche Container miteinander sprechen dürfen, und hältst andere strikt getrennt.
Ausgehenden Traffic kontrollieren
Erlaube nur den notwendigen Egress, etwa zu Datenbanken, APIs oder Update-Repositories. Das reduziert Seitwärtsbewegung und Datenabfluss.
Updates, Patches und Abhängigkeiten
Regelmäßig neu bauen
Baue Images regelmäßig neu, damit Sicherheitsupdates einfließen. Plane Patch-Zyklen, damit du nicht hinterherläufst, und teste vor dem Rollout.
Dependencies aktuell halten
Pflege Lockfiles und nutze Sicherheitswarnungen der Paketmanager. Aktualisiere gezielt, damit Funktion und Sicherheit im Gleichgewicht bleiben.
Laufzeitabsicherung und Observability
Ressourcen begrenzen
Setze Limits für CPU und RAM. So verhinderst du, dass ein Container den Host überlastet.
docker run --cpus=1 --memory=512m myapp
Healthchecks und automatisches Heilen
Definiere Healthchecks, damit fehlerhafte Container schnell erkannt und neu gestartet werden.
HEALTHCHECK --interval=30s --timeout=3s CMD curl -f http://localhost:8080/health || exit 1
Zentrale Logs und Metriken
Sammle Logs, Metriken und Events zentral. Unerwartete Restart-Zähler, Peaks bei CPU oder Netzwerk sind oft Frühwarnzeichen.
Sichere Entwicklungs- und Delivery-Pipeline
Shift Left Security
Prüfe Sicherheit schon im Pull Request: Linting, Dependency-Checks, Image-Scanning. Früh gefundene Fehler sind günstiger und leichter zu beheben.
Unveränderliche Deployments
Arbeite mit immutable Images. Keine manuellen Eingriffe auf Servern. Änderungen passieren nur über neue Builds und definierte Pipelines.
Signierte Promotion
Erlaube Promotion in Test und Produktion nur für signierte, gescannte Images. Dokumentiere die Build-Provenance, damit du Vertrauen nachweisen kannst.
Beispiel: Minimal gehärtete Dockerfile und Run-Flags
FROM gcr.io/distroless/nodejs22
WORKDIR /app
COPY dist/ ./dist
USER 10001
EXPOSE 8080
CMD ["dist/server.js"]
docker run \
--read-only \
--cap-drop=ALL \
--cpus=1 \
--memory=512m \
myapp
Häufige Fehler und wie du sie vermeidest
Viele Probleme wiederholen sich: Secrets im Repo, Root-Container, aufgeblasene Images, zu breite Netzwerkfreigaben, fehlende Scans und kein Patch-Prozess. Wenn du diese Punkte systematisch angehst und deine Maßnahmen schrittweise automatisierst, erreichst du schnell mehr Sicherheit bei geringem Aufwand.
Fazit
Docker Sicherheit ist ein Prozess, kein einmaliges Projekt. Mit schlanken, geprüften Images, Non-Root Usern, sauberem Secret-Management, reduzierten Capabilities, Read-Only Dateisystem, klaren Netzwerkgrenzen, regelmäßigen Updates und sichtbarer Laufzeitüberwachung erreichst du ein stabiles, praxistaugliches Sicherheitsniveau. Baue darauf auf, automatisiere, dokumentiere und halte deine Standards aktuell. So bleiben deine Container schnell, verlässlich und sicher.



Hinterlasse einen Kommentar
An der Diskussion beteiligen?Hinterlasse uns deinen Kommentar!