Docker & Kubernetes: Leitfaden zur Container-Sicherheit
Container haben die Art und Weise, wie wir Software bereitstellen, verändert – aber viele Teams liefern sie mit Root-Zugriff, veralteten Images und exponierten Geheimnissen. Hier ist der vollständige Härtungsleitfaden.
Inhaltsverzeichnis
- Das Container-Sicherheits-Missverständnis
- Docker Image Härtung
- Minimale Base-Images verwenden
- Multi-Stage Builds
- Niemals als Root ausführen
- Images auf Schwachstellen scannen
- Docker Runtime-Sicherheit
- Fähigkeiten verringern
- Seccomp und AppArmor
- Niemals --privileged verwenden
- Kubernetes Sicherheitshärtung
- Pod Security Standards
- RBAC: Geringste Privilegien für Service Accounts
- Geheimniseverwaltung
- Netzwerkrichtlinien
- Kontinuierliche Sicherheitslage
Das Container-Sicherheits-Missverständnis
Ein häufiges Missverständnis ist, dass Container eine starke Isolation bieten, die vergleichbar mit virtuellen Maschinen ist. Das ist nicht der Fall. Container teilen den Host-Kernel – eine Container-Escape-Schwachstelle, die Code-Ausführung im Host-Kernel erreicht, gewährt Zugriff auf jeden Container auf diesem Host sowie den Host selbst. Container-Sicherheit geht darum, den Schadensradius eines kompromittierten Containers zu reduzieren, nicht darum anzunehmen, dass die Grenze undurchdringbar ist.
Die Angriffsfläche umfasst das Container-Image, die Runtime-Konfiguration, die Orchestrierungsplattform, das Netzwerk und die Schicht zur Geheimniserewaltung. Die Härtung muss alle Schichten berücksichtigen.
Docker Image Härtung
Minimale Base-Images verwenden
Jedes Paket in einem Base-Image ist eine potenzielle Schwachstelle. Bevorzugen Sie Distroless-Images (Googles Images ohne Shell, Paketmanager oder OS-Tools) oder Alpine Linux (musl libc, apk, ~5MB):
# Statt ubuntu:22.04
FROM gcr.io/distroless/java21-debian12
Distroless-Images können nicht interaktiv hineingewechselt werden – dies schränkt die Optionen eines Angreifers erheblich ein, wenn der Container kompromittiert wird.
Multi-Stage Builds
Build-Abhängigkeiten (Compiler, Build-Tools, Test-Frameworks) sollten niemals im Produktions-Image vorhanden sein:
FROM golang:1.22 AS builder
WORKDIR /app
COPY . .
RUN go build -o server .
FROM gcr.io/distroless/static-debian12
COPY --from=builder /app/server /server
ENTRYPOINT ["/server"]
Das finale Image enthält nur die kompilierte Binärdatei und ihre Runtime-Abhängigkeiten.
Niemals als Root ausführen
Standardmäßig laufen Prozesse in Containern als Root (UID 0). Wenn ein Container-Escape auftritt, hat der Angreifer Root auf dem Host. Erstellen Sie immer einen Nicht-Root-Benutzer:
RUN useradd -u 1001 -r appuser
USER appuser
Kombinieren Sie dies mit einem --read-only-Dateisystem und --tmpfs /tmp für Orte, an denen Schreibzugriff benötigt wird.
Images auf Schwachstellen scannen
Integrieren Sie Image-Scanning in Ihre CI/CD-Pipeline:
# Trivy – schneller, umfassender Schwachstellenscanner
trivy image myapp:latest
# Grype – Alternative mit SBOM-Unterstützung
grype myapp:latest
Lassen Sie den Build fehlschlagen, wenn hohe oder kritische CVEs gefunden werden. Erstellen Sie Base-Images regelmäßig neu und aktualisieren Sie diese – nicht nur, wenn Sie Anwendungscode ändern.
Docker Runtime-Sicherheit
Fähigkeiten verringern
Linux-Fähigkeiten unterteilen das Alles-oder-nichts-Privileg-Modell von Root in diskrete Einheiten. Verringern Sie alle Fähigkeiten und fügen Sie nur hinzu, was die Anwendung benötigt:
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE myapp
Seccomp und AppArmor
Dockers Standard-Seccomp-Profil blockiert ~44 gefährliche Syscalls. Verwenden Sie es explizit und erwägen Sie ein benutzerdefiniertes Profil für sensible Workloads. AppArmor- oder SELinux-Profile fügen mandatory access control zusätzlich zum Kernel hinzu:
docker run --security-opt seccomp=profile.json myapp
docker run --security-opt apparmor=docker-default myapp
Niemals --privileged verwenden
Das --privileged-Flag gibt dem Container nahezu vollständigen Host-Zugriff und deaktiviert alle Sicherheitsisolierungen. Es ist gelegentlich für spezifische Anwendungsfälle erforderlich (wie die Ausführung von Docker-in-Docker), sollte aber in der Produktion vollständig vermieden werden und bei Sicherheitsüberprüfungen als sofortiges Warnsignal behandelt werden.
Kubernetes Sicherheitshärtung
Pod Security Standards
Kubernetes erzwingt Sicherheitsrichtlinien über Pod Security Standards (ersetzt die veraltete PodSecurityPolicy):
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
Das restricted-Profil erzwingt: keine privilegierten Container, kein Root-Benutzer, keine Privilegieneskalation, erforderliches Seccomp-Profil, alle Fähigkeiten verringert.
RBAC: Geringste Privilegien für Service Accounts
Jeder Pod läuft mit einem Service Account. Standardmäßig kann dieser Service Account die Kubernetes API erreichen. Wenden Sie das Prinzip der geringsten Privilegien an:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-role
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get"]
Prüfen Sie mit kubectl auth can-i --list --as=system:serviceaccount:default:myapp. Deaktivieren Sie das automatische Einbinden von Service-Account-Tokens, wenn nicht benötigt: automountServiceAccountToken: false.
Geheimniseverwaltung
Kubernetes Secrets sind standardmäßig Base64-kodiert, nicht verschlüsselt. Verwenden Sie:
- Verschlüsselung im Ruhezustand: Aktivieren Sie
EncryptionConfigurationim API-Server, um Secrets in etcd zu verschlüsseln - Externe Geheimnisverwaltung: AWS Secrets Manager, HashiCorp Vault oder GCP Secret Manager über den External Secrets Operator
- Legen Sie niemals Geheimnisse in ConfigMaps, Umgebungsvariablen in Deployment-Specs (über
kubectl describesichtbar) oder Container-Images ab
Netzwerkrichtlinien
Standardmäßig können alle Pods in einem Kubernetes-Cluster miteinander kommunizieren. Implementieren Sie NetworkPolicy zur Mikrosegmentierung:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
spec:
podSelector: {}
policyTypes: [Ingress]
Fügen Sie dann explizite Erlaubnisregeln nur für notwendige Kommunikationspfade hinzu. Verwenden Sie ein CNI-Plugin, das NetworkPolicy erzwingt (Calico, Cilium, Weave).
Kontinuierliche Sicherheitslage
- Verwenden Sie Falco (CNCF Runtime-Sicherheitstool), um verdächtiges Verhalten zur Laufzeit zu erkennen: unerwartete Shell-Ausführungen, ausgehende Verbindungen zu neuen IPs, Privilegieneskalationsversuche
- Scannen Sie Cluster-Konfigurationen mit kube-bench (CIS Kubernetes Benchmark) und dem Trivy-Operator
- Aktivieren Sie Audit-Protokollierung auf dem Kubernetes API-Server und senden Sie Protokolle an ein SIEM
- Rotieren Sie regelmäßig Image-Digests und automatisieren Sie Abhängigkeits-Updates mit Renovate oder Dependabot