Pod Security Admission: die eingebaute Kubernetes-Grenze

Written in

von

Am 07.09. ging es an dieser Stelle um Kyverno und darum, wie du erzwingst, dass nur signiert Images in deinen Cluster kommen („Nur signierte Images im Cluster: Provenance mit Kyverno erzwingen“). Kyverno ist dafür der richtige Werkzeugkasten: frei definierbare Admission-Policies, die du selbst schreibst, für Regeln, die es in Kubernetes von Haus aus nicht gibt.

Für einen großen Teil der Pod-Härtung brauchst du diesen Werkzeugkasten aber gar nicht erst aufzuschlagen. Kubernetes bringt seit Version 1.25 einen eigenen Admission-Controller mit, der drei fertige Sicherheitsstufen kennt und sich über ein einziges Namespace-Label aktivieren lässt: Pod Security Admission (PSA). Kein Helm-Chart, kein CRD, kein Update-Zyklus einer dritten Komponente – nur ein Label, das der kube-apiserver selbst auswertet.

Dieser Artikel klärt, was PSA tatsächlich kann, wo die eingebaute Grenze verläuft und ab wann du zwangsläufig bei Kyverno (oder einer vergleichbaren Policy-Engine) landest.

Was Pod Security Admission ist

PSA ist ein in kube-apiserver eingebauter Admission-Controller. Die offizielle Dokumentation führt ihn als „built-in Pod Security admission controller to enforce the Pod Security Standards“ (kubernetes.io, Pod Security Admission). Der Feature-Status ist seit Kubernetes 1.25 „Stable“ – PSA ist damit kein Beta-Feature mehr, sondern GA (General Availability).

Die Pod Security Standards, die PSA durchsetzt, sind kein MHM-Konstrukt, sondern eine eigene Kubernetes-Spezifikation mit drei kumulativen Stufen (kubernetes.io, Pod Security Standards):

  • Privileged: „purposely-open, and entirely unrestricted“ – keine Einschränkung, gedacht für System- und Infrastruktur-Workloads unter vertrauenswürdiger Kontrolle.
  • Baseline: „aimed at ease of adoption for common containerized workloads while preventing known privilege escalations“ – verbietet unter anderem privilegierte Container, das Teilen von Host-Namespaces (hostNetwork, hostPID, hostIPC), Host-Path-Volumes und zusätzliche Linux-Capabilities über eine feste Erlaubnisliste hinaus.
  • Restricted: „Heavily restricted policy, following current Pod hardening best practices“ – verlangt zusätzlich zu Baseline unter anderem, dass Container nicht als root laufen, dass Privilege Escalation (allowPrivilegeEscalation) deaktiviert ist, dass alle Capabilities gedroppt werden (nur NET_BIND_SERVICE darf optional ergänzt werden) und dass ein Seccomp-Profil explizit gesetzt ist.

Diese drei Stufen sind vordefiniert. Du kannst sie auswählen, aber nicht umschreiben – genau das ist der Unterschied zu Kyverno, dazu unten mehr.

Die drei Modi: enforce, audit, warn

PSA kennt pro Namespace drei unabhängig konfigurierbare Modi (kubernetes.io, Pod Security Admission):

Modus Verhalten
enforce Verstoß führt zur Ablehnung des Pods.
audit Verstoß wird als Audit-Annotation im Audit-Log vermerkt, der Pod wird trotzdem erstellt.
warn Verstoß erzeugt eine Warnung für den Nutzer (z. B. bei kubectl apply), der Pod wird trotzdem erstellt.

Wichtig für die Praxis: enforce wirkt laut Dokumentation nur auf die finalen Pod-Objekte, nicht auf die Templates von Deployments, StatefulSets oder Jobs selbst – audit und warn dagegen werden zusätzlich auf die Workload-Ressourcen angewendet, damit Verstöße schon beim kubectl apply auf ein Deployment sichtbar werden, bevor der erste Pod überhaupt entsteht.

Das Namespace-Label in der Praxis

Jede Stufe und jeder Modus wird über ein Label-Paar pod-security.kubernetes.io/<MODE>: <LEVEL> gesetzt. Optional lässt sich die Kubernetes-Minor-Version fixieren, gegen die geprüft wird (kubernetes.io, Pod Security Admission):

apiVersion: v1
kind: Namespace
metadata:
  name: team-checkout
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

Mit diesem Label ist der Namespace team-checkout sofort auf die restriktivste Stufe gesetzt – ohne Controller-Deployment, ohne eigene Policy-Sprache, ohne zusätzliche Wartung. Willst du erst beobachten, bevor du hart durchsetzt, setzt du enforce vorerst auf baseline und audit/warn bereits auf restricted – so siehst du im Audit-Log und in der kubectl-Ausgabe, welche Workloads bei einer Verschärfung brechen würden, ohne dass produktiv schon etwas blockiert wird.

Wo die eingebaute Grenze endet

PSA prüft ausschließlich Felder im securityContext eines Pods und einige verwandte Spec-Felder – festgelegt durch die drei Standard-Stufen. Es gibt keinen Mechanismus, um eine eigene Regel zu ergänzen, etwa „nur Images aus einer bestimmten Registry“ oder „nur Images mit gültiger Signatur“. Genau das war der Gegenstand des Kyverno-Artikels vom 07.09.: Provenance- und Signatur-Prüfung ist keine der drei vordefinierten Pod Security Standards, also kann PSA sie grundsätzlich nicht abbilden – unabhängig davon, welche Stufe du wählst.

Kyverno wiederum ist laut eigener Dokumentation dafür gebaut, Policies „as declarative Kubernetes resources“ zu verwalten und dabei „YAML and CEL … with no new language to learn“ für frei definierte Regeln zu nutzen (kyverno.io, Introduction). Es lässt sich als eigener Admission-Controller im Cluster betreiben und prüft nicht nur Pods, sondern beliebige Ressourcentypen gegen selbst geschriebene Bedingungen.

Abgrenzung zum Kyverno-Artikel vom 07.09.: Dort ging es um frei definierbare Admission-Policies – etwa die Durchsetzung von Image-Signaturen –, die als eigene Regeln geschrieben und im Cluster betrieben werden. Hier geht es um die eingebauten, vordefinierten Pod-Security-Standards, die ohne Custom-Policy-Sprache und ohne zusätzliche Installation direkt im Namespace-Label stecken.

PSA vs. Kyverno im Vergleich

Pod Security Admission Kyverno
Installation Eingebaut in kube-apiserver, keine zusätzliche Komponente (kubernetes.io) Eigener Admission-Controller, muss im Cluster betrieben werden (kyverno.io)
Regelumfang Drei vordefinierte Stufen: privileged, baseline, restricted (kubernetes.io) Frei definierbare Regeln als eigene YAML-Ressourcen (kyverno.io)
Konfiguration Ein Namespace-Label pro Modus Policy-Ressourcen (z. B. ClusterPolicy) mit eigener Logik
Prüfgegenstand Pod-securityContext und verwandte Spec-Felder Beliebige Ressourcentypen und Felder
Beispiel-Use-Case root-Container, privilegierte Container, Host-Namespaces verbieten Image-Signaturen erzwingen, Registry-Whitelisting, Label-Pflichten
Betriebsaufwand Keiner über die Label-Pflege hinaus Eigener Lebenszyklus: Updates, CRDs, Monitoring der Policy-Engine

Wann PSA reicht – und wann nicht

Wenn deine Anforderung sich in einem Satz mit „root“, „privilegiert“, „Host-Namespace“ oder „Capabilities“ formulieren lässt, deckt eine der drei Pod Security Standards das vermutlich schon ab – dann reicht das Namespace-Label, und du sparst dir den Betrieb einer zusätzlichen Policy-Engine. Sobald deine Anforderung eine Regel ist, die es in den drei Standards nicht gibt – Bildherkunft, Registry-Zugehörigkeit, eigene Label- oder Annotation-Pflichten, Beziehungen zwischen mehreren Ressourcen –, ist PSA am Ende seiner Reichweite, und du brauchst eine Engine wie Kyverno, die eigene Regeln versteht.

Der wirtschaftlich sinnvolle Weg ist deshalb nicht „Kyverno für alles“, sondern die Stufen zu trennen: erst das eingebaute, kostenlose PSA-Label auf restricted setzen, dort wo es reicht – und Kyverno gezielt für die Regeln einsetzen, die PSA strukturell nicht abbilden kann.


Bei der Einordnung von Pod Security Admission oder Kyverno für deinen Cluster: Schreib mir an mm@mhm-dl.de.

Hinterlasse einen Kommentar

Diese Seite verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden..