AKS Pod Security Admission — namespace labels, PSS profiles, Azure Policy
Labels decide what may be born. Privileged pods that already run are not rewritten by a new enforce label.
Labels decide what may be born. Privileged pods that already run are not rewritten by a new enforce label.
§I — Frame
On AKS, Pod Security Admission (PSA) is the built-in gate that checks pod specs against Pod Security Standards (PSS) when objects are created or updated. You turn it on with namespace labels. Azure Policy for AKS can push the same posture across many namespaces and clusters. This is not NetworkPolicy (09-09), not IRSA (09-06), and not Ingress path routing (09-03). It is also not node AppArmor from the GKE hardening pass (08-31). Today is admit-time pod shape.
§II — Three profiles, three modes
| Profile | Intent |
|---|---|
| privileged | Unrestricted. Useful for system namespaces that must run hostPath or privileged init. |
| baseline | Blocks known-dangerous patterns (privileged, host namespaces, dangerous capabilities) while staying compatible with common workloads. |
| restricted | Hardened defaults: non-root, drop ALL capabilities, no privilege escalation, no hostPath, seccomp RuntimeDefault (or Localhost). |
| Mode | Effect |
|---|---|
| enforce | Reject non-conforming pods (admission denial). |
| audit | Allow, emit audit annotations/events. |
| warn | Allow, print warnings to the API client. |
Label keys:
pod-security.kubernetes.io/enforce=<profile>
pod-security.kubernetes.io/audit=<profile>
pod-security.kubernetes.io/warn=<profile>
Optional version pins: enforce-version, audit-version, warn-version (latest or a Kubernetes minor).
§III — Worked AKS shape
Create a tenancy namespace and enforce restricted:
kubectl create namespace secure-team
kubectl label ns secure-team \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=latest \
pod-security.kubernetes.io/warn=restricted \
--overwrite
A Deployment that sets privileged: true, runAsUser: 0, adds NET_ADMIN, or mounts hostPath will fail create under enforce=restricted. That is the Bootcamp Q14 failure class. Fix the pod template (drop privileges, run as non-root, emptyDir instead of hostPath) and re-apply.
Fleet note for AKS: enabling the Azure Policy add-on lets you assign built-in initiatives that require PSA labels or equivalent controls across namespaces. Use cluster-local labels for one namespace; use Azure Policy when the requirement is "every app namespace is at least baseline." Document which layer owns the control so two tools do not fight.
§IV — Failure modes
- Enforce after Pods exist. Existing Pods keep running. PSA checks create/update of Pod objects. To prove enforce, delete a Pod (or scale) and watch the ReplicaSet FailedCreate events (Bootcamp Q47 pattern).
- Wrong namespace labeled. Policy on
platformdoes not protectapp. - System namespaces at restricted. kube-system often needs privileged or hostPath. Leave system namespaces on privileged (or carefully baseline) and harden app namespaces first.
- Warn-only forever. Warn and audit are staging tools. Production tenancy that must reject root needs enforce.
- Confusing PSA with NetworkPolicy. PSA never filters east-west packets. A restricted pod can still dial the whole cluster unless NetworkPolicy says otherwise.
§V — How this differs from last K8s Ops
09-09 spent VPC CNI NetworkPolicy enforcement and least-permissive ingress. 09-06 spent OIDC issuer and IAM trust for ServiceAccounts. 09-03 spent AKS Ingress and Application Gateway paths. Today spends AKS PSA labels and PSS profiles, with Azure Policy as the optional fleet amplifier.
§VI — Operator checklist
- List namespaces and current
pod-security.kubernetes.io/*labels. - Choose profile per tenancy (app = restricted or baseline; system = privileged as needed).
- Apply enforce (and matching warn/audit during rollout).
- Dry-run a known-bad Pod:
kubectl label ns ... --dry-run=serverandkubectl apply --dry-run=server. - Confirm Azure Policy assignments if fleet policy is in scope.
- Inventory privileged SecurityContext pods (Dev/Go companions) before flipping enforce.
§VII — Closing
Admit the narrow pod. Measure FailedCreate after the label lands. Leave packet filters and cloud identity on their own shelves.
Related
- Dev — Python PSA label census
- Cert — CKS PSA restricted enforce
- Go — client-go PSA namespace inventory