Container Escape Prevention — Du deployst Container ohne Hardening. Privilegierter Container, Angreifer hat Root auf Host. Lateral Movement, dein Cluster ist kompromittiert.
Du deployst Container ohne Hardening. Privilegierter Container, Angreifer hat Root auf Host. Lateral Movement, dein Cluster ist kompromittiert. Hier ist, wie du das verhinderst.
Was ist ein Container Escape? Einfach erklärt.
Ein Container Escape ist, wenn ein Angreifer aus der Container-Isolation ausbricht und Zugriff auf den Host-OS oder andere Container erhält. Häufige Vektoren: privilegierte Container (--privileged), Docker Socket Mounts (/var/run/docker.sock), fehlende seccomp/AppArmor Profile, Kernel CVEs (runc/containerd). Container Escapes sind häufiger als Kernel-Exploits — meist durch Fehlkonfiguration, nicht 0-Day-Exploits. Gute Container Security: Pod Security Standards (restricted), seccomp/AppArmor Profile, Read-Only Root Filesystem, gVisor Sandbox für untrusted Workloads.
↓ Springe direkt zur technischen Tiefe5 Container Escape Vektoren & Fixes
Running containers with --privileged grants full host capabilities. Trivial escape via /proc/sysrq-trigger, device mounts, or kernel module loading.
# WRONG — never run in production
docker run --privileged myimage
# CORRECT — drop ALL capabilities, add only what's needed
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE myimage
# Kubernetes: enforce via Pod Security Standards
apiVersion: v1
kind: Pod
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- name: app
securityContext:
allowPrivilegeEscalation: false
privileged: false
capabilities:
drop: ["ALL"]
add: ["NET_BIND_SERVICE"] # only if neededMounting host paths like /, /etc, /var/run/docker.sock gives container full host access. Docker socket mount = root on host.
# WRONG — mounts giving host escape
docker run -v /:/host myimage # Full host filesystem
docker run -v /etc:/etc myimage # Host config
docker run -v /var/run/docker.sock:/var/run/docker.sock myimage # Docker-in-Docker escape
# CORRECT — mount only what's needed, read-only where possible
docker run -v /data/app:/app:ro myimage
# Kubernetes: OPA Gatekeeper policy blocking docker.sock mounts
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPVolumeTypes
metadata:
name: psp-volume-types
spec:
match:
kinds: [{apiGroups: [""], kinds: ["Pod"]}]
parameters:
volumes:
- "configMap"
- "emptyDir"
- "projected"
- "secret"
- "downwardAPI"
- "persistentVolumeClaim"
# hostPath EXCLUDED — no host mountsWithout seccomp, containers can call any kernel syscall. 300+ syscalls available — many enable privilege escalation (ptrace, mount, keyctl, clone with new namespaces).
# Apply seccomp RuntimeDefault (blocks 100+ dangerous syscalls)
# Docker:
docker run --security-opt seccomp=/path/to/profile.json myimage
# Kubernetes — apply to all containers via RuntimeDefault:
apiVersion: v1
kind: Pod
spec:
securityContext:
seccompProfile:
type: RuntimeDefault # Blocks dangerous syscalls automatically
# AppArmor (Ubuntu/Debian):
docker run --security-opt apparmor=docker-default myimage
# OpenClaw: detect containers running without seccomp profile
openclaw check --namespace production --rule no-seccomp-profileWritable container filesystem allows attackers to modify binaries, add persistence, install tools after gaining initial access.
# Kubernetes: enforce read-only root filesystem
spec:
containers:
- name: app
securityContext:
readOnlyRootFilesystem: true
volumeMounts:
- name: tmp
mountPath: /tmp # tmpfs for writable temp
- name: var-run
mountPath: /var/run # tmpfs for runtime files
volumes:
- name: tmp
emptyDir:
medium: Memory
- name: var-run
emptyDir:
medium: Memory
# Docker:
docker run --read-only --tmpfs /tmp --tmpfs /var/run myimageSharing host PID/IPC/network namespaces with the container collapses isolation boundaries. hostPID=true allows container to see and signal all host processes.
# Kubernetes: explicitly prohibit host namespace sharing
spec:
hostPID: false # Default false — but set explicitly
hostIPC: false # Default false — but set explicitly
hostNetwork: false # Default false — only enable if actually needed
# OPA Gatekeeper constraint to block hostPID/hostIPC:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPHostNamespace
metadata:
name: psp-host-namespace
spec:
match:
kinds: [{apiGroups: [""], kinds: ["Pod"]}]
# Constraint: hostPID and hostIPC must be falseReal-World Scars: Production Incidents
--privileged Container deployed, Angreifer hat Root auf Host, greift alle anderen Container an. Fix: Pod Security Standards 'restricted' erzwingen, keine privilegierten Container.
Docker Socket in Container gemountet, Angreifer kontrolliert Docker Daemon, spawnet bösartige Container. Fix: hostPath Mounts verbieten, OPA Gatekeeper für Volume-Typen.
Sofortmaßnahmen: Was heute tun?
Pod Security Standards aktivieren
'restricted' Profil auf Cluster-Level erzwingen.
seccomp RuntimeDefault erzwingen
seccompProfile.type: RuntimeDefault für alle Pods.
Read-Only Root Filesystem
readOnlyRootFilesystem: true für alle Container.
gVisor für untrusted Workloads
RuntimeClass gvisor für Multi-Tenant.
Interaktive Container Security Checkliste
Container Security Score Calculator
Industrie-Durchschnitt: 15/100
Häufige Fragen
Was ist ein Container Escape und wie häufig sind sie?
Ein Container Escape ist, wenn ein Angreifer, der einen Container kompromittiert hat, aus der Container-Isolation ausbricht und Zugriff auf den Host-OS oder andere Container erhält. Häufige Vektoren: privilegierte Container (trivial ausnutzbar), docker.sock Mounts (sofortiger Root auf Host), Kernel CVEs in runc/containerd (CVE-2024-21626 runc escape), gefährliche Syscalls ohne seccomp (ptrace, mount). Real-World-Frequenz: Container Escapes werden in fast jedem Kubernetes-Security-Audit gefunden. Fehlkonfigurationen (privilegierte Container, Socket-Mounts) sind viel häufiger als Kernel-Exploits — und einfacher zu beheben.
Was ist gVisor und wann sollte ich es nutzen?
gVisor ist ein User-Space-Kernel in Go (entwickelt von Google), der Container-Syscalls abfängt, bevor sie den Host-Kernel erreichen. Anstatt dass Syscalls direkt zum Linux-Kernel gehen, verarbeitet gVisor's Sentry sie. Warum das wichtig ist: selbst wenn ein Container-Prozess eine Kernel-Vulnerability ausnutzt, exploitet er gVisor's Kernel — nicht den Host-Kernel. Ein gVisor-Escape würde einen zweiten Exploit gegen gVisor selbst erfordern. Nutze gVisor wenn: untrusted Workloads (z.B. user-submitted code), Multi-Tenant Kubernetes wo Tenant-Isolation kritisch ist, jeder Workload, der sonst privilegierte Container erfordern würde. Tradeoff: ~10-20% Performance-Overhead für syscall-heavy Workloads. Kubernetes RuntimeClass: set runtimeClassName: gvisor auf sensitive Pods.
Wie erkennt OpenClaw Container-Escape-Versuche zur Laufzeit?
OpenClaw integriert mit Falco für Runtime-Detection. Key Rules: 1) Privileged Container Prozess spawnet Shell (container_shell_from_privileged). 2) Write zu sensiblen Host-Pfaden aus einem Container (/etc, /proc/sysrq-trigger). 3) Docker Socket Access aus einem Container (fd opened matching /var/run/docker.sock). 4) Unexpected Capability Use (ptrace, mount syscall aus non-init container). 5) Namespace Escape Indicators (setns syscall, clone mit CLONE_NEWUSER aus Container). 6) Unexpected Network Connections aus einem Container zu host-only Subnets. Alerts route via OpenClaw's Webhook-Integration zu deinem SIEM.
Was ist die wirkungsvollste einzelne Änderung, um Container Escapes zu verhindern?
Pod Security Standards auf Cluster-Level erzwingen. Ein einziger Admission Webhook, der das 'restricted' PSS-Profil erzwingt, verhindert: privilegierte Container, hostPath Mounts, hostPID/hostIPC/hostNetwork, fehlende seccomp Profile, Privilege Escalation, Ausführung als Root. Ein OPA Gatekeeper oder Kyverno Policy Set, das PSS 'restricted' erzwingt, eliminiert die häufigsten Container-Escape-Vektoren cluster-weit. Das ist wirkungsvoller als individuelle Vulnerabilities anzugehen, weil es ganze Klassen von Fehlkonfiguration verhindert. Sofort auf neuen Clustern aktivieren; auf bestehenden Clustern zuerst 'warn' Mode nutzen, um Violations zu identifizieren, dann auf 'enforce' wechseln.