What it does. Configures and operates the Kubernetes Pod Security Admission (PSA) controller that enforces Pod Security Standards: namespace enforce/audit/warn labels, cluster-wide defaults via AdmissionConfiguration, exemptions for usernames, runtime classes and namespaces, version pinning, and troubleshooting pods the controller rejected. Use when wiring PSA up on a cluster, setting cluster-wide default enforcement, exempting system namespaces, debugging why a pod was rejected or why enforcement is not firing, or reading PSA audit and warning output. Keywords: Pod Security Admission, PSA, admission controller, AdmissionConfiguration, pod-security.kubernetes.io labels, enforce audit warn, exemptions, kube-apiserver. Do not use for choosing which security profile a workload needs - use implementing-kubernetes-pod-security-standards. Part of mukul975/Anthropic-Cybersecurity-Skills (817 security skills) (mukul975/Anthropic-Cybersecurity-Skills).
Install
npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill implementing-pod-security-admission-controller, or copy the skill folder into ~/.claude/skills/implementing-pod-security-admission-controller/.
- Raw file:
curl -sL https://raw.githubusercontent.com/mukul975/Anthropic-Cybersecurity-Skills/HEAD/skills/implementing-pod-security-admission-controller/SKILL.md
SKILL.md (verbatim)
name: implementing-pod-security-admission-controller
description: >-
Configures and operates the Kubernetes Pod Security Admission (PSA) controller
that enforces Pod Security Standards: namespace enforce/audit/warn labels,
cluster-wide defaults via AdmissionConfiguration, exemptions for usernames,
runtime classes and namespaces, version pinning, and troubleshooting pods the
controller rejected. Use when wiring PSA up on a cluster, setting cluster-wide
default enforcement, exempting system namespaces, debugging why a pod was
rejected or why enforcement is not firing, or reading PSA audit and warning
output. Keywords: Pod Security Admission, PSA, admission controller,
AdmissionConfiguration, pod-security.kubernetes.io labels, enforce audit warn,
exemptions, kube-apiserver. Do not use for choosing which security profile a
workload needs - use implementing-kubernetes-pod-security-standards.
domain: cybersecurity
subdomain: container-security
tags:
- kubernetes
- pod-security-admission
- psa
- pod-security-standards
- admission-controller
version: '1.0'
author: mahipal
license: Apache-2.0
nist_csf:
- PR.PS-01
- PR.IR-01
- ID.AM-08
- DE.CM-01
mitre_attack:
- T1610
- T1611
- T1609
- T1525
Implementing Pod Security Admission Controller
Overview
Pod Security Admission (PSA) is a built-in Kubernetes admission controller (stable since v1.25) that enforces Pod Security Standards at the namespace level. It replaces the deprecated PodSecurityPolicy (PSP) and provides three security profiles: Privileged, Baseline, and Restricted, with three enforcement modes: enforce, audit, and warn.
When to Use
- Wiring PSA up on a cluster for the first time
- Setting cluster-wide default enforcement via
AdmissionConfiguration
- Exempting system namespaces, service accounts, or runtime classes from enforcement
- Debugging why a pod was rejected, or why enforcement is silently not firing
- Staging a safe rollout:
warn and audit first, enforce once violations reach zero
- Pulling PSA violations out of the kube-apiserver audit log
Not this skill: deciding which profile a workload should run under, or what
securityContext changes Restricted demands. Use
implementing-kubernetes-pod-security-standards.
Prerequisites
- Kubernetes v1.25+ (PSA is stable/GA)
- kubectl with cluster-admin access
- No dependency on external tools - PSA is built into kube-apiserver
Pod Security Standards
Privileged Profile
- Unrestricted - No restrictions applied
- Use case: System-level pods (kube-system, monitoring)
Baseline Profile
- Minimally restrictive - Prevents known privilege escalation
- Blocks: privileged containers, hostPID, hostIPC, hostNetwork, hostPorts, certain volume types, adding capabilities beyond runtime defaults
Restricted Profile
- Heavily restricted - Follows security best practices
- Requires: non-root, drop ALL capabilities, seccomp RuntimeDefault, read-only root filesystem considerations
- Blocks: Everything in Baseline plus running as root, privilege escalation, non-approved volume types
Enforcement Modes
| Mode |
Behavior |
Use Case |
| enforce |
Reject pods violating policy |
Production enforcement |
| audit |
Log violations to audit log |
Pre-enforcement assessment |
| warn |
Show warnings to user |
Developer feedback |
Implementation
Apply to Namespace via Labels
# Restricted enforcement with audit and warn
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: v1.28
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: v1.28
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: v1.28
# Baseline enforcement for staging
apiVersion: v1
kind: Namespace
metadata:
name: staging
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/enforce-version: v1.28
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: v1.28
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: v1.28
# Privileged for system namespaces
apiVersion: v1
kind: Namespace
metadata:
name: kube-system
labels:
pod-security.kubernetes.io/enforce: privileged
Apply Labels with kubectl
# Set restricted enforcement
kubectl label namespace production \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=v1.28 \
pod-security.kubernetes.io/audit=restricted \
pod-security.kubernetes.io/warn=restricted
# Set baseline enforcement
kubectl label namespace staging \
pod-security.kubernetes.io/enforce=baseline \
pod-security.kubernetes.io/audit=restricted \
pod-security.kubernetes.io/warn=restricted
# Check current labels
kubectl get namespace production -o jsonpath='{.metadata.labels}' | jq .
Dry-Run Testing
# Test what would happen with restricted policy on a namespace
kubectl label --dry-run=server --overwrite namespace staging \
pod-security.kubernetes.io/enforce=restricted
# Output shows existing pods that would violate the policy
# Warning: existing pods in namespace "staging" violate the new PodSecurity enforce level "restricted:latest"
Cluster-Wide Defaults (AdmissionConfiguration)
# /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-public
- kube-node-lease
- calico-system
- gatekeeper-system
- monitoring
- falco
Apply to API Server
# Add to kube-apiserver manifests
# /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
containers:
- command:
- kube-apiserver
- --admission-control-config-file=/etc/kubernetes/psa-config.yaml
volumeMounts:
- name: psa-config
mountPath: /etc/kubernetes/psa-config.yaml
readOnly: true
volumes:
- name: psa-config
hostPath:
path: /etc/kubernetes/psa-config.yaml
type: File
Compliant Pod Examples
Restricted-Compliant Pod
apiVersion: v1
kind: Pod
metadata:
name: restricted-pod
namespace: production
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
automountServiceAccountToken: false
containers:
- name: app
image: myregistry/myapp:v1.0.0
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
limits:
cpu: 500m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
Baseline-Compliant Pod
apiVersion: v1
kind: Pod
metadata:
name: baseline-pod
namespace: staging
spec:
containers:
- name: app
image: myregistry/myapp:v1.0.0
securityContext:
allowPrivilegeEscalation: false
resources:
limits:
cpu: 500m
memory: 256Mi
Migration from PodSecurityPolicy
Step 1: Audit Current State
# Check existing PSPs
kubectl get psp
# Check which service accounts use which PSP
kubectl get clusterrolebinding -o json | \
jq '.items[] | select(.roleRef.name | startswith("psp-")) | {name: .metadata.name, subjects: .subjects}'
Step 2: Map PSP to PSA Profiles
# For each namespace, determine required PSA level
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
echo "Namespace: $ns"
kubectl label --dry-run=server namespace $ns \
pod-security.kubernetes.io/enforce=restricted 2>&1 | head -5
done
Step 3: Apply PSA Labels (Audit First)
# Start with audit mode
kubectl label namespace production \
pod-security.kubernetes.io/audit=restricted \
pod-security.kubernetes.io/warn=restricted
Step 4: Review and Fix Violations
# Check audit logs for violations
kubectl get events --field-selector reason=FailedCreate -A
Step 5: Enable Enforcement
kubectl label namespace production \
pod-security.kubernetes.io/enforce=restricted
Monitoring
# Check PSA violations in events
kubectl get events --all-namespaces --field-selector reason=FailedCreate
# Check audit logs
kubectl logs -n kube-system kube-apiserver-* | grep "pod-security.kubernetes.io"
# List namespace PSA labels
kubectl get namespaces -L pod-security.kubernetes.io/enforce
Best Practices
- Start with audit+warn before enforce to assess impact
- Use dry-run to test enforcement before applying
- Exempt system namespaces (kube-system, monitoring) in cluster defaults
- Pin version (enforce-version) for predictable behavior across upgrades
- Set cluster-wide baseline as default, then restrict specific namespaces
- Combine with Gatekeeper for additional custom policies beyond PSA
- Use restricted profile for all production workloads
- Document exemptions with clear justification
Other files in this skill
assets/template.md (verbatim)
Pod Security Admission Deployment Plan
Namespace PSA Configuration
| Namespace |
Enforce |
Audit |
Warn |
Justification |
| production |
restricted |
restricted |
restricted |
Production workloads |
| staging |
baseline |
restricted |
restricted |
Pre-production testing |
| development |
baseline |
restricted |
restricted |
Developer workloads |
| kube-system |
privileged |
- |
- |
System components |
| monitoring |
privileged |
- |
- |
Prometheus, Grafana |
| ingress-nginx |
baseline |
restricted |
restricted |
Ingress controller |
Migration Checklist
Compliant Security Context Template
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
references/api-reference.md (verbatim)
API Reference: Kubernetes Pod Security Admission Controller
Libraries Used
| Library |
Purpose |
kubernetes |
Official Kubernetes Python client for cluster API access |
json |
Parse and format admission review payloads |
yaml |
Read and write Pod Security Standard label configurations |
Installation
pip install kubernetes pyyaml
Authentication
from kubernetes import client, config
# In-cluster (running inside a pod)
config.load_incluster_config()
# Local kubeconfig
config.load_kube_config(context="my-cluster")
v1 = client.CoreV1Api()
Pod Security Standards Levels
| Level |
Description |
privileged |
Unrestricted — no restrictions applied |
baseline |
Minimally restrictive — prevents known privilege escalation |
restricted |
Heavily restricted — follows hardening best practices |
Namespace Label API
Pod Security Admission is configured via namespace labels:
| Label |
Purpose |
pod-security.kubernetes.io/enforce |
Reject pods that violate the policy |
pod-security.kubernetes.io/enforce-version |
Pin policy to specific k8s version |
pod-security.kubernetes.io/audit |
Log violations in audit log |
pod-security.kubernetes.io/audit-version |
Pin audit policy version |
pod-security.kubernetes.io/warn |
Show warnings to kubectl users |
pod-security.kubernetes.io/warn-version |
Pin warning policy version |
Core Operations
List Namespaces with PSA Labels
namespaces = v1.list_namespace()
for ns in namespaces.items:
labels = ns.metadata.labels or {}
enforce = labels.get("pod-security.kubernetes.io/enforce", "none")
audit = labels.get("pod-security.kubernetes.io/audit", "none")
warn = labels.get("pod-security.kubernetes.io/warn", "none")
print(f"{ns.metadata.name}: enforce={enforce} audit={audit} warn={warn}")
Apply PSA Labels to a Namespace
body = {
"metadata": {
"labels": {
"pod-security.kubernetes.io/enforce": "restricted",
"pod-security.kubernetes.io/enforce-version": "latest",
"pod-security.kubernetes.io/audit": "restricted",
"pod-security.kubernetes.io/warn": "restricted",
}
}
}
v1.patch_namespace(name="production", body=body)
Audit All Namespaces for Missing PSA Labels
def audit_psa_labels():
findings = []
namespaces = v1.list_namespace()
for ns in namespaces.items:
name = ns.metadata.name
labels = ns.metadata.labels or {}
if name in ("kube-system", "kube-public", "kube-node-lease"):
continue
enforce = labels.get("pod-security.kubernetes.io/enforce")
if not enforce:
findings.append({"namespace": name, "issue": "no enforce label"})
elif enforce == "privileged":
findings.append({"namespace": name, "issue": "enforce=privileged"})
return findings
Check Pod Violations Against a Level
def check_pod_security(namespace, level="restricted"):
pods = v1.list_namespaced_pod(namespace=namespace)
violations = []
for pod in pods.items:
for container in pod.spec.containers:
sc = container.security_context
if not sc:
violations.append({
"pod": pod.metadata.name,
"container": container.name,
"issue": "no securityContext defined",
})
continue
if sc.privileged:
violations.append({
"pod": pod.metadata.name,
"container": container.name,
"issue": "privileged=true",
})
if sc.run_as_non_root is not True:
violations.append({
"pod": pod.metadata.name,
"container": container.name,
"issue": "runAsNonRoot not set",
})
caps = sc.capabilities
if level == "restricted" and (not caps or not caps.drop or "ALL" not in caps.drop):
violations.append({
"pod": pod.metadata.name,
"container": container.name,
"issue": "capabilities.drop does not include ALL",
})
return violations
kubectl Equivalents
# Label a namespace with restricted enforcement
kubectl label namespace production \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/warn=restricted \
--overwrite
# Dry-run to test impact before enforcing
kubectl label --dry-run=server --overwrite namespace production \
pod-security.kubernetes.io/enforce=restricted
# Check which namespaces have PSA labels
kubectl get namespaces -L pod-security.kubernetes.io/enforce
{
"namespace": "production",
"enforce_level": "restricted",
"audit_level": "restricted",
"warn_level": "restricted",
"pod_violations": [
{
"pod": "legacy-app-7f8b9c",
"container": "app",
"issue": "privileged=true"
}
],
"compliant": false
}
references/standards.md (verbatim)
Standards - Pod Security Admission Controller
Kubernetes Pod Security Standards
| Profile |
Controls Enforced |
| Baseline |
No privileged, no hostPID/IPC/Network, no hostPorts, restricted volumes, no procMount, restricted seccomp, restricted capabilities |
| Restricted |
All Baseline + non-root, drop ALL caps, seccomp required, restricted volume types, no privilege escalation |
CIS Kubernetes Benchmark v1.8
- 5.2.1: Ensure privileged containers are not used
- 5.2.2-5.2.4: Ensure host namespace sharing is disabled
- 5.2.5: Ensure privilege escalation is not allowed
- 5.2.6: Ensure root containers are not admitted
- 5.2.7: Ensure seccomp profile is set
- 5.7.3: Apply security context to pods
NIST SP 800-190
- Section 4.3: Container runtime security
- Section 5.4: Admission control enforcement
NSA/CISA Kubernetes Hardening Guide v1.2
- Section 1: Pod Security - Use Pod Security Standards
Compliance Mappings
- PCI DSS v4.0 Req 2.2: Configuration standards
- SOC 2 CC6.1: Logical access controls
- HIPAA 164.312(a)(1): Access controls
references/workflows.md (verbatim)
Workflow - Implementing Pod Security Admission
Phase 1: Assessment
- List all namespaces and their current security posture
- Run dry-run against restricted profile for each namespace
- Document violations and required exemptions
Phase 2: Apply Audit Mode
for ns in production staging; do
kubectl label namespace $ns \
pod-security.kubernetes.io/audit=restricted \
pod-security.kubernetes.io/warn=restricted
done
Phase 3: Fix Violations
- Update Deployments/StatefulSets with compliant security contexts
- Add seccomp profiles
- Switch containers to non-root
- Drop ALL capabilities
Phase 4: Enable Enforcement
kubectl label namespace production \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=v1.28
Phase 5: Set Cluster Defaults
- Create AdmissionConfiguration with baseline defaults
- Apply to kube-apiserver
- Exempt system namespaces
Phase 6: Monitor
- Watch for FailedCreate events
- Review audit logs weekly
- Update exemptions as needed
Back to mukul975/Anthropic-Cybersecurity-Skills (817 security skills) or Agent skills.