Minimize The Admission Privileged Container
More Info:
Do not generally permit containers to be run with the securityContext.privileged flag set to true.
Risk Level
Critical
Address
Security
Compliance Standards
- APRA CPS 234 (Australia)
- BSI C5 (Germany)
- Brazil LGPD
- CCPA / CPRA (California)
- CIS AKS
- CIS Critical Security Controls v8
- CMMC 2.0
- CSA Cloud Controls Matrix v4
- DPDPA
- Digital Operational Resilience Act (EU)
- Essential 8
- ISO/IEC 27017
- ISO/IEC 27018
- ISO/IEC 27701
- KSA PDPL
- MAS Technology Risk Management (Singapore)
- MITRE ATT&CK (Cloud)
- NIS2 Directive
- NIST SP 800-171
- NYDFS 23 NYCRR 500
- SWIFT Customer Security Controls Framework
- Sarbanes-Oxley IT General Controls
- UK NCSC Cyber Assessment Framework
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
List existing Pod Security labels on all namespaces
Run on: any machine with kubectl accesskubectl get ns --show-labelsIdentify namespaces lacking
pod-security.kubernetes.io/enforce,pod-security.kubernetes.io/warn, orpod-security.kubernetes.io/auditlabels, or where these are set weaker than desired (e.g., notrestrictedorbaseline). -
Identify namespaces that must be excluded from strict enforcement
Run on: any machine with kubectl accesskubectl get nsFrom the list, note system/infra namespaces (e.g.,
kube-system,gatekeeper-system,azure-arc,azure-extensions-usage-system, and any vendor/operator namespaces). Plan to either:- Leave them without
enforce=restricted, or - Use
warn/auditlevels first instead of strict enforcement.
- Leave them without
-
Apply restricted enforcement to selected application namespaces
For each non-excluded application namespace you want to lock down:
Run on: any machine with kubectl accesskubectl label --overwrite ns <NAMESPACE> pod-security.kubernetes.io/enforce=restrictedReplace
<NAMESPACE>with the actual name (e.g.,prod-app,staging-app). This will block future admission of privileged containers and other disallowed settings under the Restricted profile. -
Set a cluster-wide baseline warning level for all namespaces
Run on: any machine with kubectl accesskubectl label --overwrite ns --all pod-security.kubernetes.io/warn=baselineThis does not block workloads, but it will surface warnings when workloads violate the Baseline policy, helping you detect remaining privileged or near-privileged configurations.
-
Review existing workloads that might be using privileged containers
Run on: any machine with kubectl accesskubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{" "}{.spec.containers[*].name}{" "}{.spec.containers[*].securityContext.privileged}{"\n"}{end}' \| grep ' true' || echo "No containers with privileged=true found"For any pods reported with
privileged true, review their necessity with the workload owners and plan remediation (e.g., removesecurityContext.privileged: trueor migrate to capabilities/hostPath alternatives). -
Verify PSA labels and re-check after changes
Run on: any machine with kubectl access- Verify namespace labels:
kubectl get ns --show-labels
- If desired, attempt to deploy a test privileged pod into a restricted namespace to confirm admission is blocked (expect failure due to
enforce=restricted).
- Verify namespace labels:
Using kubectl
# 1) List all namespaces and their Pod Security Admission labels
# Run on: any machine with kubectl access
kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.labels.pod-security\.kubernetes\.io/enforce}{"\t"}{.metadata.labels.pod-security\.kubernetes\.io/warn}{"\n"}{end}' \
| column -t
Problem indication:
- Namespaces with an empty value in both
enforceandwarncolumns have no PSA policy configured. - Namespaces where
enforceis notrestricted(e.g., empty,baseline, or another value) are not enforcing the strict policy that blocks privileged containers. - Namespaces where only
warnis set (and notenforce) rely only on warnings, not enforcement.
# 2) Show full labels for a specific namespace (replace <namespace>)
kubectl get ns <namespace> --show-labels
Problem indication:
- Missing
pod-security.kubernetes.io/enforce=restrictedon namespaces where you expect strict blocking of privileged containers. - Absence of any
pod-security.kubernetes.io/*labels on application namespaces suggests privileged pods may be admitted unless controlled elsewhere.
# 3) Identify namespaces that are likely "system" or exempt candidates
kubectl get ns | egrep 'kube-system|gatekeeper-system|azure-arc|azure-extensions-usage-system'
Usage:
- These namespaces are commonly excluded from strict enforcement. Their presence does not indicate a problem by itself; they need human review to decide whether exemption is appropriate.
# 4) Spot-check for existing privileged pods (read-only review)
kubectl get pods -A -o jsonpath='{range .items[?(@.spec.containers[*].securityContext.privileged==true)]}{.metadata.namespace}{"\t"}{.metadata.name}{"\n"}{end}'
Problem indication:
- Any output here means there are currently pods running with
securityContext.privileged=true. - If these pods are in namespaces without
enforce=restricted, that namespace is a candidate for stricter PSA configuration (subject to application needs and exemptions).
# 5) Verify after you adjust labels (re-run relevant commands)
kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.labels.pod-security\.kubernetes\.io/enforce}{"\t"}{.metadata.labels.pod-security\.kubernetes\.io/warn}{"\n"}{end}' \
| column -t
Verification:
- Namespaces where you decided to enforce restricted PSA should now show
restrictedunder theenforcecolumn. - System/exempt namespaces should match your intended policy decision (e.g., no
enforce=restrictedif you chose to exempt them).
Automation
#!/usr/bin/env bash
# Report namespaces that do NOT have PSA labels enforcing restricted or warning on baseline.
# Run on: any machine with kubectl access and correct KUBECONFIG.
set -euo pipefail
echo "=== Pod Security Admission (PSA) labels per namespace ==="
kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.labels.pod-security\.kubernetes\.io/enforce}{"\t"}{.metadata.labels.pod-security\.kubernetes\.io/warn}{"\n"}{end}' \
| awk 'BEGIN{print "NAMESPACE\tENFORCE\tWARN"}1' | column -t
echo
echo "=== Namespaces WITHOUT enforce=restricted ==="
kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.labels.pod-security\.kubernetes\.io/enforce}{"\n"}{end}' \
| awk '$2 != "restricted" {print $1}' | sort
echo
echo "=== Namespaces WITHOUT warn=baseline ==="
kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.labels.pod-security\.kubernetes\.io/warn}{"\n"}{end}' \
| awk '$2 != "baseline" {print $1}' | sort
echo
echo "=== Namespaces with pods currently running privileged containers ==="
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| {ns:.metadata.namespace, name:.metadata.name, c:.spec.containers}
| select(.c != null)
| .c[]
| select(.securityContext.privileged == true)
| "\(.name)\t\(.securityContext.privileged)\t\(. | tostring)" as $cinfo
| "\(.ns)\t\(.name)\t" + $cinfo
' 2>/dev/null \
| awk 'BEGIN{print "NAMESPACE\tPOD\tCONTAINER\tPRIVILEGED\tCONTAINER_SPEC"}1' | column -t
How to interpret the output:
- In the first table, any namespace with an empty
ENFORCEfield is missingpod-security.kubernetes.io/enforce=restricted. These namespaces are not enforcing the restricted policy and may admit privileged containers. - In the “Namespaces WITHOUT enforce=restricted” list, every namespace shown is a candidate to tighten (unless it is intentionally excluded, e.g.
kube-system,gatekeeper-system,azure-arc,azure-extensions-usage-systemor other infrastructure namespaces you have decided to exempt). - In the “Namespaces WITHOUT warn=baseline” list, namespaces shown do not even have a baseline warning; these are higher priority for review.
- In the final section, any line indicates a pod that is currently running at least one privileged container; these namespaces and workloads should be reviewed and either:
- moved to exempt namespaces where privileged is explicitly allowed and justified, or
- refactored to run without
securityContext.privileged: true.