Docker Hardening: So schützt du Images, Secrets und User im Alltag

Docker Hardening: So schützt du Images, Secrets und User im Alltag - IT-Glossary

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.

0 Kommentare

Hinterlasse einen Kommentar

An der Diskussion beteiligen?
Hinterlasse uns deinen Kommentar!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert