Minimize The Admission Of Privileged Containers
More Info:
Privileged containers can access host devices and escape isolation. Enforce Pod Security Admission policies in each namespace with user workloads to restrict privileged container admission.
Risk Level
Critical
Address
Security
Compliance Standards
- CIS OKE
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
List all namespaces and identify user-workload namespaces
- Run on: any machine with kubectl access
kubectl get ns --show-labels- From the output, determine which namespaces contain user workloads (excluding system/control namespaces such as
kube-system,kube-public,kube-node-lease,kube-admin, and any provider-specific system namespaces).
-
Review existing Pod Security Admission labels on user-workload namespaces
- Run on: any machine with kubectl access
kubectl get ns <USER_NAMESPACE> -o jsonpath='{.metadata.labels}' | jq- For each user namespace, check whether
pod-security.kubernetes.io/enforceis present and whether its value is at leastrestrictedfor namespaces where privileged workloads must not be allowed.
-
Identify current privileged pod usage and decide on required policy level
- Run on: any machine with kubectl access
kubectl get pods -A -o jsonpath='{range .items[?(@.spec.containers[*].securityContext.privileged==true)]}{.metadata.namespace}{"\t"}{.metadata.name}{"\n"}{end}'- For each user namespace, decide if privileged containers are truly required. If privileged pods are in use and needed, you may need to keep a less strict policy (e.g.,
baselineor no enforce label yet) or redesign those workloads. If they are not required, plan to enforcerestricted.
-
Apply or adjust Pod Security Admission labels per namespace
- Run on: any machine with kubectl access
- For namespaces where privileged containers must be prevented:
kubectl label --overwrite ns <USER_NAMESPACE> pod-security.kubernetes.io/enforce=restricted
- Optionally, to introduce a gentler rollout by warning before enforcing, you can use:
kubectl label --overwrite ns <USER_NAMESPACE> pod-security.kubernetes.io/warn=restricted
-
Optionally set default warnings cluster-wide, then tighten per-namespace
- Run on: any machine with kubectl access
kubectl label --overwrite ns --all pod-security.kubernetes.io/warn=baseline- Then override critical user namespaces individually with
pod-security.kubernetes.io/enforce=restrictedas in step 4, once you are confident workloads comply.
-
Verify namespaces are correctly labeled and privileged pods are blocked
- Run on: any machine with kubectl access
kubectl get ns -L pod-security.kubernetes.io/enforce -L pod-security.kubernetes.io/warn- In a namespace where you set
pod-security.kubernetes.io/enforce=restricted, attempt to create a privileged pod and confirm it is rejected:
kubectl run privileged-test \--image=alpine \--restart=Never \--overrides='{"spec":{"containers":[{"name":"c","image":"alpine","securityContext":{"privileged":true}}]}}' \-n <USER_NAMESPACE>- Ensure the API server denies this pod, confirming privileged containers are minimized in that namespace.
Using kubectl
# 1) List all namespaces and their Pod Security Admission labels
# Run on: any machine with kubectl access
kubectl get ns \
-o custom-columns='NAME:.metadata.name,ENFORCE:.metadata.labels.pod-security\.kubernetes\.io/enforce,WARN:.metadata.labels.pod-security\.kubernetes\.io/warn,AUDIT:.metadata.labels.pod-security\.kubernetes\.io/audit' \
--sort-by=.metadata.name
Problem indication:
ENFORCEis empty (<none>) for namespaces that host user workloads.ENFORCEis set toprivilegedin any user-workload namespace.- There is no
WARN/AUDITconfiguration where you expect at least visibility of violations.
Identify user workload namespaces (exclude system/control-plane):
# 2) List non-system namespaces (candidate user namespaces)
kubectl get ns \
--no-headers \
| awk '!/^(kube-system|kube-public|kube-node-lease|default)$/ {print $1}'
Problem indication:
- Any namespace returned here that, when checked in step 1, has no
pod-security.kubernetes.io/enforcelabel, or has it set toprivileged, needs review.
Drill into a single namespace’s PSA config:
# 3) Inspect labels on a specific namespace
NAMESPACE=example-namespace
kubectl get ns "$NAMESPACE" --show-labels
Problem indication:
- Missing
pod-security.kubernetes.io/enforcelabel, or value not aligned with your policy (e.g., notrestrictedfor sensitive/user-facing workloads). - Conflicting or unexpected combinations of
enforce,warn, andauditlabels.
Review currently admitted privileged workloads:
# 4) List pods that request privileged containers cluster-wide
kubectl get pods -A -o json \
| jq -r '
.items[]
| {ns: .metadata.namespace, pod: .metadata.name, containers: [.spec.containers[], (.spec.initContainers // [])[]]}
| .ns as $ns
| .pod as $pod
| .containers[]
| select(.securityContext.privileged == true)
| "\($ns) \($pod) \(.name) privileged=true"
'
Problem indication:
- Any line in the output shows a privileged container. For those namespaces:
- Check whether PSA
enforceis absent or too permissive (from steps 1–3). - Decide if those privileged pods are truly justified; if not, the namespace’s PSA policy is likely too weak.
- Check whether PSA
Automation
#!/usr/bin/env bash
set -euo pipefail
# This script runs on: any machine with kubectl access
echo "=== Pod Security Admission (PSA) status per namespace ==="
echo
# Show all namespaces with their PSA labels
echo "Current PSA labels on all namespaces:"
kubectl get ns -o custom-columns=NAME:.metadata.name,ENFORCE:.metadata.labels.pod-security\\.kubernetes\\.io/enforce,ENFORCE-VERSION:.metadata.labels.pod-security\\.kubernetes\\.io/enforce-version,WARN:.metadata.labels.pod-security\\.kubernetes\\.io/warn,AUDIT:.metadata.labels.pod-security\\.kubernetes\\.io/audit --sort-by=.metadata.name
echo
# Highlight namespaces that likely contain user workloads and lack a strong enforce policy
# Heuristics: exclude kube-system, kube-public, kube-node-lease, default, and any beginning with "kube-"
echo "Namespaces that MAY contain user workloads and do NOT enforce 'restricted':"
kubectl get ns -o json \
| jq -r '
.items[]
| select(.metadata.name
| test("^kube-") | not
and . != "kube-system"
and . != "kube-public"
and . != "kube-node-lease")
| {
name: .metadata.name,
enforce: (.metadata.labels["pod-security.kubernetes.io/enforce"] // "NONE")
}
| select(.enforce != "restricted")
| "\(.name)\tENFORCE=\(.enforce)"
' | sort || true
echo
# Report any existing pods that are privileged
echo "=== Pods currently running with privileged containers (cluster-wide) ==="
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| . as $pod
| [
$pod.metadata.namespace,
$pod.metadata.name,
(
[
($pod.spec.containers[]?, $pod.spec.initContainers[]?)
| select(.securityContext.privileged == true)
| .name
] | unique | join(",")
)
]
| select(.[2] != "")
| @tsv
' | awk 'BEGIN { OFS="\t"; print "NAMESPACE","POD","PRIVILEGED_CONTAINERS" } { print }' || true
echo
cat <<'EOF'
How to interpret results:
1) Namespace PSA label table:
- Problem indicators:
- ENFORCE is empty (no pod-security.kubernetes.io/enforce label).
- ENFORCE is set to "privileged" or "baseline" instead of "restricted"
for namespaces where you want to minimize privileged containers.
2) "Namespaces that MAY contain user workloads and do NOT enforce 'restricted'":
- This list is a REVIEW QUEUE, not an automatic violation:
- Each listed namespace may host user workloads but does not have
pod-security.kubernetes.io/enforce=restricted.
- For each, decide if enforcing 'restricted' is appropriate
(consider legacy workloads, operational needs, and migration plans).
3) "Pods currently running with privileged containers":
- Any line here indicates a pod with at least one container
having securityContext.privileged=true.
- For each such pod, review:
- Whether privilege is strictly required.
- Whether it’s in a namespace that should enforce 'restricted'.
- Whether it can be refactored to use less-privileged mechanisms.
EOF