28. Mai 2026 · 10 Min. Lesezeit

Kubernetes Pod Security: Privilegierte Container, Root-UIDs und wie Kyverno sie blockiert

Ein Pod als root mit hostPath-Zugriff auf das Node-Dateisystem kann einen Kubernetes-Cluster in Minuten vollständig kompromittieren. Zwei Fragen — wie schlimm ist es, und wie behebt man es richtig?

Ein Kubernetes-Pod, der als root läuft und dabei hostPath-Zugriff auf das Root-Dateisystem des Nodes hat — das klingt nach einem theoretischen Worst-Case-Szenario. In der Praxis ist es erschreckend häufig: Legacy-Deployments, schnell portierte Docker-Setups, Debug-Container die nie entfernt wurden, oder einfach fehlende Security-Policies.

Zwei Fragen, die sich jeder CTO und jeder Platform Engineer stellen sollte: Wie schlimm ist es wirklich — und wie behebt man es, ohne den laufenden Betrieb zu stören?

Wie schlimm ist es wirklich?

Die Antwort ist direkt: katastrophal. Ein Pod, der als UID 0 (root) läuft und dabei hostPath: / gemountet hat, besitzt faktisch root-Zugriff auf den Node — nicht nur im Container-Namespace, sondern auf das echte Node-Dateisystem.

Was ein Angreifer damit tun kann, der diesen Container kompromittiert:

  • Kubelet-Credentials stehlen — die Kubelet-Zertifikate liegen unter/var/lib/kubelet/pki/. Mit diesen Credentials kann sich ein Angreifer direkt gegenüber dem API-Server als Node authentifizieren und von dort alle Secrets aller Pods auf diesem Node lesen.
  • Container Runtime Socket missbrauchen — der containerd-Socket liegt unter /run/containerd/containerd.sock. Wer diesen Socket lesen und schreiben kann, kann beliebige privilegierte Container starten — und damit den Kubernetes-Admission-Controller vollständig umgehen.
  • Kompletten Cluster-Takeover — von einem kompromittierten Node aus lässt sich über gestohlene Credentials oder Service Account Tokens ein Weg zum cluster-admin-Level finden. Zeitrahmen: Minuten, nicht Stunden.

Wichtig für DSGVO-Compliance: Ein vollständiger Cluster-Takeover bedeutet Zugriff auf alle persistenten Daten aller Namespaces — Datenbanken, Secrets, Backups. Das ist ein meldepflichtiger Datenschutzvorfall nach Art. 33 DSGVO. Die 72-Stunden-Frist zur Meldung an die Aufsichtsbehörde beginnt ab Kenntnis — nicht ab Entdeckung.

Sofortmaßnahmen: Was heute noch geändert werden muss

Wenn Sie heute einen laufenden Pod mit dieser Konfiguration haben, sind das die drei Schritte in der richtigen Reihenfolge:

1. Den hostPath-Zugriff einschränken

Wenn der Pod hostPath: / wirklich braucht (z.B. für Log-Collection), beschränken Sie den Mount auf den tatsächlich benötigten Pfad und setzen Sie ihn auf read-only:

volumes:
  - name: host-logs
    hostPath:
      path: /var/log   # nur was wirklich gebraucht wird
      type: Directory
containers:
  - name: log-collector
    volumeMounts:
      - name: host-logs
        mountPath: /host/var/log
        readOnly: true   # kein Schreibzugriff

Für die meisten Workloads gibt es keinen legitimen Grund für hostPath-Zugriff. Logging-Agents wie Promtail oder Fluentd benötigen nur /var/log/podsoder /var/log/containers — nicht das gesamte Root-Dateisystem.

2. Den SecurityContext härten

Das ist die unmittelbarste Gegenmaßnahme und lässt sich in jedem bestehenden Deployment ohne Service-Unterbrechung ergänzen:

securityContext:
  runAsNonRoot: true
  runAsUser: 1000        # explizite UID, kein root
  runAsGroup: 1000
  fsGroup: 1000
  seccompProfile:
    type: RuntimeDefault  # aktiviert seccomp-Filter

containers:
  - name: app
    securityContext:
      allowPrivilegeEscalation: false   # kein sudo, kein setUID
      privileged: false
      readOnlyRootFilesystem: true      # kein Schreiben ins Container-FS
      capabilities:
        drop:
          - ALL             # alle Linux capabilities entfernen
        add:
          - NET_BIND_SERVICE # nur hinzufügen was wirklich gebraucht wird

Praxis-Hinweis: readOnlyRootFilesystem: true bricht oft Anwendungen, die in /tmp oder /var/run schreiben. Lösung: diese Pfade explizit als emptyDir-Volume mounten. Das ist ein einmaliger Aufwand — danach ist das Dateisystem unveränderbar.

3. Das privileged-Flag entfernen

privileged: true gibt einem Container faktisch alle Linux-Capabilities und deaktiviert seccomp, AppArmor und SELinux-Einschränkungen. Es gibt wenige legitime Use Cases — CNI-Plugins, bestimmte Storage-Treiber. Für Anwendungs-Container ist es immer falsch.

Langfristige Absicherung: Pod Security Admission

Einzelne Deployments zu korrigieren ist notwendig, aber nicht ausreichend. Ohne einen Mechanismus, der neue Deployments blockiert, ist die nächste fehlerhafte Konfiguration nur eine Pipeline-Ausführung entfernt.

Kubernetes 1.25+ hat Pod Security Admission (PSA) als stabiles Feature eingebaut — es ersetzt die veralteten PodSecurityPolicies. PSA definiert drei Profile:

  • privileged — keine Einschränkungen (Standard)
  • baseline — verhindert die offensichtlichsten Angriffsvektoren: hostPID, hostIPC, hostNetwork, privilegierte Container, gefährliche Capabilities
  • restricted — maximale Einschränkung: runAsNonRoot, keine Privilege Escalation, seccomp RuntimeDefault, alle Capabilities gedroppt

PSA wird per Namespace über Labels aktiviert:

# Namespace auf "restricted" setzen — zunächst im warn-Modus
kubectl label namespace production \
  pod-security.kubernetes.io/warn=restricted \
  pod-security.kubernetes.io/warn-version=latest

# Nach Validierung auf enforce umstellen
kubectl label namespace production \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/enforce-version=latest

PSA ist der richtige erste Schritt — aber es hat Grenzen: Es arbeitet nur auf Namespace-Ebene und bietet keine feingranulare Policy-Kontrolle. Für Produktionsumgebungen kombinieren wir PSA immer mit Kyverno.

Kyverno: Policy-as-Code für Kubernetes

In unserer Kubernetes-Beratung setzen wir auf Kyverno als primäres Policy-Engine — weil Kyverno Policies als native Kubernetes-Ressourcen definiert, kein eigenes DSL erfordert, und sich direkt in GitOps-Workflows integriert.

Eine Kyverno-Policy die UID 0 global blockiert:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-root-user
spec:
  validationFailureAction: Audit   # erst Audit, dann Enforce
  background: true
  rules:
    - name: check-runasnonroot
      match:
        any:
          - resources:
              kinds: [Pod]
      validate:
        message: "Pods müssen als Non-Root-User laufen (runAsNonRoot: true)"
        pattern:
          spec:
            =(securityContext):
              =(runAsNonRoot): "true"
            containers:
              - =(securityContext):
                  =(runAsNonRoot): "true"
                  =(runAsUser): ">0"

Weitere Kyverno-Policies die wir standardmäßig deployen:

  • disallow-privileged-containers — blockiert privileged: true
  • disallow-privilege-escalation — erzwingt allowPrivilegeEscalation: false
  • disallow-host-path — blockiert alle hostPath-Volumes (mit Ausnahme-Liste für System-Namespaces)
  • require-readonly-root-filesystem — erzwingt readOnlyRootFilesystem: true
  • drop-all-capabilities — erzwingt capabilities.drop: [ALL]

Der entscheidende Schritt: Audit-Modus vor Enforcement

Hier passiert der häufigste Fehler: Policies direkt auf Enforce setzen und sich wundern, warum plötzlich Deployments in Production fehlschlagen.

Die richtige Vorgehensweise ist eine zweistufige Rollout-Strategie:

  • Woche 1–2: Audit-ModusvalidationFailureAction: Auditloggt Verstöße, blockiert aber nichts. Kyverno-Reports zeigen welche Pods betroffen sind.
  • Woche 3+: Enforcement — erst wenn alle bestehenden Workloads angepasst wurden, auf Enforce umstellen.
# Kyverno PolicyReport auslesen — welche Pods verstoßen aktuell?
kubectl get policyreport -A
kubectl describe policyreport -n production

# Oder via kubectl-kyverno Plugin
kubectl kyverno test . --policy-report

Versteckte Dependencies aufdecken: Der Audit-Modus zeigt oft Überraschungen — Init-Container die als root laufen, Sidecar-Injections durch Service Meshes, oder Helm-Charts von Drittanbietern mit hartcodierten Security Contexts. Ohne Audit-Phase würden diese bei Enforcement sofort Pods blockieren.

OPA Gatekeeper als Alternative

OPA Gatekeeper ist die andere weit verbreitete Option — CNCF-graduated, basiert auf der Rego-Policy-Sprache. Wir empfehlen Kyverno für die meisten Mittelstands-Setups, weil:

  • Kyverno-Policies sind YAML — kein neues DSL zu lernen
  • Das Kyverno-CLI ermöglicht lokales Policy-Testing ohne Cluster
  • Kyverno kann auch Ressourcen mutieren (z.B. SecurityContext automatisch ergänzen)
  • Gatekeeper hat mehr operationale Komplexität bei ähnlichem Ergebnis

Für Teams mit bestehender Rego-Expertise oder komplexen Cross-Ressource-Validierungen ist Gatekeeper die bessere Wahl. Beide sind produktionsreif — die Entscheidung hängt vom Team ab, nicht von der Technologie.

Vollständige Security-Baseline für Produktions-Cluster

Pod Security ist ein Layer — nicht der einzige. Eine produktionsreife Kubernetes-Security-Baseline umfasst mindestens:

  • Network Policies mit Default-Deny-All — jede erlaubte Verbindung ist explizit definiert
  • RBAC nach Least Privilege — kein Wildcard-Verb, kein Cluster-Admin für Anwendungs-Service-Accounts
  • External Secrets Operator — keine Secrets in Git, auch nicht base64-encoded
  • Image Policy — nur signierte Images aus bekannten Registries (Cosign + Kyverno)
  • Admission Controller Hardening — API-Server-Flags: --anonymous-auth=false, --audit-log-path
  • CIS Benchmark — regelmäßige Überprüfung mit kube-bench

Wenn Sie wissen möchten, wo Ihr Cluster aktuell steht: unser Kubernetes-Audit deckt genau diese Punkte ab — mit einem priorisierten Bericht und konkreten Empfehlungen für Ihren Stack.

Fazit: Security ist kein Feature, sondern ein Betriebsmodus

Ein privilegierter Pod mit hostPath-Zugriff ist kein theoretisches Risiko — es ist eine offene Tür. Die Gegenmaßnahmen sind bekannt und implementierbar: SecurityContext härten, PSA aktivieren, Kyverno-Policies deployen, im Audit-Modus starten.

Der häufigste Grund warum diese Maßnahmen fehlen, ist nicht mangelndes Wissen — sondern fehlende Zeit und fehlende Policy-Infrastruktur. Ein Cluster der täglich Deployments sieht, braucht automatisierte Kontrollen. Manuelle Reviews skalieren nicht.

Wir bauen diese Security-Layer als Teil jedes Kubernetes-Plattform-Aufbaus ein — nicht als optionales Add-on, sondern als Default.

Nächster Schritt
30 Minuten — unverbindlich

Wir schauen uns Ihre konkrete Situation an und sagen Ihnen ehrlich, ob und wie wir helfen können.

Erstgespräch buchen Kostenloser Plattform-Check →