Minimize The Admission Of Privileged Containers
More Info:
Privileged containers effectively have root access to the host node. Pod Security Admission policies should restrict their admission across namespaces.
Risk Level
Critical
Address
Security
Compliance Standards
- CIS AKS
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
List and review existing Pod Security Admission labels per namespace
Run on any machine with kubectl access:kubectl get ns -L pod-security.kubernetes.io/enforce \-L pod-security.kubernetes.io/audit \-L pod-security.kubernetes.io/warnIdentify application namespaces that either have no PSA labels or do not use
restrictedforenforce. -
Identify namespaces that must allow privileged workloads (exceptions)
Still on any kubectl machine, list all namespaces and note system/infra ones that may legitimately need privileges (e.g.kube-system,gatekeeper-system,azure-arc,azure-extensions-usage-system, CNI/CSI/operator namespaces):kubectl get nsBuild a short list of namespaces that should be exempt from strict
restrictedenforcement and will instead usebaselineor onlywarn. -
Detect currently running privileged pods for risk assessment
Check which pods are privileged or use host namespaces, per namespace, to understand current usage before tightening policy:kubectl get pods -A -o json | \jq -r '.items[] |. as $pod |.spec.containers[]? as $c |select(($c.securityContext.privileged == true)or ($c.securityContext.allowPrivilegeEscalation == true)or ($c.securityContext.runAsUser == 0)or ($pod.spec.hostPID == true)or ($pod.spec.hostNetwork == true)or ($pod.spec.hostIPC == true)) |"\($pod.metadata.namespace) \($pod.metadata.name) \($c.name)"'For each listed pod, decide whether it is strictly required and in which namespace it runs.
-
Apply or tighten PSA enforcement on standard application namespaces
For each application namespace where privileged containers are not required, enforcerestrictedper the remediation:kubectl label --overwrite ns <APP_NAMESPACE> pod-security.kubernetes.io/enforce=restrictedOptionally, to ensure at least
baselinewarnings everywhere while you roll outrestrictedgradually:kubectl label --overwrite ns --all pod-security.kubernetes.io/warn=baseline -
Adjust or confirm labels for exception namespaces
For each namespace identified in step 2 that must allow some privileged behavior, ensure it does NOT haveenforce=restrictedunless validated safe. You can either remove or relax labels as appropriate, for example:# Example: relax to baseline for an infra namespacekubectl label --overwrite ns kube-system pod-security.kubernetes.io/enforce=baselineRe-review privileged pods from step 3 in these namespaces to confirm they are intentional and documented.
-
Verify the final configuration and admission behavior
a) Confirm labels:kubectl get ns -L pod-security.kubernetes.io/enforce \-L pod-security.kubernetes.io/audit \-L pod-security.kubernetes.io/warnb) (Optional but recommended) Attempt to create a clearly privileged test pod in a
restrictednamespace and ensure it is rejected; for example:kubectl -n <RESTRICTED_NAMESPACE> apply -f - << 'EOF'apiVersion: v1kind: Podmetadata:name: privileged-testspec:containers:- name: busyboximage: busyboxsecurityContext:privileged: truecommand: ["sh", "-c", "sleep 3600"]EOFConfirm that admission is denied by the Pod Security Admission controller, demonstrating that privileged pods are minimized as intended.
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
How to review
- Problem indicators:
- Empty or missing
pod-security.kubernetes.io/enforcefor regular (non-system) namespaces. pod-security.kubernetes.io/enforceset toprivilegedorbaselinewhere you expectrestricted.- No
pod-security.kubernetes.io/warnlabel on namespaces where you want a cluster-wide baseline/warn posture.
- Empty or missing
# 2) Show full labels for all namespaces for detailed inspection
# Run on: any machine with kubectl access
kubectl get ns --show-labels
How to review
- Problem indicators:
- Business / application namespaces without any
pod-security.kubernetes.io/*labels. - PSA labels only on a few namespaces, implying many are unprotected.
- Sensitive namespaces (e.g., production) not set to
enforce=restricted.
- Business / application namespaces without any
# 3) Identify namespaces that allow or already run privileged pods
# (sample admission test using a dry-run privileged pod)
# Run on: any machine with kubectl access
for ns in $(kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}'); do
echo "=== Testing namespace: $ns ==="
kubectl apply -n "$ns" -f - --dry-run=server <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: privileged-test
spec:
containers:
- name: c
image: busybox
command: ["sh", "-c", "sleep 3600"]
securityContext:
privileged: true
restartPolicy: Never
EOF
echo
done
How to review
- Problem indicators:
- Namespaces where the dry-run succeeds (no PSA-related error): these currently admit privileged pods.
- Namespaces where the dry-run fails specifically due to Pod Security Admission (forbidden/denied) are configured to block privileged pods, which is usually desired (except for intentionally exempt system namespaces).
# 4) Inspect existing pods that are privileged or host-level
# Run on: any machine with kubectl access
kubectl get pods -A -o jsonpath='
{range .items[*]}
{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}
{.spec.securityContext.runAsUser}{"\t"}
{range .spec.containers[*]}
{"container="}{.name}{": privileged="}{.securityContext.privileged}{" capAdd="}{.securityContext.capabilities.add}{" "}
{end}
{"\n"}
{end}' | column -t
How to review
- Problem indicators:
- Application namespaces (not
kube-systemor other intentionally privileged namespaces) where:- Any container shows
privileged=true. - Unnecessary extra capabilities are added (e.g.,
SYS_ADMIN) that may require higher policies.
- Any container shows
- Pods relying on privileged mode instead of fine-grained securityContext settings.
- Application namespaces (not
# 5) Focus on non-system namespaces (where you usually want enforce=restricted)
# Run on: any machine with kubectl access
kubectl get ns -o jsonpath='{range .items[?(@.metadata.name!="kube-system" && @.metadata.name!="kube-public" && @.metadata.name!="kube-node-lease")]}{.metadata.name}{"\t"}{.metadata.labels.pod-security\.kubernetes\.io/enforce}{"\n"}{end}' \
| column -t
How to review
- Problem indicators:
- Empty or
nullenforce value in business / app namespaces. - Enforce set to anything weaker than your chosen standard (commonly
restricted) for those namespaces.
- Empty or
These commands surface the current posture; based on your environment’s needs, you must decide which namespaces should be tightened (e.g., label with enforce=restricted) and which must remain exempt (e.g., kube-system, admission controllers), before making any changes.
Automation
#!/usr/bin/env bash
# Report namespaces and pods that may allow privileged containers,
# plus current Pod Security Admission (PSA) labels.
set -euo pipefail
echo "=== Pod Security Admission labels per namespace ==="
# Shows which namespaces have PSA labels set (or missing).
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 \
--no-headers | sort
cat <<'EOF'
Interpretation:
- ENFORCE empty or not 'restricted' on application namespaces = needs review.
- System namespaces (e.g., kube-system, gatekeeper-system, azure-arc, azure-extensions-usage-system)
may intentionally differ but should still be reviewed.
EOF
echo "=== Namespaces WITHOUT an enforce=restricted PSA label ==="
kubectl get ns \
-o jsonpath='{range .items[?(!@.metadata.labels.pod-security\.kubernetes\.io/enforce)]}{.metadata.name}{"\n"}{end}'
echo
echo "=== Namespaces with enforce label NOT set to 'restricted' ==="
kubectl get ns \
-o jsonpath='{range .items[?(@.metadata.labels.pod-security\.kubernetes\.io/enforce!=="restricted")]}{.metadata.name}{"\t"}{.metadata.labels.pod-security\.kubernetes\.io/enforce}{"\n"}{end}'
cat <<'EOF'
Interpretation:
- Any non-system namespace listed above is a potential problem:
it is not enforcing the 'restricted' PSA level and may admit privileged pods.
EOF
echo "=== Pods that request privileged=true (across all namespaces) ==="
# Lists any container or initContainer with securityContext.privileged=true.
kubectl get pods --all-namespaces -o json | \
jq -r '
[
.items[]
| {
ns: .metadata.namespace,
pod: .metadata.name,
containers: (
(.spec.containers // []) + (.spec.initContainers // [])
| map({name, sc: .securityContext})[]
)
}
| select(.containers.sc.privileged == true)
| "\(.ns)\t\(.pod)\t\(.containers.name)\tprivileged=true"
] | unique[]' 2>/dev/null || echo "jq not available; skipping privileged container scan."
cat <<'EOF'
Interpretation:
- Any line here shows a pod/container that is explicitly privileged.
- If such pods exist in namespaces that are *not* exempt system namespaces,
this is typically a policy violation.
EOF
echo "=== Pods that can escalate capabilities (allowPrivilegeEscalation=true) ==="
kubectl get pods --all-namespaces -o json | \
jq -r '
[
.items[]
| {
ns: .metadata.namespace,
pod: .metadata.name,
containers: (
(.spec.containers // []) + (.spec.initContainers // [])
| map({name, sc: .securityContext})[]
)
}
| select(.containers.sc.allowPrivilegeEscalation == true)
| "\(.ns)\t\(.pod)\t\(.containers.name)\tallowPrivilegeEscalation=true"
] | unique[]' 2>/dev/null || echo "jq not available; skipping allowPrivilegeEscalation scan."
cat <<'EOF'
Interpretation:
- Not strictly 'privileged=true', but often disallowed under stricter policies.
- Use this as additional context when reviewing namespaces and workloads.
EOF
What output indicates a problem
Run on any machine with kubectl access and jq installed.
Problem indicators you should manually review and decide on:
-
Namespaces:
- Appearing under:
- “Namespaces WITHOUT an enforce=restricted PSA label”
- or “Namespaces with enforce label NOT set to 'restricted'”
- And they are not intentionally exempt system namespaces.
- These namespaces may admit privileged containers and should be considered for:
kubectl label --overwrite ns <NAMESPACE> pod-security.kubernetes.io/enforce=restricted
- Appearing under:
-
Pods:
- Any lines under:
- “Pods that request privileged=true (across all namespaces)”
- Especially in non-exempt namespaces.
- These workloads either need:
- design justification and documented exception, or
- remediation to run without
privileged: trueunder a restricted policy.
- Any lines under:
This script only reports the state; you must decide which namespaces/pods are acceptable exceptions and then apply labels or change manifests accordingly.