Skip to content
DevOps AI ToolKit
Newsletter
All prompts
AI for Kubernetes & Helm Difficulty: Intermediate ClaudeChatGPT

Kubernetes Pod Security Admission (PSA) Migration Prompt

Migrate from PodSecurityPolicy (removed 1.25) to Pod Security Admission — baseline/restricted levels, namespace labels, exceptions, audit warnings.

Target user
Kubernetes platform engineers migrating to PSA
Difficulty
Intermediate
Tools
Claude, ChatGPT

The prompt

You are a senior Kubernetes security engineer who has migrated production clusters from PodSecurityPolicy (PSP, removed in 1.25) to Pod Security Admission (PSA). You know the three levels (privileged/baseline/restricted) and the namespace-label model.

I will provide:
- The cluster K8s version
- Current security posture: PSP still installed? Or third-party (Kyverno/Gatekeeper) replacing? Or unprotected?
- Workload inventory complexity (number of namespaces, special workloads like CNI, monitoring agents that need elevated privileges)
- The goal: design PSA policy / migrate from PSP / debug a violation

Your job:

1. **Understand the PSA levels**:
   - **`privileged`** — no restrictions; for trusted system workloads
   - **`baseline`** — minimally restrictive; allows most non-malicious workloads; blocks known privilege escalations
   - **`restricted`** — heavily restricted; requires non-root, drop ALL caps, runAsNonRoot, seccompProfile
2. **The three enforcement modes** (per namespace label):
   - `enforce` — block violating pods
   - `audit` — record violation in audit log
   - `warn` — return warning to user but still admit
   - All three can be set with different levels (e.g., `audit: restricted`, `enforce: baseline`)
3. **Label format**:
   ```yaml
   metadata:
     labels:
       pod-security.kubernetes.io/enforce: baseline
       pod-security.kubernetes.io/enforce-version: latest
       pod-security.kubernetes.io/audit: restricted
       pod-security.kubernetes.io/warn: restricted
   ```
4. **Migration strategy** (3-phase):
   - **Phase 1**: Label every namespace with `audit: <target-level>` + `warn: <target-level>`. Workloads admit normally; violations logged.
   - **Phase 2**: Fix violating workloads (drop caps, run as non-root, etc.)
   - **Phase 3**: Switch to `enforce: <target-level>`
5. **Common violations** in `restricted` level (from baseline-compliant workloads):
   - `runAsNonRoot: true` not set
   - `allowPrivilegeEscalation: true` (default)
   - capabilities not dropped (`drop: [ALL]` required)
   - seccompProfile not set (`RuntimeDefault` required)
   - `runAsUser: 0` (root) used
6. **For workloads that need elevation**:
   - **System workloads** (kube-proxy, kubelet, CNI agents) in `kube-system` — label with `privileged`
   - **Monitoring agents** (node-exporter, fluent-bit) with hostPath/hostNetwork — `baseline` may not be enough; consider exception namespace
   - **Database operators** that need PVC mounts as specific UID — typically baseline-compatible with tuning
7. **Cluster-wide default** (1.27+):
   - Can set cluster-wide default via apiserver admission config
   - Namespace labels override
   - For "secure by default" — set cluster-wide to `baseline`; exempt specific namespaces
8. **For debugging a violation**:
   - Apply workload; PSA returns specific message ("violates restricted policy: runAsNonRoot != true")
   - Fix pod spec accordingly
   - Re-apply; verify admission

Mark DESTRUCTIVE: switching to `enforce` without an audit phase (immediate breakage), labeling `kube-system` with `restricted` (kube-system pods often need elevation), removing PSP enforcement during migration (window of unprotection).

---

Cluster K8s version: [DESCRIBE]
Current state: [PSP still in use / no enforcement / Kyverno-Gatekeeper / mixed]
Workload complexity: [DESCRIBE — namespaces, special workloads]
Goal: [design / migrate / debug a specific violation]
Specific violation (if debugging):
```
[PASTE error message + pod spec]
```

Run this prompt with AI

Test it, get an AI-improved version, or compare models — live in the Prompt Workspace. No copy-paste.

Why this prompt works

PSA is the official PSP replacement but with a simpler model (3 levels, labels). Migration mistakes (enforce too soon, system namespaces over-restricted) cause outages. This prompt walks the standard 3-phase migration.

How to use it

  1. For new clusters, start with baseline cluster-wide + restricted for app namespaces.
  2. For existing clusters with PSP, run an audit phase (long) before enforce.
  3. Label kube-system with privileged — always.
  4. For debugging, the violation message tells you which field to fix.

Useful commands

# Inventory labels
kubectl get namespaces -L pod-security.kubernetes.io/enforce,pod-security.kubernetes.io/audit,pod-security.kubernetes.io/warn

# Label a namespace
kubectl label namespace <ns> \
  pod-security.kubernetes.io/enforce=baseline \
  pod-security.kubernetes.io/enforce-version=latest \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted

# Test a workload against a level (dry-run)
kubectl apply --dry-run=server -f workload.yaml

# Find violations in audit logs
# (in audit log)
grep "pod-security" /var/log/kube-apiserver/audit.log | \
    jq 'select(.annotations."pod-security.kubernetes.io/audit-violations")'

# Look for `warn` warnings from kubectl
kubectl apply -f workload.yaml
# Warning lines appear in stderr if violations exist

# Cluster-wide PSA default (advanced; apiserver admission config)
# /etc/kubernetes/admission-config/podsecurity.yaml on apiserver

Migration phases

Phase 1: Audit mode

# Label every namespace except system
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
    case "$ns" in
        kube-system|kube-public|kube-node-lease)
            kubectl label namespace "$ns" pod-security.kubernetes.io/enforce=privileged --overwrite
            ;;
        *)
            kubectl label namespace "$ns" \
                pod-security.kubernetes.io/audit=baseline \
                pod-security.kubernetes.io/warn=baseline --overwrite
            ;;
    esac
done

Phase 2: Find violators

# Audit log query (depends on log backend)
kubectl get events --field-selector type=Warning -A | grep PolicyViolation

# Or use third-party PSA-violation reporters
# https://github.com/kubernetes-sigs/security-profiles-operator includes some

Phase 3: Enforce

# Switch to enforce after all violations fixed
for ns in $(kubectl get ns -l 'pod-security.kubernetes.io/audit=baseline' -o jsonpath='{.items[*].metadata.name}'); do
    kubectl label namespace "$ns" pod-security.kubernetes.io/enforce=baseline --overwrite
done

Spec adjustments for restricted compliance

apiVersion: v1
kind: Pod
metadata:
  name: secure-app
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: myorg/app:v1
    securityContext:
      runAsUser: 1000
      allowPrivilegeEscalation: false
      capabilities:
        drop: [ALL]
      readOnlyRootFilesystem: true
    volumeMounts:
    - name: tmp
      mountPath: /tmp
  volumes:
  - name: tmp
    emptyDir: {}

Cluster-wide default config

# /etc/kubernetes/admission-config/podsecurity.yaml
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]

Then in apiserver: --admission-control-config-file=/etc/kubernetes/admission-config/podsecurity.yaml.

Common findings this catches

  • Workload fails admission with runAsNonRoot != true → set securityContext explicitly.
  • hostPath volume rejected by baseline → typically OK in privileged namespace; or use CSI driver instead.
  • kube-system pod fails → kube-system labeled too restrictively; relax to privileged.
  • CNI agents (Calico, Cilium) fail → these need hostNetwork + privileged; their namespace should be privileged.
  • Logging agents (Fluent Bit, Fluentd) fail → hostPath access; baseline namespace, or use kube-state-metrics + remote logging.
  • runAsUser: 0 in restricted → set non-root UID; verify image supports it.

When to escalate

  • Cluster has many legacy PSPs that don’t map cleanly to PSA levels — engage security team; may need Kyverno/Gatekeeper for fine control.
  • Migration causes prolonged warnings/audits — fix violators incrementally; communicate timeline.
  • Conflict between PSA and third-party policy (Kyverno restrict policies) — consolidate ownership.

Related prompts

More Kubernetes & Helm prompts & error guides

Browse every Kubernetes & Helm prompt and troubleshooting guide in one place.

Free download · 368-page PDF

Reading prompts? Get all 500 in one free PDF

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.