The PSP to Pod Security Standards migration was supposed to be simple. It wasn't. Half our legacy apps broke because they were running as root and nobody documented why. But compared to the YAML hell of Pod Security Policies, which got deprecated in K8s 1.21 and finally killed in 1.25, Pod Security Standards is actually a relief.
Instead of writing custom PSP YAML files that nobody understood (we all copy-pasted from Stack Overflow), you get three options. Done. Pod Security Admission handles everything through namespace labels. Actually stable since 1.25 and built right into K8s, which is nice for once. Still need to configure it properly, but at least it exists without needing another third-party operator.
The Three Security Profiles
Privileged is basically "fuck it, do whatever you want" mode. Everything's allowed - privileged containers, host network access, hostPath volumes. Your kube-system namespace probably needs this because system pods are special snowflakes that need to touch everything.
Baseline blocks the obvious stupid shit while still being practical. No privileged containers, no host namespace sharing, no dangerous Linux capabilities. Most Helm charts from 2019 work with Baseline after you patch a few securityContext settings.
Restricted is where things get real. Non-root execution required, all capabilities dropped except NET_BIND_SERVICE, mandatory seccomp and AppArmor profiles. This breaks more things than you expect - DNS-based service discovery, init containers that write configs, monitoring agents that need special access. We had three apps that took weeks to fix because they assumed they could write to /tmp as root.
Implementation Through Pod Security Admission
Pod Security Admission is built into K8s now (finally stable in 1.25) but of course you still need to configure it. Three modes: enforce (kills pods that don't comply), audit (logs violations), and warn (shows warnings to kubectl users).
Start with audit and warn modes before enabling enforce - seriously, don't skip this step or you'll take down production. EKS, GKE, and AKS all support Pod Security Standards now, but the configuration varies enough to make you swear at your cloud provider.
Namespace-level labels control everything. Your kube-system namespace stays Privileged, production apps get Restricted, everything else gets Baseline. The error messages are useless - "violates PodSecurity restricted" is the most unhelpful error message in K8s. It doesn't tell you WHICH control failed, so you get to play guessing games.
Migration from Pod Security Policies
The migration from PSPs is like ripping off a Band-Aid that's been stuck for three years. Google's migration guide makes it sound easy - surprise, it's fucking not.
First, you audit your existing PSPs to see what they actually do. Most organizations discover they have 10 different PSPs that do basically the same thing, plus one snowflake policy for that legacy Java app that needs root access for "historical reasons" (nobody remembers what those reasons were).
The real timeline: Plan 2-3 months for a cluster with 100+ apps if you want to sleep at night. The policy change takes 5 minutes, fixing everything that breaks takes forever. Our first production cluster migration? Disaster. Found like 40-something apps running as root (maybe 47? stopped counting), a bunch that needed privileged containers because "legacy reasons" that nobody could explain, and one critical database backup script that just assumed it owned the entire filesystem. Version pinning seems smart until you're stuck on an old standard during cluster upgrades and can't figure out why your new deployments aren't starting. We learned this the hard way during a K8s 1.27 upgrade when half our apps wouldn't restart.