Alle Rezepte
Kubernetes · Workload-Security · Grundlagen

Pod Security Standards:
drei Stufen, ein Namespace-Label

Kubernetes definiert drei fertige Sicherheitsstufen für Pods. Man muss keine eigenen Regeln schreiben – nur wissen, welche Stufe passt und wie man sie auf einen Namespace klebt. Sieben Abschnitte vom Grundprinzip bis zum schrittweisen Einstieg ohne Ausfall.

0GrundideeDrei Stufen, kumulativ 1Die drei StufenVergleich und Auswahl 2Standard vs. ContextRegel oder Einstellung 3BaselineWas verboten wird 4RestrictedWas zusätzlich gilt 5AktivierenLabels, enforce/audit/warn 6EinstiegSchrittweise, ohne Ausfall
0

Grundidee: drei fertige Stufen

Die Pod Security Standards sind drei vordefinierte Regelsätze, die das Sicherheitsspektrum grob abdecken – von „alles erlaubt“ bis „nur das Nötigste“. Sie sind kumulativ: jede Stufe enthält alles aus der darunter.

Die drei Stufen im Aufbau

Die drei Pod Security Standards als aufeinander aufbauende Stufen Privileged erlaubt alles. Baseline verbietet bekannte Ausbruchswege. Restricted enthält alles aus Baseline und fordert zusätzlich Härtungsmaßnahmen. Privileged — keine Einschränkungen Baseline — bekannte Ausbruchswege gesperrt Restricted — zusätzlich gehärtet non-root · Rechte-Aufstieg gesperrt · alle Capabilities weg seccomp aktiv · nur unkritische Volume-Typen außen = mehr erlaubt · innen = strenger

Wer Restricted erfüllt, erfüllt automatisch auch Baseline. Die Stufen sind keine Alternativen zueinander, sondern Verschärfungen.

Wie Sicherheitszonen am Flughafen. Draußen darf jeder alles mitnehmen. Hinter der Kontrolle sind bekannte gefährliche Gegenstände verboten. Im Sicherheitsbereich der Crew gelten zusätzlich eigene Regeln – aber die Kontrolle davor hat trotzdem jeder passiert.
Warum es das gibt: Vor den Standards musste jedes Team eigene Regeln über PodSecurityPolicy formulieren – aufwendig und fehleranfällig. Die Standards sind der fertige, vom Projekt gepflegte Ersatz dafür.
1

Die drei Stufen im Vergleich

Wofür jede Stufe gedacht ist und wer sie typischerweise braucht.

StufeBedeutungGedacht für
Privileged Bewusst offen, ohne jede Einschränkung. Erlaubt auch bekannte Wege, die Container-Isolation zu umgehen – etwa direkten Zugriff auf das Host-Netzwerk. System- und Infrastruktur-Workloads, die von vertrauenswürdigen Admins betrieben werden: CNI-Plugins, Storage-Treiber, Monitoring-Agents
Baseline Minimal einschränkend. Verhindert bekannte Wege der Rechte-Ausweitung, lässt aber eine normale Pod-Konfiguration ohne Anpassung durchgehen. Anwendungsbetrieb und Entwicklung nicht-kritischer Anwendungen
Restricted Stark einschränkend, folgt dem aktuellen Stand der Pod-Härtung – auf Kosten der Kompatibilität mit manchen Images. Sicherheitskritische Anwendungen und Umgebungen mit weniger vertrauenswürdigen Nutzern

Welche Stufe passt?

Entscheidungshilfe für die passende Stufe Braucht der Workload Host-Zugriff, bleibt nur Privileged. Sonst Restricted versuchen; scheitert das Image daran, Baseline verwenden. Braucht der Workload Host-Zugriff? ja nein Privileged eigener Namespace, wenige Pods Läuft das Image als non-root? nein ja Baseline Image später anpassen Restricted der Normalfall

Die ehrliche Kurzfassung: Restricted ist das Ziel für alles, was eine normale Anwendung ist. Baseline ist die Zwischenstation, wenn ein Image noch nicht mitspielt. Privileged bleibt der begründete Sonderfall in einem eigenen Namespace.

Warum es nichts zwischen Privileged und Baseline gibt: Die Standards sollen wenige, klar unterscheidbare Stufen bieten. Wer etwas dazwischen braucht, setzt eine der Stufen und ergänzt eigene Regeln über ein Policy-Werkzeug.
2

Standard oder securityContext – was ist was?

Die häufigste Anfängerverwirrung. Beide Begriffe reden über dieselben Felder, aber aus entgegengesetzter Richtung.

securityContext

Die Einstellung. Steht im Pod-Manifest und legt fest, wie dieser eine Pod läuft: als welcher Benutzer, mit welchen Capabilities, mit welchem seccomp-Profil.

Geschrieben vom Team, das die Anwendung deployt.

Pod Security Standard

Die Regel. Legt fest, welche Werte im securityContext überhaupt erlaubt sind – und welche zu einer Ablehnung führen.

Gesetzt vom Team, das den Cluster oder den Namespace verantwortet.

Der securityContext ist der ausgefüllte Antrag, der Standard ist die Prüfstelle. Man schreibt selbst hinein, was man möchte; die Stelle entscheidet, ob das durchgeht.

Und wer prüft das tatsächlich?

Der Standard ist zunächst nur ein Dokument. Durchgesetzt wird er vom Pod Security Admission Controller – der ist seit Kubernetes 1.25 fest eingebaut und muss nicht installiert werden. Er liest das Namespace-Label, prüft jeden neuen Pod dagegen und lehnt ab, was nicht passt.

Pod-Manifest wird eingereicht
        │
        ▼
Pod Security Admission liest das Namespace-Label
        │
        ▼
Prüfung des securityContext gegen die Stufe
        │
        ├── passt      → Pod wird erstellt
        └── passt nicht → Ablehnung mit Begründung
Wichtig: Die Prüfung greift, wenn ein Pod erstellt wird. Bereits laufende Pods bleiben unberührt, wenn ein Label nachträglich verschärft wird. Das Problem taucht erst beim nächsten Rollout oder Neustart auf – oft Wochen später und dann überraschend.
3

Baseline: was verboten wird

Baseline sperrt die bekannten Wege, mit denen ein Container die Isolation zur Node durchbricht. Eine gewöhnliche Anwendung merkt davon in der Regel nichts.

Die Verbote in Alltagssprache

BereichWas Baseline verlangt
Host-NamespacesKein Mitbenutzen von Netzwerk, Prozessliste oder IPC der Node (hostNetwork, hostPID, hostIPC)
Privilegierte Containerprivileged: true ist nicht erlaubt
CapabilitiesNur ein fester Satz gängiger Capabilities darf hinzugefügt werden – alles darüber hinaus ist gesperrt
HostPath-VolumesKeine Verzeichnisse der Node in den Pod mounten
Host-PortsMöglichst gar nicht, sonst nur eine bekannte Liste
Probes und Lifecycle-HooksDas host-Feld darin darf nicht gesetzt werden (seit 1.34)
AppArmorDas Standardprofil darf nicht abgeschaltet oder beliebig überschrieben werden
SELinuxNur bestimmte Typen erlaubt; eigener SELinux-User oder eigene Rolle sind verboten
/proc-MountMuss auf der Voreinstellung bleiben, damit die Schutzmasken greifen
SeccompDarf nicht ausdrücklich auf Unconfined gesetzt werden
SysctlsNur ein kleiner Satz als sicher eingestufter Kernel-Parameter
HostProcess (Windows)Privilegierter Zugriff auf den Windows-Host ist nicht erlaubt
Welche Capabilities Baseline zulässt

Hinzugefügt werden dürfen nur diese – Namen jeweils ohne CAP_-Präfix:

AUDIT_WRITE   CHOWN            DAC_OVERRIDE
FOWNER        FSETID           KILL
MKNOD         NET_BIND_SERVICE SETFCAP
SETGID        SETPCAP          SETUID
SYS_CHROOT

Alles andere – insbesondere SYS_ADMIN, NET_ADMIN oder SYS_PTRACE – wird abgelehnt.

Der Grundgedanke: Baseline verbietet nichts, was eine normale Anwendung tut. Es verbietet, was eine normale Anwendung nicht tut – und was fast immer ein Warnsignal ist, wenn es doch auftaucht.
4

Restricted: was zusätzlich gilt

Restricted enthält alles aus Baseline und fordert darüber hinaus aktive Härtung. Hier reicht es nicht mehr, nichts Verbotenes zu tun – bestimmte Felder müssen gesetzt sein.

Die zusätzlichen Anforderungen

BereichWas gefordert wird
Volume-TypenNur unkritische Typen: configMap, csi, downwardAPI, emptyDir, ephemeral, persistentVolumeClaim, projected, secret
Rechte-AufstiegallowPrivilegeEscalation: false an jedem Container
Als non-root laufenrunAsNonRoot: true – darf auf Pod-Ebene stehen
Keine UID 0runAsUser darf nicht 0 sein (darf auch weggelassen werden)
SeccompMuss ausdrücklich auf RuntimeDefault oder Localhost stehen – Weglassen reicht hier nicht mehr
Capabilitiesdrop: ["ALL"] ist Pflicht; zurückgeben darf man nur NET_BIND_SERVICE

Der Unterschied in einem Satz

Baseline

Prüft, ob du etwas Verbotenes tust. Ein Pod ganz ohne securityContext kommt durch.

Restricted

Prüft zusätzlich, ob du das Vorgeschriebene tust. Ein Pod ohne securityContext wird abgelehnt.

Ein Pod, der Restricted erfüllt
apiVersion: v1
kind: Pod
metadata:
  name: beispiel
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 10000
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: nginxinc/nginx-unprivileged
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: ["ALL"]

Das ist die Minimalform. runAsNonRoot und seccompProfile dürfen auf Pod-Ebene stehen und gelten dann für alle Container; allowPrivilegeEscalation und capabilities müssen an jeden einzelnen Container.

Init- und Sidecar-Container zählen mit. Die Prüfung betrachtet alle Container eines Pods. Ein einziger, der die Anforderungen nicht erfüllt, lässt den kompletten Pod durchfallen.
A-C-R-S für die vier Pflichtfelder: Aufstieg verboten, Capabilities weg, Root verboten, Seccomp an.
5

Aktivieren: ein Label pro Namespace

Die Stufe wird nicht im Pod hinterlegt, sondern am Namespace. Drei Modi bestimmen, was bei einem Verstoß passiert – und genau darin liegt der sichere Einstiegsweg.

Die drei Modi

ModusWirkung bei VerstoßWofür
enforceDer Pod wird abgelehnt und startet nichtScharfschaltung
auditDer Pod läuft; der Verstoß landet im Audit-Logstille Bestandsaufnahme
warnDer Pod läuft; der Nutzer bekommt sofort eine Warnung im TerminalFeedback an Entwickler

Die Modi lassen sich kombinieren – und das ist der entscheidende Trick: man kann eine strengere Stufe warnend beobachten, während eine mildere scharf geschaltet ist.

Labels setzen

# Baseline scharf, Restricted nur beobachtend
kubectl label namespace meine-app \
  pod-security.kubernetes.io/enforce=baseline \
  pod-security.kubernetes.io/warn=restricted \
  pod-security.kubernetes.io/audit=restricted

Oder direkt im Namespace-Manifest:

apiVersion: v1
kind: Namespace
metadata:
  name: meine-app
  labels:
    pod-security.kubernetes.io/enforce: baseline
    pod-security.kubernetes.io/enforce-version: v1.34
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/audit: restricted
Wozu das -version-Label?

Die Standards entwickeln sich weiter – neue Kubernetes-Versionen ergänzen gelegentlich Prüfungen. Ohne Versionsangabe gilt immer die aktuellste Fassung, ein Cluster-Update kann dann unerwartet Pods ablehnen.

Mit einer festen Version friert man das Verhalten ein und hebt es bewusst an, wenn man Zeit zum Testen hat. Für produktive Namespaces ist das die ruhigere Variante.

Prüfen, was gesetzt ist

# Labels eines Namespace
kubectl get namespace meine-app --show-labels

# Alle Namespaces auf einmal
kubectl get namespaces -o custom-columns=\
NAME:.metadata.name,\
ENFORCE:.metadata.labels.pod-security\\.kubernetes\\.io/enforce
Namespaces ohne Label werden nicht geprüft. Fehlt das Label, gilt faktisch Privileged. Ein frisch angelegter Namespace ist damit ungeschützt – daran denken, wenn Namespaces automatisiert erzeugt werden.
6

Einstieg ohne Ausfall

Direkt enforce: restricted auf einen bestehenden Namespace zu setzen ist der zuverlässigste Weg, einen Abend zu verlieren. Der schrittweise Weg kostet mehr Geduld und keinen Ausfall.

Der Weg in fünf Schritten

  1. Beobachten statt blockierenNur warn und audit auf restricted setzen, enforce weglassen. Nichts wird abgelehnt, aber jeder Verstoß wird sichtbar.
  2. Bestand durchtestenDie vorhandenen Deployments einmal neu ausrollen und die Warnungen sammeln. Erst dieser Schritt zeigt, welche Workloads betroffen sind.
  3. Manifeste nachziehenFehlende Felder ergänzen, Images auf non-root umstellen. Das ist der eigentliche Aufwand – und der Grund, warum Schritt 1 vorher kommt.
  4. Baseline scharf schaltenenforce: baseline setzen, während warn weiterhin auf restricted steht. Die erste echte Schutzstufe steht.
  5. Auf Restricted anhebenWenn keine Warnungen mehr auflaufen, enforce: restricted setzen.

Typische Stolpersteine

  • Image läuft als root – viele offizielle Images tun das. Für gängige Anwendungen gibt es unprivilegierte Varianten, sonst hilft ein eigenes Image mit passendem USER.
  • Schreibzugriff aufs Root-Dateisystem – nicht von den Standards verboten, fällt aber beim Härten meist zusammen mit auf. Lösung sind emptyDir-Volumes an den Schreibpfaden.
  • Sidecars aus fremden Charts – Service-Mesh-Proxies und Logging-Agents bringen eigene Anforderungen mit und sind nicht immer Restricted-tauglich.
  • Nachträgliches Verschärfen – bestehende Pods laufen weiter, der Bruch zeigt sich erst beim nächsten Rollout. Deshalb in Schritt 2 aktiv neu ausrollen statt abzuwarten.
  • Infrastruktur-Namespaces – CNI, CSI und Monitoring brauchen oft echten Host-Zugriff. Diese Namespaces bekommen bewusst privileged, nicht das ganze Cluster.
Faustregel für den Zielzustand: Anwendungs-Namespaces auf restricted, einzelne Ausnahmen auf baseline mit Begründung, Infrastruktur-Namespaces auf privileged – und kein Namespace ganz ohne Label.