- Authors

- Name
- Phillip Pham
- @ddppham
Kubernetes Pod Security Standards: Admission Controllers richtig einsetzen
TL;DR
- PodSecurityPolicy (PSP) wurde in Kubernetes 1.25 entfernt. Pod Security Standards (PSS) mit dem Pod Security Admission Controller sind der offizielle Nachfolger.
- Es gibt drei Profile: Privileged (keine Einschraenkungen), Baseline (bekannte Privilege Escalations blockiert), Restricted (Best Practices erzwungen).
- Steuerung erfolgt ueber Namespace-Labels mit drei Modi:
enforce(blockiert),audit(loggt),warn(warnt den User). - Starten Sie mit
warnundauditaufrestricted, bevor Sieenforceaktivieren -- so finden Sie Verstoesse ohne Ausfaelle. - PSS ist seit Kubernetes 1.25 stable und erfordert keine Installation -- der Admission Controller ist im API-Server eingebaut.
Warum PodSecurityPolicy abgeloest wurde
PodSecurityPolicy hatte fundamentale Probleme: Die Zuordnung von Policies zu Pods erfolgte ueber RBAC und ServiceAccounts, was schwer nachvollziehbar war. Ausserdem waren PSPs cluster-weit und liessen sich nicht granular pro Namespace steuern.
Pod Security Standards loesen diese Probleme:
| Eigenschaft | PodSecurityPolicy (alt) | Pod Security Standards (neu) |
|---|---|---|
| Zuordnung | Ueber RBAC/ServiceAccounts | Ueber Namespace-Labels |
| Granularitaet | Cluster-weit | Pro Namespace |
| Konfiguration | Eigene API-Objekte | Labels auf Namespaces |
| Installation | Admission Plugin aktivieren | Standardmaessig aktiv ab 1.25 |
| Komplexitaet | Hoch (viele Felder) | Einfach (drei Profile) |
Wenn Sie noch PSP verwenden, ist die Migration dringend -- seit Kubernetes 1.25 existiert die PSP-API nicht mehr.
Die drei Profile verstehen
Privileged -- keine Einschraenkungen
Das Privileged-Profil erlaubt alles. Es ist fuer System-Workloads wie CNI-Plugins, Storage-Treiber oder Log-Collector gedacht, die privilegierten Zugriff brauchen.
# Typischer Workload fuer Privileged: kube-system Namespace
apiVersion: v1
kind: Namespace
metadata:
name: kube-system
labels:
pod-security.kubernetes.io/enforce: privileged
pod-security.kubernetes.io/audit: privileged
pod-security.kubernetes.io/warn: privileged
Verwenden Sie dieses Profil nur fuer Namespaces, die es wirklich brauchen -- typischerweise kube-system und Infrastruktur-Namespaces.
Baseline -- bekannte Risiken blockiert
Baseline blockiert die gefaehrlichsten Konfigurationen, erlaubt aber noch einige Freiheiten. Es ist ein guter Startpunkt fuer Anwendungs-Namespaces.
Was Baseline blockiert:
- Privilegierte Container (
privileged: true) - Host-Namespaces (
hostPID,hostIPC,hostNetwork) - Gefaehrliche Capabilities (
SYS_ADMIN,NET_RAW, etc.) - hostPath Volumes
- Container, die als ProcMountType
Unmaskedlaufen
Was Baseline erlaubt:
- Container die als Root laufen
- Keine Seccomp-Profile erzwungen
- Capabilities wie
NET_BIND_SERVICE
apiVersion: v1
kind: Namespace
metadata:
name: staging
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
Diese Kombination ist ein bewaehertes Muster: Baseline wird erzwungen, waehrend restricted als Audit und Warning laeuft. So sehen Sie bereits, welche Pods das strikte Profil verletzen wuerden.
Restricted -- maximale Sicherheit
Restricted erzwingt alle aktuellen Security Best Practices. Dieses Profil ist das Ziel fuer Produktions-Workloads.
Zusaetzlich zu Baseline erfordert Restricted:
- Container muessen als Non-Root laufen (
runAsNonRoot: true) - Seccomp-Profil muss gesetzt sein (
RuntimeDefaultoderLocalhost) - Alle Capabilities muessen gedroppt werden
- Root-Dateisystem muss read-only sein oder
allowPrivilegeEscalation: false - Keine zusaetzlichen Capabilities ausser
NET_BIND_SERVICE
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: v1.31
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: v1.31
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: v1.31
Das Pinning auf eine Version (hier v1.31) ist wichtig. Ohne Version gilt immer das Profil der aktuellen Kubernetes-Version. Bei einem Cluster-Upgrade koennten neue Regeln hinzukommen, die bestehende Pods blockieren.
Die drei Modi: enforce, audit, warn
Jedes Profil kann in drei Modi betrieben werden. Das ist der groesste Vorteil gegenueber PSP -- Sie koennen schrittweise verschaerfen.
# Namespace mit allen drei Modi erstellen
kubectl create namespace secure-app
kubectl label namespace secure-app \
pod-security.kubernetes.io/enforce=baseline \
pod-security.kubernetes.io/audit=restricted \
pod-security.kubernetes.io/warn=restricted
| Modus | Verhalten | API-Server Response |
|---|---|---|
enforce | Pod wird abgelehnt | HTTP 403 Forbidden |
audit | Verstoss wird in Audit-Log geschrieben | Pod wird erstellt |
warn | User sieht Warning-Meldung | Pod wird erstellt |
Enforce in Aktion
# Namespace mit enforce=restricted erstellen
kubectl create namespace restricted-ns
kubectl label namespace restricted-ns \
pod-security.kubernetes.io/enforce=restricted
# Einen Pod ohne Security Context deployen -- wird abgelehnt
kubectl run nginx --image=nginx -n restricted-ns
Die Fehlermeldung ist praezise:
Error from server (Forbidden): pods "nginx" is forbidden: violates PodSecurity
"restricted:latest": allowPrivilegeEscalation != false
(container "nginx" must set securityContext.allowPrivilegeEscalation=false),
unrestricted capabilities (container "nginx" must set
securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or
container "nginx" must set securityContext.runAsNonRoot=true),
seccompProfile (pod or container "nginx" must set securityContext.seccompProfile.type
to "RuntimeDefault" or "Localhost")
Audit-Logs pruefen
Im audit-Modus schreibt der API-Server Annotations in die Audit-Logs:
# Audit-Logs auf dem API-Server pruefen (bei Self-Managed Clustern)
# Die Annotations sehen so aus:
# audit.k8s.io/pod-security-violations:
# would violate PodSecurity "restricted:latest":
# allowPrivilegeEscalation != false, ...
# Bei Managed Kubernetes (EKS, AKS, GKE) finden Sie
# die Audit-Logs im jeweiligen Logging-Service
Pod fuer das Restricted-Profil konfigurieren
So sieht ein Pod aus, der das Restricted-Profil erfuellt:
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-web-app
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: secure-web-app
template:
metadata:
labels:
app: secure-web-app
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: registry.example.com/web-app:v2.1.0
ports:
- containerPort: 8080
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /var/cache
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
Wichtige Details:
- readOnlyRootFilesystem: Erfordert explizite emptyDir-Volumes fuer Verzeichnisse, in die die App schreiben muss (wie
/tmp). - runAsUser/runAsGroup: Das Container-Image muss einen Non-Root-User enthalten. Viele offizielle Images (nginx, redis) laufen standardmaessig als Root -- verwenden Sie die
-unprivilegedVarianten. - capabilities.drop ALL: Entfernt alle Linux-Capabilities. Falls Ihre App auf Port unter 1024 lauschen muss, fuegen Sie
NET_BIND_SERVICEhinzu.
Migration von PodSecurityPolicy: Schritt fuer Schritt
Schritt 1: Bestandsaufnahme -- welche PSPs existieren
# Alle PodSecurityPolicies auflisten (nur auf Clustern vor 1.25)
kubectl get psp
# PSP-Details anzeigen
kubectl get psp -o yaml
# Welche ServiceAccounts nutzen welche PSP
kubectl get clusterrolebinding -o json | \
jq -r '.items[] | select(.roleRef.kind=="ClusterRole") |
select(.roleRef.name | test("psp")) |
"\(.metadata.name) -> \(.roleRef.name)"'
Schritt 2: PSPs auf Profile mappen
Erstellen Sie eine Mapping-Tabelle:
# Trockenlauf: Pruefen welche Pods gegen welches Profil verstossen
# Dieses Skript testet alle Namespaces gegen das Restricted-Profil
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
violations=$(kubectl label --dry-run=server --overwrite ns "$ns" \
pod-security.kubernetes.io/enforce=restricted 2>&1 | \
grep -c "would violate" || true)
if [ "$violations" -gt 0 ]; then
echo "VIOLATIONS in $ns: $violations"
else
echo "OK: $ns"
fi
done
Schritt 3: Schrittweise Labels setzen
# Phase 1: Warn und Audit auf allen Anwendungs-Namespaces
for ns in app-frontend app-backend app-worker; do
kubectl label namespace "$ns" \
pod-security.kubernetes.io/warn=restricted \
pod-security.kubernetes.io/audit=restricted
done
# Phase 2: Nach 2 Wochen ohne Violations -- Enforce aktivieren
for ns in app-frontend app-backend app-worker; do
kubectl label namespace "$ns" \
pod-security.kubernetes.io/enforce=restricted
done
Schritt 4: Namespace-Exceptions mit Labels
Manche Namespaces brauchen Ausnahmen. Statt alles auf Privileged zu setzen, nutzen Sie Baseline als Kompromiss:
# Monitoring-Namespace braucht hostNetwork fuer Node-Exporter
apiVersion: v1
kind: Namespace
metadata:
name: monitoring
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
Haeufige Verstoesse und ihre Loesung
Verstoss: allowPrivilegeEscalation nicht false
# Vorher (verstoesst gegen Restricted)
containers:
- name: app
image: my-app:latest
# Nachher (konform)
containers:
- name: app
image: my-app:latest
securityContext:
allowPrivilegeEscalation: false
Verstoss: Container laeuft als Root
# Vorher (verstoesst gegen Restricted)
spec:
containers:
- name: nginx
image: nginx:latest
# Nachher (konform -- unprivileged Image verwenden)
spec:
securityContext:
runAsNonRoot: true
runAsUser: 101
containers:
- name: nginx
image: nginxinc/nginx-unprivileged:latest
Verstoss: Capabilities nicht gedroppt
# Vorher (verstoesst gegen Restricted)
containers:
- name: app
image: my-app:latest
securityContext:
allowPrivilegeEscalation: false
# Nachher (konform)
containers:
- name: app
image: my-app:latest
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
Verstoss: Kein Seccomp-Profil
# Vorher (verstoesst gegen Restricted)
spec:
containers:
- name: app
image: my-app:latest
# Nachher (konform -- auf Pod-Ebene setzen)
spec:
securityContext:
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: my-app:latest
Cluster-weite Defaults konfigurieren
Sie koennen Defaults fuer den Pod Security Admission Controller auf Cluster-Ebene setzen. Das ist nuetzlich, wenn neue Namespaces automatisch ein Mindestmass an Sicherheit haben sollen.
# AdmissionConfiguration fuer den API-Server
# Datei: /etc/kubernetes/psa-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: PodSecurity
configuration:
apiVersion: pod-security.admission.config.k8s.io/v1
kind: PodSecurityConfiguration
defaults:
enforce: baseline
enforce-version: latest
audit: restricted
audit-version: latest
warn: restricted
warn-version: latest
exemptions:
usernames: []
runtimeClasses: []
namespaces:
- kube-system
- kube-node-lease
- kube-public
# API-Server mit der Konfiguration starten (Self-Managed)
# In der API-Server-Manifest-Datei:
# --admission-control-config-file=/etc/kubernetes/psa-config.yaml
# Pruefen ob die Konfiguration aktiv ist
kubectl create namespace test-psa
kubectl run nginx --image=nginx -n test-psa
# Sollte eine Warnung anzeigen, wenn warn=restricted gesetzt ist
kubectl delete namespace test-psa
PSS mit externen Policy Engines kombinieren
Pod Security Standards decken die wichtigsten Faelle ab, sind aber bewusst einfach gehalten. Fuer granulare Policies kombinieren Sie PSS mit einer Policy Engine:
# Beispiel: PSS als Basis + OPA Gatekeeper fuer zusaetzliche Regeln
# PSS stellt sicher: Kein privilegierter Zugriff
# Gatekeeper stellt sicher: Nur erlaubte Image-Registries
# Installation von Gatekeeper
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm install gatekeeper gatekeeper/gatekeeper \
--namespace gatekeeper-system \
--create-namespace
# Gatekeeper Constraint: Nur Images aus der internen Registry
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
name: allowed-repos
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaces:
- production
- staging
parameters:
repos:
- "registry.internal.example.com/"
- "docker.io/library/"
Fuer eine tiefere Einfuehrung in Kubernetes Security lesen Sie unseren Security Hardening Guide.
Best Practices fuer den produktiven Einsatz
1. Labels in GitOps verwalten
Namespace-Labels gehoeren in Ihre GitOps-Pipeline, nicht in manuelle kubectl-Befehle:
# namespace.yaml in Ihrem GitOps-Repository
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: v1.31
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
team: platform
environment: production
2. Monitoring der Violations
# Audit-Log-Violations zaehlen (mit jq)
# Nuetzlich um den Fortschritt der Migration zu tracken
kubectl get events --all-namespaces -o json | \
jq '[.items[] | select(.reason == "FailedCreate") |
select(.message | test("PodSecurity"))] | length'
3. CI/CD-Pipeline Integration
Pruefen Sie Ihre Manifeste vor dem Deployment:
# Mit kubectl --dry-run=server gegen den Cluster testen
kubectl apply --dry-run=server -f deployment.yaml -n production
# Oder lokal mit kubeconform und PSS-Checks
# Linting mit kube-linter
kube-lint lint deployment.yaml --config .kube-linter.yaml
Wenn Sie Ihre CI/CD-Pipeline mit GitOps betreiben, hilft unser ArgoCD Tutorial bei der Integration.
Checkliste: Pod Security Standards einfuehren
- Inventar erstellen: Alle Namespaces und ihre aktuellen Workloads dokumentieren
- Profile zuordnen: Jeder Namespace bekommt ein Ziel-Profil (Privileged, Baseline, Restricted)
- Warn/Audit zuerst: Labels mit
warnundauditauf dem Ziel-Profil setzen - Violations beheben: Deployments anpassen (Security Context, Images, Capabilities)
- Enforce aktivieren: Nach erfolgreicher Test-Phase
enforceauf das Ziel-Profil setzen - Monitoring einrichten: Audit-Logs ueberwachen, Alerts bei neuen Violations
- GitOps integrieren: Namespace-Labels in der Versionskontrolle verwalten
Wer sich fuer die CKS-Zertifizierung vorbereitet, sollte Pod Security Standards im Detail kennen -- das Thema ist pruefungsrelevant.
Fazit
Kubernetes Pod Security Standards sind deutlich einfacher als die alten PodSecurityPolicies. Drei Profile, drei Modi, Steuerung ueber Namespace-Labels -- das ist alles. Der groesste Vorteil: Sie koennen schrittweise verschaerfen, ohne bestehende Workloads zu brechen.
Starten Sie mit warn und audit auf restricted fuer alle Anwendungs-Namespaces. Beheben Sie die gemeldeten Violations. Und aktivieren Sie dann enforce. In den meisten Clustern ist das in zwei bis vier Wochen erledigt.
Fuer komplexere Anforderungen -- Image-Policies, Label-Pflicht, Netzwerk-Regeln -- kombinieren Sie PSS mit OPA Gatekeeper oder Kyverno. PSS liefert die Basis, die Policy Engine die granularen Regeln.
Weitere Informationen zu Kubernetes-Security finden Sie in unserem RBAC Enterprise Guide und dem Network Security Artikel.
Verwandte Artikel
- Kubernetes Security Hardening: Cluster absichern
- CKS Zertifizierung Deutschland
- Kubernetes RBAC Enterprise
- Kubernetes Network Security
- Kubernetes Compliance: DSGVO und BSI
Brauchen Sie Unterstuetzung bei der Einfuehrung von Pod Security Standards in Ihrem Cluster? Unsere Kubernetes-Experten helfen Ihnen bei der Migration von PodSecurityPolicy und der Konfiguration sicherer Namespaces -- kontaktieren Sie uns fuer eine unverbindliche Beratung.
Kubernetes-Beratung gesucht?
Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.
📖 Verwandte Artikel
Weitere interessante Beiträge zu ähnlichen Themen
Pod Security Admission: PSA richtig konfigurieren
Pod Security Admission ersetzt PodSecurityPolicy seit Kubernetes 1.25. So konfiguriert ihr PSA-Profile und Enforcement-Modi für eure Namespaces.
OPA Gatekeeper: Admission Controller für Kubernetes
OPA Gatekeeper setzt Policies im Kubernetes-Cluster durch und blockiert fehlerhafte Deployments vor dem Rollout. Praxisguide mit Rego-Beispielen.
API Server Hardening: Kubernetes absichern
Kubernetes API Server härten mit Audit-Logging, Encryption at Rest, OIDC und Rate Limiting. Praxisnahe Konfiguration für sichere Cluster.
Kubernetes Audit Logging richtig konfigurieren
Kubernetes Audit Logging einrichten: Audit Policies definieren, Log-Backends konfigurieren und compliance-relevante Ereignisse zuverlässig erfassen.
CIS Benchmark: Kubernetes-Cluster härten
CIS Kubernetes Benchmark mit kube-bench prüfen und kritische Findings an API-Server, etcd und Kubelet systematisch beheben.