· Kubernetes · 7 Min. Lesezeit
PodSecurity restricted: die vollständige Sammlung der Stolpersteine
Zehn Fälle, an denen eine Migration auf enforce restricted hängen bleibt: von der Wildcard über initContainers bis zur Exemption, die den halben Cluster öffnet. Jeder Fall im Schema Symptom, Ursache, Prüfung und Lösung, mit Prüfbefehlen zum Kopieren.

Die Fälle unten sind für zwei Situationen gedacht. Die erste: Sie planen eine Migration auf enforce: restricted und wollen vorher wissen, was Sie erwartet, statt es beim Rollout herauszufinden. Die zweite: Bei Ihnen scheitert bereits etwas, und Sie suchen die passende Ursache zu einem Symptom, das Sie vor sich haben.
Der Ablauf selbst, also Bestandsaufnahme, Trockenlauf, securityContext am Workload, Version-Pin und die Verankerung der Labels in GitOps, steht im Hauptbeitrag PodSecurity restricted: der Namespace, in dem keine Pods starten. Wenn Sie noch am Anfang stehen, arbeiten Sie den zuerst durch und nehmen diese Seite als Begleitung daneben.
1. Das Deployment wird angelegt, es entsteht kein Pod
Symptom: kubectl apply des Deployments läuft fehlerfrei durch. kubectl get deploy zeigt dauerhaft 0/2, ohne dass am Deployment ein Grund steht.
Ursache: enforce wird laut Doku zur Pod Security Admission nicht auf Workload-Ressourcen angewendet, sondern nur auf die resultierenden Pod-Objekte. Das Deployment passiert die Admission also ungeprüft. Abgewiesen wird erst, wenn der ReplicaSet-Controller den Pod erzeugen will. Der Status des Deployments ist dafür der falsche Ort.
Prüfung:
kubectl describe rs -n <namespace>kubectl get events -n <namespace> --sort-by=.lastTimestampLösung: Setzen Sie zu enforce immer auch warn und audit auf demselben Level. warn greift auf die Workload-Ressource, dadurch sehen Sie den Verstoß schon beim apply des Deployments und nicht erst im Event einer Zwischenressource.
2. Der ungelabelte Namespace ist nicht streng, sondern offen
Symptom: Ein frisch angelegter Namespace ohne PodSecurity-Label verhält sich nicht restriktiv, unsichere Pods laufen dort durch.
Ursache: Der eingebaute Default der PodSecurityConfiguration ist privileged. Ohne eigene AdmissionConfiguration fällt ein ungelabelter Namespace auf diese offenste Stufe zurück, nicht auf eine strenge.
Prüfung:
kubectl get namespaces --selector='!pod-security.kubernetes.io/enforce'Lösung: Entweder den Default über eine AdmissionConfiguration am kube-apiserver anheben, oder jeden Namespace explizit labeln. Die zweite Variante ist die einzige, die auch in Clustern funktioniert, in denen Sie die apiserver-Konfiguration nicht anfassen können.
3. Der Pod erfüllt scheinbar alles und wird trotzdem abgewiesen
Symptom: Der Anwendungscontainer trägt einen vollständigen securityContext, der Pod wird dennoch nicht zugelassen.
Ursache: Die Kontrollen der Pod Security Standards gelten mit Wildcard für containers[*], initContainers[*] und ephemeralContainers[*]. Ein vergessener initContainer oder ein nachträglich injizierter Sidecar reißt den ganzen Pod mit. Dazu kommen zwei leicht übersehene Punkte: runAsUser darf nicht 0 sein, und spec.volumes[*] ist auf acht Typen begrenzt.
Prüfung:
kubectl get pod <name> -n <namespace> \
-o jsonpath='{.spec.initContainers[*].securityContext}{"\n"}{.spec.containers[*].securityContext}{"\n"}'kubectl get pod <name> -n <namespace> -o jsonpath='{.spec.volumes[*]}{"\n"}'Lösung: Setzen Sie runAsNonRoot und seccompProfile auf Pod-Ebene, damit sie für alle Container-Listen gelten. capabilities.drop: ["ALL"] muss je Container stehen. hostPath ersetzen Sie durch emptyDir, configMap, secret, projected oder persistentVolumeClaim. Beachten Sie außerdem, dass das gitRepo-Volume-Plugin mit Kubernetes 1.36 standardmäßig deaktiviert ist und sich laut Changelog nicht wieder einschalten lässt.
4. Nach dem Cluster-Upgrade werden Pods abgewiesen, die vorher liefen
Symptom: Am Manifest hat sich nichts geändert, nach dem Upgrade der Control Plane scheitert der Rollout trotzdem.
Ursache: Ohne Version-Label gilt latest. Die Definition eines Levels kann sich zwischen Minor-Versionen ändern. restricted wurde in v1.25 auf spec.os.name umgestellt, die Capabilities-Kontrolle kam in v1.22 dazu, die Kontrolle gegen runAsUser: 0 in v1.23.
Prüfung:
kubectl get ns <namespace> -o jsonpath='{.metadata.labels}{"\n"}'Lösung: pod-security.kubernetes.io/<MODE>-version explizit auf eine Minor-Version pinnen und beim Upgrade bewusst nachziehen, statt die Änderung im laufenden Betrieb zu erben.
5. Die Admission ergänzt keine fehlenden Felder
Symptom: Ein Pod ohne securityContext wird abgewiesen, obwohl man erwartet hätte, dass die Admission die Pflichtfelder setzt.
Ursache: Pod Security Admission ist ausdrücklich nicht mutierend. Anders als die früheren PodSecurityPolicies setzt sie keine Defaults, sie prüft nur. Die offizielle Anleitung zur Migration von PodSecurityPolicy zu Pod Security Admission benennt das als bekannte Lücke.
Prüfung: Ein kubectl apply eines Pods ohne securityContext in einem restricted-Namespace muss fehlschlagen, nicht still ergänzt werden.
Lösung: Entweder jeden Workload anpassen, oder laut derselben Anleitung einen Mutating Admission Webhook einsetzen. Bei fremden Helm-Charts heißt das in der Praxis, die securityContext-Werte über die Values zu setzen.
6. Ein Team hebelt die Härtung im eigenen Namespace aus
Symptom: Trotz restricted laufen in einem Namespace Pods, die dort nicht laufen dürften.
Ursache: Wer einen Namespace anlegen, ändern oder patchen darf, darf laut Migrationsanleitung auch dessen PodSecurity-Level ändern und die strengere Richtlinie damit umgehen.
Prüfung:
kubectl auth can-i patch namespaces --as=deploy@lab.rz.jabi-it.dekubectl auth can-i create namespaces --as=deploy@lab.rz.jabi-it.deLösung: RBAC so schneiden, dass update, patch und create auf Namespaces nur privilegierten Rollen offenstehen. Wie Sie die eigenen Rechte in einer eingeschränkten Umgebung überhaupt feststellen, steht im Beitrag Wenn der einzige Zugang die Rancher-Shell ist.
7. Die Exemption wirkt nicht oder viel zu breit
Symptom: Eine Ausnahme für einen einzelnen Benutzer greift nicht. Oder eine Ausnahme für einen Controller-Account öffnet den Cluster weit über die Absicht hinaus.
Ursache: Die meisten Pods werden von einem Controller als Reaktion auf eine Workload-Ressource erzeugt. Eine Benutzer-Exemption wirkt deshalb nur beim direkten Anlegen von Pods. Eine Exemption für einen Controller-ServiceAccount wie system:serviceaccount:kube-system:replicaset-controller nimmt dagegen implizit jeden aus, der die entsprechende Workload-Ressource anlegen darf. Die Doku rät ausdrücklich davon ab.
Prüfung: Die AdmissionConfiguration am kube-apiserver lesen und sicherstellen, dass unter exemptions.usernames kein Controller-ServiceAccount steht.
Lösung: Ausnahmen über die Dimensionen namespaces oder runtimeClasses steuern, nicht über Benutzer oder Controller-Accounts.
8. Argo CD setzt die Labels nicht oder entfernt sie wieder
Symptom: Der Namespace entsteht, die PodSecurity-Labels aus der Application fehlen. Oder sie waren da und sind nach einem Sync verschwunden.
Ursache: Zwei getrennte Punkte, beide in der Argo-CD-Doku zu den Sync-Optionen benannt. managedNamespaceMetadata wirkt nur mit gesetzter Sync-Option CreateNamespace=true, und ein eigenes Namespace-Manifest in derselben Application überschreibt die Werte. Für den zweiten Fall warnt die Doku, dass Argo CD bestehende Labels und Annotationen entfernen kann, solange die Ressource nicht auf Server-Side Apply umgestellt ist.
Prüfung: Die Labels vor und nach einem Sync vergleichen:
kubectl get ns <namespace> -o jsonpath='{.metadata.labels}{"\n"}'Lösung: CreateNamespace=true setzen, kein konkurrierendes Namespace-Manifest ausliefern, und die Namespace-Ressource auf Server-Side Apply umstellen.
9. Das Upgrade auf 1.35 bricht vor der Policy-Arbeit ab
Symptom: Beim Anheben des Clusters auf 1.35 startet das kubelet nicht mehr, oder kubeadm bricht mit einem Fehler der Systemprüfung ab.
Ursache: Die Release-Notes zu Kubernetes 1.35 nennen zwei Punkte mit dem Vermerk ACTION REQUIRED. Das kubelet-Flag --pod-infra-container-image wurde entfernt. Und der cgroups-Validator meldet ab KubeletVersion v1.35 einen Fehler statt einer Warnung, wenn auf dem Host cgroups v1 erkannt wird.
Prüfung:
stat -fc %T /sys/fs/cgroup/kubectl get cm kubelet-config -n kube-system -o yamlLösung: Die Reihenfolge ist vorgegeben. Entfernen Sie --pod-infra-container-image vor dem kubelet-Upgrade manuell aus der Konfiguration, sonst startet das kubelet nicht. Und ergänzen Sie die ConfigMap kube-system/kubelet-config vor dem Upgrade um failCgroupV1: false, falls Sie cgroups v1 vorerst weiterfahren müssen. Liefert stat den Wert cgroup2fs, laufen Sie bereits auf cgroups v2 und der Punkt entfällt.
10. Windows-Pods verhalten sich anders
Symptom: In einem gemischten Cluster greift restricted bei Windows-Workloads nicht so, wie es bei Linux-Workloads greift.
Ursache: Seit v1.25 wertet das Profil pod.spec.os.name aus. Rechteausweitung, seccomp und Linux-Capabilities werden nur verlangt, wenn spec.os.name nicht windows ist.
Prüfung:
kubectl get pod <name> -n <namespace> -o jsonpath='{.spec.os.name}{"\n"}'Lösung: In gemischten Clustern spec.os.name bewusst setzen und nicht davon ausgehen, dass restricted auf Windows dieselben Garantien liefert wie auf Linux.
Wie Sie diese Liste einsetzen
Die Fälle 1 bis 4 treten am Anfang einer Migration auf und blockieren den Rollout sichtbar. Die Fälle 5 bis 8 betreffen die Umgebung um die Policy herum, also Workload-Anpassung, RBAC, Ausnahmen und GitOps. Sie fallen später auf und sind dann teurer zu korrigieren. Fall 9 und 10 sind Randbedingungen des Clusters selbst, die mit der Policy nichts zu tun haben, den Zeitplan einer Härtung aber trotzdem bestimmen.
Ich gehe die Liste vor dem ersten scharfen enforce-Label einmal von oben nach unten durch und halte je Namespace fest, welcher Punkt zutrifft. Das kostet eine überschaubare Vorbereitung und verhindert, dass eine Absicherung mitten im Rollout wieder zurückgedreht wird. Der zugehörige Ablauf mit Trockenlauf und Prüfbefehlen steht im Beitrag PodSecurity restricted: der Namespace, in dem keine Pods starten.
Sie wollen einen Cluster, der sicher ist und trotzdem zuverlässig ausrollt? Ich härte Kubernetes-Umgebungen so, dass die Absicherung greift, ohne dass Deployments still liegen bleiben. Mehr unter IT-Sicherheit & ISMS, das Erstgespräch ist unverbindlich.

Alex Jabi
Ich betreue IT, Informationssicherheit und Datenschutz für KMU und Praxen an der Bergstraße und im Odenwald, persönlich, dokumentiert und ohne Cloud-Zwang.
Mehr über mich

