Pod Security Standards (PSS) on EKS aren’t just a set of rules; they’re a dynamic enforcement mechanism that prevents unauthorized pod security configurations from ever reaching your cluster.
Let’s see PSS in action. Imagine a basic nginx deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
If you try to deploy this as is to an EKS cluster with PSS enforced, you might get an error. Why? Because by default, nginx:latest might run as root, which violates the baseline or restricted PSS.
To illustrate, let’s assume your EKS cluster has the restricted PSS policy applied at the namespace level. You’d typically do this by labeling the namespace:
kubectl label namespace default pod-security.kubernetes.io/enforce=restricted
Now, if you try to apply the nginx-deployment YAML above, you’ll likely see an admission control error, something along the lines of:
Error from server (Forbidden): error when creating "nginx-deployment.yaml": admission webhook "pod-security.eks.amazonaws.com" denied the request: restricted: container nginx within pod nginx-deployment-xyzabc must not run as root (user: 0)
This is the system preventing a potentially insecure pod from being created. The pod-security.eks.amazonaws.com webhook is the admission controller doing the heavy lifting. It intercepts the pod creation request and checks it against the PSS policy configured for that namespace.
To fix this, you need to modify the pod spec to comply. For nginx, a common adjustment is to specify a non-root user. You can often find this information in the container’s documentation or by inspecting the image. For nginx, using the lts or stable tags is generally recommended over latest, and they often have USER directives. If not, you can override it:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
securityContext:
runAsUser: 101 # Example non-root user ID for nginx
runAsGroup: 101
allowPrivilegeEscalation: false
containers:
- name: nginx
image: nginx:stable-alpine # Using a more specific, potentially safer tag
ports:
- containerPort: 80
Here, we’ve added a securityContext to the pod spec, explicitly setting runAsUser and runAsGroup to a non-root ID (101 is a common one for nginx, but it depends on the image). We also set allowPrivilegeEscalation: false to further adhere to the restricted policy. Now, when you apply this modified YAML, the admission controller will allow the deployment.
The core problem PSS solves is the lack of a default security posture for workloads. Without it, any container image could be deployed with elevated privileges, potentially leading to security breaches. EKS’s integration with PSS ensures that only pods adhering to a defined security baseline can run.
The PSS levels — privileged, baseline, and restricted — offer increasing levels of security. privileged allows everything. baseline prevents known privilege escalations. restricted applies a strong security posture, disallowing root execution, host mounts, and other dangerous capabilities. You can also set policies at the audit and warn levels, which log or warn about violations without blocking them, useful for migrating to stricter policies.
The exact levers you control are the PSS profile (privileged, baseline, restricted) and the enforcement action (enforce, audit, warn) applied at the namespace level via labels. These labels are the interface to the pod-security.eks.amazonaws.com admission controller.
What most people don’t realize is that the runAsUser or runAsGroup values in securityContext must match an actual user ID present within the container image’s /etc/passwd file. If you specify a runAsUser that doesn’t exist in the image, the container might fail to start because the entrypoint process cannot be executed by a non-existent user.
The next step after enforcing security is managing image provenance and vulnerability scanning for the images you do allow.