Minimize The Admission Of Containers With Allow Privilege
More Info:
Do not generally permit containers to be run with the allowPrivilegeEscalation flag set to true.
Risk Level
High
Address
Security
Compliance Standards
- APRA CPS 234 (Australia)
- BSI C5 (Germany)
- Brazil LGPD
- CCPA / CPRA (California)
- CIS Critical Security Controls v8
- CIS OKE
- 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)
- 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 namespaces with user workloads and existing policies
- Run on: any machine with kubectl access
kubectl get nskubectl get psp,pss,validatingwebhookconfiguration,mutatingwebhookconfiguration -A 2>/dev/null- Decide which namespaces contain user workloads (exclude system namespaces such as
kube-system,kube-public,kube-node-lease, provider-specific system namespaces, etc.).
-
Review current constraints on allowPrivilegeEscalation per namespace
- For each user namespace
<ns>:
# Check if any PodSecurity admission labels are presentkubectl get ns <ns> -o yaml | grep -i "pod-security" -A2 || true# List pods and containers that currently use allowPrivilegeEscalation=truekubectl get pods -n <ns> -o json | \jq -r '.items[]| {pod: .metadata.name,c: (.spec.containers + (.spec.initContainers // []))}| .pod as $pod| .c[]| select(.securityContext.allowPrivilegeEscalation == true)| "\($pod) \(.name) allowPrivilegeEscalation=true"'- Note namespaces/workloads that require privileged behavior and those that do not.
- For each user namespace
-
Decide your policy per namespace
- For each user namespace, choose one of:
- Strict: disallow
allowPrivilegeEscalation=truefor all user workloads. - Exception-based: disallow by default but allow for a small set of known pods/containers after review.
- Strict: disallow
- Document any workloads that must keep
allowPrivilegeEscalation=trueand why (e.g., specific debug/infra containers).
- For each user namespace, choose one of:
-
Implement or adjust admission policy for each namespace
- Option A – using Pod Security admission labels (per namespace
<ns>):- To enforce at least
restricted(which effectively disallowsallowPrivilegeEscalation=trueexcept for system workloads in exempt namespaces):kubectl label ns <ns> \pod-security.kubernetes.io/enforce=restricted \pod-security.kubernetes.io/enforce-version=latest \--overwrite
- To enforce at least
- Option B – using a validating admission policy/mechanism you already run (e.g., Gatekeeper/Kyverno/ValidatingAdmissionPolicy):
- Create or adjust a policy that rejects pods where any container or initContainer has
securityContext.allowPrivilegeEscalation=truein the target namespaces. - Apply via your existing policy deployment manifests, then verify with a dry-run pod (see next step).
- Create or adjust a policy that rejects pods where any container or initContainer has
- Option A – using Pod Security admission labels (per namespace
-
Test that the policy behaves as intended
- On any machine with kubectl access, for each protected namespace
<ns>:
cat <<'EOF' | kubectl apply -n <ns> -f - --dry-run=serverapiVersion: v1kind: Podmetadata:name: test-allow-pe-truespec:containers:- name: cimage: busyboxcommand: ["sh", "-c", "sleep 3600"]securityContext:allowPrivilegeEscalation: trueEOF- Confirm this is rejected in namespaces where you decided to disallow
allowPrivilegeEscalation=true. - Optionally test a pod omitting
allowPrivilegeEscalationor setting it tofalseto confirm legitimate workloads still admit.
- On any machine with kubectl access, for each protected namespace
-
Re-verify cluster-wide and track exceptions
- Run on any machine with kubectl access:
# Re-scan all namespaces for pods with allowPrivilegeEscalation=truefor ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); doecho "Namespace: $ns"kubectl get pods -n "$ns" -o json | \jq -r '.items[]| {pod: .metadata.name,c: (.spec.containers + (.spec.initContainers // []))}| .pod as $pod| .c[]| select(.securityContext.allowPrivilegeEscalation == true)| "\($pod) \(.name) allowPrivilegeEscalation=true"' || trueechodone- Ensure remaining
allowPrivilegeEscalation=trueusages correspond only to explicitly documented exceptions or system/infra components you intentionally exempted.
Using kubectl
# 1) List all namespaces (for scoping your review)
# Run on: any machine with kubectl access
kubectl get namespaces -o name
Review which of these are user-workload namespaces (not kube-system, kube-public, etc.). For each user namespace, check for policies that restrict allowPrivilegeEscalation:
# 2) Check for validating admission policies related to allowPrivilegeEscalation
# Run on: any machine with kubectl access
kubectl get validatingadmissionpolicy,validatingadmissionpolicybinding -A
Problem indication:
- No
ValidatingAdmissionPolicy/ValidatingAdmissionPolicyBindingobjects that referenceallowPrivilegeEscalationor container security context fields. - Or they exist, but are not bound (
Bindingmissing orparamRefmisconfigured).
If you use Gatekeeper (OPA) for policy, inspect constraints:
# 3) List Gatekeeper constraints and templates (if used)
# Run on: any machine with kubectl access
kubectl get constrainttemplates -A
kubectl get constraints -A
Problem indication:
- No constraint/template that enforces
securityContext.allowPrivilegeEscalation=falseon Pods/Workloads. - Constraints exist but are scoped only to a subset of namespaces that does not include your user-workload namespaces.
Now review actual workloads for allowPrivilegeEscalation usage. This is evidence, not the policy itself:
# 4) Inspect current pods in a namespace for allowPrivilegeEscalation
# Replace <NAMESPACE> with a user-workload namespace
# Run on: any machine with kubectl access
kubectl get pods -n <NAMESPACE> -o json \
| jq '.items[]
| { name: .metadata.name,
containers: [ .spec.containers[]
| { name: .name,
allowPrivilegeEscalation: ( .securityContext.allowPrivilegeEscalation // "unset" )
}
],
initContainers: ( .spec.initContainers // []
| [ .[]
| { name: .name,
allowPrivilegeEscalation: ( .securityContext.allowPrivilegeEscalation // "unset" )
}
]
)
}'
Problem indication:
- Any container or initContainer shows
"allowPrivilegeEscalation": true. - Many containers show
"unset"and you have no admission policy forcing it tofalse(this typically means the setting is uncontrolled and could default totruedepending on runtime/pod security configuration).
To focus only on containers where it is explicitly true:
# 5) Show only pods where any container/initContainer has allowPrivilegeEscalation=true
# Run on: any machine with kubectl access
kubectl get pods -n <NAMESPACE> -o json \
| jq '.items[]
| select(
([.spec.containers[]?.securityContext?.allowPrivilegeEscalation] // []) | any(. == true)
or
([.spec.initContainers[]?.securityContext?.allowPrivilegeEscalation] // []) | any(. == true)
)
| { name: .metadata.name }'
Problem indication:
- Any pod names returned here represent workloads that currently run with
allowPrivilegeEscalation=true.
Finally, inspect how pods are being created (Deployments, DaemonSets, etc.) to see if their templates set this flag:
# 6) Review workload specs for allowPrivilegeEscalation
# Run on: any machine with kubectl access
# Deployments
kubectl get deploy -n <NAMESPACE> -o yaml \
| grep -nA3 -B5 -E 'allowPrivilegeEscalation'
# DaemonSets
kubectl get ds -n <NAMESPACE> -o yaml \
| grep -nA3 -B5 -E 'allowPrivilegeEscalation'
# StatefulSets
kubectl get sts -n <NAMESPACE> -o yaml \
| grep -nA3 -B5 -E 'allowPrivilegeEscalation'
Problem indication:
- Any workload templates explicitly set
allowPrivilegeEscalation: true. - No compensating policy (from earlier steps) is in place for that namespace to block such specs from being admitted in the future.
These commands only surface the current state. Deciding which workloads (if any) may legitimately require allowPrivilegeEscalation=true, and designing namespace-scoped policies that enforce the desired standard while allowing justified exceptions, requires human review.
Automation
#!/usr/bin/env bash
# Report pods and (pod)security admission settings related to allowPrivilegeEscalation
set -euo pipefail
echo "=== 1) Pods with allowPrivilegeEscalation != false (or missing) ==="
echo "Namespace,Pod,Container,allowPrivilegeEscalation"
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| . as $pod
| (.metadata.namespace // "default") as $ns
| (.metadata.name // "") as $podname
| (
($pod.spec.initContainers // []) + ($pod.spec.containers // [])
)[]
| .name as $cname
| .securityContext.allowPrivilegeEscalation as $ape
| if $ape != false then
"\($ns),\($podname),\($cname),\($ape)"
else
empty
end
' | sort
cat <<'EOF'
[INTERPRETATION]
- Any CSV line printed above indicates a container that is *not* explicitly pinned to allowPrivilegeEscalation=false.
- allowPrivilegeEscalation values you may see:
- "false" (container is safe; if nothing prints, all are explicitly false)
- "true" (problem: container is allowed to escalate privileges)
- "null" (field not set; admission policy should normally prevent this or default it to false)
- Focus review on application namespaces (exclude kube-system / control-plane if required by your platform).
EOF
echo "=== 2) Namespace-level (Pod)Security admission labels (v1.25+) ==="
echo "Namespace,psa-profile,psa-enforce,psa-warn,psa-audit"
kubectl get ns --show-labels -o json \
| jq -r '
.items[]
| .metadata.name as $ns
| .metadata.labels as $l
| [
$ns,
($l["pod-security.kubernetes.io/profile"] // ""),
($l["pod-security.kubernetes.io/enforce"] // $l["pod-security.kubernetes.io/enforce-level"] // ""),
($l["pod-security.kubernetes.io/warn"] // ""),
($l["pod-security.kubernetes.io/audit"] // "")
]
| @csv
' | sort
cat <<'EOF'
[INTERPRETATION]
- For namespaces running user workloads, you generally want:
- enforce (or profile) level "restricted" (or stricter), which disallows allowPrivilegeEscalation=true.
- Potential problems:
- No PodSecurity labels at all on a user-workload namespace (empty columns).
- enforce/enforce-level set to "privileged" or "baseline" where you expect "restricted".
- warn/audit weaker than enforce can indicate drift or gaps to review.
EOF
echo "=== 3) PodSecurityPolicy objects (if still in use on older clusters) ==="
if kubectl api-resources | grep -q "^podsecuritypolicies"; then
kubectl get psp -o json \
| jq -r '
.items[]
| .metadata.name as $name
| .spec.allowPrivilegeEscalation as $ape
| .spec.defaultAllowPrivilegeEscalation as $dape
| "\($name),allowPrivilegeEscalation=\($ape),defaultAllowPrivilegeEscalation=\($dape)"
' | sort
cat <<'EOF'
[INTERPRETATION]
- PSPs that either:
- .spec.allowPrivilegeEscalation == true, or
- .spec.defaultAllowPrivilegeEscalation == true, or
- either field is null/omitted
may allow pods with allowPrivilegeEscalation=true to be admitted.
- Review which service accounts / namespaces are bound to such PSPs.
EOF
else
echo "PodSecurityPolicy API not found; skipping PSP review."
fi