Lab 30 - Pod Security Admission
Lab 30 - Pod Security Admission
Goal: roll out Pod Security Standards on a namespace the safe way: warn first, enforce later. Chapter: Pod Security Standards and Admission
Uses namespace hard and hardened.yaml from
Lab 29.
# 1 - which namespaces have a level today?
kubectl get ns -L pod-security.kubernetes.io/enforce,pod-security.kubernetes.io/warn
Nothing - every namespace allows privileged Pods.
# 2 - a privileged Pod, allowed today
kubectl run root-shell -n dev --image busybox:1.36 --restart=Never \
--overrides='{"spec":{"hostPID":true,"containers":[{"name":"root-shell","image":"busybox:1.36","command":["sleep","3600"],"securityContext":{"privileged":true}}]}}'
kubectl get pod root-shell -n dev
kubectl delete pod root-shell -n dev
hostPID + privileged = full control over the node. Nothing stopped it.
Step 1: warn and audit
# 3 -
kubectl label ns dev pod-security.kubernetes.io/warn=restricted \
pod-security.kubernetes.io/audit=restricted
kubectl run test -n dev --image nginx:1.27
Created - but with a Warning: would violate PodSecurity "restricted:latest"
listing every problem. Developers see it, nothing breaks.
Step 2: what would break?
# 4 - dry run before enforcing
kubectl label --dry-run=server --overwrite ns dev pod-security.kubernetes.io/enforce=baseline
kubectl label --dry-run=server --overwrite ns dev pod-security.kubernetes.io/enforce=restricted
baseline - no complaints: plain nginx is fine. restricted - every
existing Pod is listed.
Step 3: enforce
# 5 - baseline in dev
kubectl label --overwrite ns dev pod-security.kubernetes.io/enforce=baseline
kubectl run root-shell -n dev --image busybox:1.36 --restart=Never \
--overrides='{"spec":{"hostPID":true,"containers":[{"name":"root-shell","image":"busybox:1.36","command":["sleep","3600"],"securityContext":{"privileged":true}}]}}'
Error from server (Forbidden): ... violates PodSecurity "baseline:latest": host namespaces (hostPID=true), privileged.
# 6 - restricted in hard: the hardened Pod passes, a plain one does not
kubectl label --overwrite ns hard pod-security.kubernetes.io/enforce=restricted
kubectl delete -f ~/hardened.yaml --ignore-not-found
kubectl apply -f ~/hardened.yaml # accepted
kubectl run plain -n hard --image nginx:1.27 # Forbidden
The Deployment trap
# 7 -
kubectl create deploy plain -n hard --image nginx:1.27
kubectl get deploy plain -n hard # 0/1 - but "created"
kubectl describe rs -n hard -l app=plain | tail -3
The Deployment was accepted; the ReplicaSet cannot create Pods
(FailedCreate ... violates PodSecurity). Always check the ReplicaSet events
when a Deployment stays at 0.
Discovery
InfodiscoverTask A. Label every namespace that has no level yet with
warn=baseline - except kube-system, calico-system and tigera-operator.
Task B. Make plain in hard run under restricted with the smallest
possible change.
Clean up
kubectl delete deploy plain -n hard; kubectl delete pod test -n dev --ignore-not-found