Veröffentlicht am

Pod Security Standards: PSS richtig konfigurieren

Teilen:
Authors

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 warn und audit auf restricted, bevor Sie enforce aktivieren -- 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:

EigenschaftPodSecurityPolicy (alt)Pod Security Standards (neu)
ZuordnungUeber RBAC/ServiceAccountsUeber Namespace-Labels
GranularitaetCluster-weitPro Namespace
KonfigurationEigene API-ObjekteLabels auf Namespaces
InstallationAdmission Plugin aktivierenStandardmaessig aktiv ab 1.25
KomplexitaetHoch (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 Unmasked laufen

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 (RuntimeDefault oder Localhost)
  • 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
ModusVerhaltenAPI-Server Response
enforcePod wird abgelehntHTTP 403 Forbidden
auditVerstoss wird in Audit-Log geschriebenPod wird erstellt
warnUser sieht Warning-MeldungPod 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 -unprivileged Varianten.
  • capabilities.drop ALL: Entfernt alle Linux-Capabilities. Falls Ihre App auf Port unter 1024 lauschen muss, fuegen Sie NET_BIND_SERVICE hinzu.

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

  1. Inventar erstellen: Alle Namespaces und ihre aktuellen Workloads dokumentieren
  2. Profile zuordnen: Jeder Namespace bekommt ein Ziel-Profil (Privileged, Baseline, Restricted)
  3. Warn/Audit zuerst: Labels mit warn und audit auf dem Ziel-Profil setzen
  4. Violations beheben: Deployments anpassen (Security Context, Images, Capabilities)
  5. Enforce aktivieren: Nach erfolgreicher Test-Phase enforce auf das Ziel-Profil setzen
  6. Monitoring einrichten: Audit-Logs ueberwachen, Alerts bei neuen Violations
  7. 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


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