FigJam Diagram: Pod Security Standards — Namespace Policy Levels (expires 2026-04-13)
Kubernetes Pod Security Admission (PSA) is enforced cluster-wide via namespace labels. Each namespace is assigned an enforcement level that controls what pods are permitted to run. Configuration is declarative in kubernetes/core/pod-security-standards.yaml; individual app manifests may also set labels on their own namespace (last-applied wins).
PSA operates in three modes per namespace: enforce (reject non-compliant pods), audit (log violations), and warn (surface warnings to the API caller). Most namespaces use enforce only; arc-runner-system uses a split configuration to catch avoidable escalations without blocking DinD workloads.
| Level | Description |
|---|---|
| restricted | Most secure — no host namespaces, no privileged containers, requires runAsNonRoot + seccomp profile |
| baseline | Moderate — prevents known privilege escalations, allows containers running as root |
| privileged | No restrictions — required for GPU device access, host networking, DinD, iSCSI |
Unlabelled namespaces inherit the k3s cluster default: privileged (permissive). Every namespace must have an explicit label.
| Namespace | Managed In | Notes |
|---|---|---|
dev-workspace |
PSS file | Standard dev namespace |
wiki |
App manifest | Wiki.js sets runAsNonRoot + seccompProfile |
gha-dashboard |
App manifest | GitHub Actions dashboard |
bryce (mesh-peers) |
App manifest | WireGuard VPN mesh peer namespace |
| Namespace | Managed In | Notes |
|---|---|---|
aja-recipes |
PSS file | Node.js recipe tracker |
alert-responder |
PSS file | FastAPI + AWS Bedrock (HTTPS only) |
authentik |
PSS file + App manifest | Helm chart doesn't set runAsNonRoot/seccompProfile natively |
auto-brand |
PSS file | CI image tagging bot |
aws-lens |
PSS file | Web app viewer |
cardboard |
PSS file + App manifest | Flask app — no seccompProfile on all containers |
cat-game |
PSS file | Simple web game |
cluster-health-monitor |
PSS file | Python HTTP metrics collector |
digital-signage |
PSS file | Flask microservices + Mosquitto + PostgreSQL |
dnd |
App manifest | FastAPI + PostgreSQL + pgvector |
email-gateway |
App manifest | Postfix runs as root (required by MTA) |
ham |
PSS file | Flask fitness tracker |
jupyter |
PSS file | Standard Jupyter notebook server |
kube-utils |
PSS file | Honeypot HTTP server (Python socketserver) |
media-profiler |
PSS file | Media analysis tool |
monitoring |
PSS file | node-exporter DaemonSet uses host mounts |
openclaw-ops |
PSS file | FastAPI ops agent with read-only ClusterRole |
openclaw-personal |
PSS file | Personal agent FastAPI — no cluster authority |
open-webui |
App manifest | LiteLLM + Open-WebUI |
polymarket-lab |
PSS file | Research/analytics platform |
public-ingress |
PSS file | TLS certs + Traefik middleware configs (no privileged pods) |
rag |
PSS file | RAG ingestion pipeline |
security-scanner |
PSS file | PostgreSQL starts as root |
trade-bot |
PSS file + App manifest | No seccompProfile on all containers |
| Namespace | Managed In | Notes |
|---|---|---|
arc-runner-system |
PSS file | DinD sidecar — enforce=privileged, audit+warn=baseline |
home-assistant |
PSS file + App manifest | hostNetwork + NET_ADMIN + NET_RAW for mDNS/SSDP |
kube-system |
PSS file | System components (Traefik, CoreDNS, MetalLB) |
longhorn-system |
PSS file | instance-manager uses hostPath + privileged containers for iSCSI/NVMeoF |
media |
App manifest | Jellyfin/Plex GPU passthrough — /dev/dri DRM ioctls require privileged: true |
protonvpn |
App manifest | VPN gateway with NET_ADMIN + TUN device |
proxmox-watchdog |
PSS file + App manifest | hostNetwork: true to reach Kasa HS300 when overlay is down |
wireguard-exporter |
PSS file | NET_ADMIN required for wg show |
The cluster uses a partially centralized governance model:
kubernetes/core/pod-security-standards.yaml — covers all infrastructure namespaces and app namespaces that don't define their own PSS labelskubernetes/apps/<app>/) — some apps set their own PSS labels in their Namespace resource (e.g., media, home-assistant, protonvpn)When both sources define labels on the same namespace, last-applied wins. In practice both agree — the central PSS file is kept in sync with app manifests.
Adding a new namespace: Add PSS labels to either the app manifest Namespace resource or the central PSS file. Default to baseline. Only request privileged when the workload requires host networking, device file access, or kernel capabilities beyond NET_BIND_SERVICE.
# Apply central PSS labels
kubectl apply -f kubernetes/core/pod-security-standards.yaml
# Verify enforcement on a namespace
kubectl get namespace <name> -o yaml | grep pod-security
# Check for violations (dry-run on a namespace)
kubectl label namespace <name> \
pod-security.kubernetes.io/enforce=baseline \
--dry-run=server
media namespace requiring privileged PSS for Intel QSV GPU transcodinghome-assistant namespace requiring privileged for hostNetwork + NET_ADMINwireguard-exporter namespace requiring privileged for NET_ADMINproxmox-watchdog namespace requiring privileged for hostNetwork