Minimize The Admission Of Containers With
More Info:
allowPrivilegeEscalation lets a process gain more privileges than its parent. Blocking it limits in-container privilege escalation.
Risk Level
High
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
List pods with
allowPrivilegeEscalation: true(any machine with kubectl access)kubectl get pods --all-namespaces -o json \| jq -r '.items[]| . as $pod| .spec.containers[]| select(.securityContext.allowPrivilegeEscalation == true)| "\($pod.metadata.namespace) \($pod.metadata.name) \(.name)"' \| sort -uSave this list; you will need it to update the workloads.
-
Review each affected workload and identify its owner (any machine with kubectl access)
For each<namespace> <pod> <container>from step 1, get the owning controller (Deployment/DaemonSet/StatefulSet/Job/etc.):NAMESPACE="<namespace>"POD="<pod_name>"kubectl get pod "$POD" -n "$NAMESPACE" -o jsonpath='{.metadata.ownerReferences}' | jqUse kind/name from
.kindand.nameto determine which resource/manifest you must change. If there is no ownerReference, the Pod is standalone and must be edited or recreated directly. -
Decide policy: namespace-level restriction vs. per-workload hardening (any machine with kubectl access)
- If your cluster uses Pod Security Admission, consider labeling user namespaces with
pod-security.kubernetes.io/enforce=restricted(or equivalent) only after confirming workloads can run without privilege escalation. - Otherwise, design or select an admission policy mechanism (e.g., Kyverno, OPA/Gatekeeper, custom admission webhook) that rejects Pods where any container has
securityContext.allowPrivilegeEscalation: trueor omitssecurityContextentirely.
This benchmark control is MANUAL: you must choose the appropriate tooling and exceptions model for your environment; there is no single mandatory configuration.
- If your cluster uses Pod Security Admission, consider labeling user namespaces with
-
Harden workload manifests by setting
allowPrivilegeEscalation: false(any machine with kubectl access)
For each affected controller (Deployment, DaemonSet, etc.), edit its manifest (preferably in your Git/IaC repo) to set this on every container and initContainer:spec:template:spec:containers:- name: <container-name>securityContext:allowPrivilegeEscalation: false# keep or add any other required securityContext fieldsinitContainers:- name: <init-container-name>securityContext:allowPrivilegeEscalation: falseApply the updated manifest:
kubectl apply -f <path-to-updated-manifest>.yamlFor standalone Pods generated without a controller, recreate them from an updated manifest containing the same change.
-
(Optional) Introduce a rejecting admission policy for future Pods (any machine with kubectl access)
After confirming critical workloads function withallowPrivilegeEscalation: false, configure your chosen admission controller to:- Deny any Pod in user namespaces where any container or initContainer has
.securityContext.allowPrivilegeEscalation: true. - Optionally also deny if the field is missing, to force explicit
false.
Implement the policy using your platform’s recommended mechanism (e.g., Kyverno, Gatekeeper, PSA labels), then test in a non-production namespace before rolling out cluster-wide.
- Deny any Pod in user namespaces where any container or initContainer has
-
Verify remediation (any machine with kubectl access)
Re-run the audit and confirm no containers reportis_compliant: false:kubectl get pods --all-namespaces -o custom-columns=POD_NAME:.metadata.name,POD_NAMESPACE:.metadata.namespace --no-headers | while read -r pod_name pod_namespacedokubectl get pod "${pod_name}" --namespace "${pod_namespace}" -o json | jq -c '.spec.containers[]' | while read -r containerdocontainer_name=$(echo ${container} | jq -r '.name')container_allowprivesc=$(echo ${container} | jq -r '.securityContext.allowPrivilegeEscalation' | sed -e 's/null/notset/g')if [ "${container_allowprivesc}" = "false" ] || [ "${container_allowprivesc}" = "notset" ]; thenecho "***pod_name: ${pod_name} container_name: ${container_name} pod_namespace: ${pod_namespace} is_container_allowprivesc: ${container_allowprivesc} is_compliant: true"elseecho "***pod_name: ${pod_name} container_name: ${container_name} pod_namespace: ${pod_namespace} is_container_allowprivesc: ${container_allowprivesc} is_compliant: false"fidonedoneInvestigate and adjust any remaining
is_compliant: falseworkloads or explicitly document them as approved exceptions.
Using kubectl
On any machine with kubectl access:
- Create a baseline restricted admission policy for each user-workload namespace
(example for namespaceprod-apps; repeat per namespace with user workloads):
kubectl label namespace prod-apps pod-security.kubernetes.io/enforce=restricted --overwrite
kubectl label namespace prod-apps pod-security.kubernetes.io/audit=restricted --overwrite
kubectl label namespace prod-apps pod-security.kubernetes.io/warn=restricted --overwrite
This uses the built-in “restricted” Pod Security Admission level, which disallows privilege escalation by default.
- For clusters/namespaces where you cannot (or do not want to) use PSA labels, create an explicit policy object.
a) If your cluster still supports PodSecurityPolicy (legacy), apply:
# psp-deny-allowprivilegeescalation.yaml
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: deny-allow-priv-escalation
spec:
privileged: false
allowPrivilegeEscalation: false
requiredDropCapabilities:
- ALL
runAsUser:
rule: MustRunAsNonRoot
seLinux:
rule: RunAsAny
fsGroup:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
volumes:
- 'configMap'
- 'emptyDir'
- 'projected'
- 'secret'
- 'downwardAPI'
- 'persistentVolumeClaim'
Apply it:
kubectl apply -f psp-deny-allowprivilegeescalation.yaml
Then bind it to your workloads’ service accounts (example for namespace prod-apps using the default service account; adjust as needed):
# rb-psp-deny-allowprivilegeescalation.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: use-deny-allow-priv-escalation-psp
namespace: prod-apps
rules:
- apiGroups: ['policy']
resources: ['podsecuritypolicies']
verbs: ['use']
resourceNames: ['deny-allow-priv-escalation']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: use-deny-allow-priv-escalation-psp
namespace: prod-apps
subjects:
- kind: ServiceAccount
name: default
namespace: prod-apps
roleRef:
kind: Role
name: use-deny-allow-priv-escalation-psp
apiGroup: rbac.authorization.k8s.io
Apply it:
kubectl apply -f rb-psp-deny-allowprivilegeescalation.yaml
b) If your cluster uses another admission controller (e.g., Kyverno or OPA/Gatekeeper), define an equivalent rule that denies pods where .spec.containers[*].securityContext.allowPrivilegeEscalation == true. (This part is policy‑engine specific and must be created with its own CRDs; there is no generic kubectl-only object beyond what is shown above.)
- Update existing offending pods’ manifests so containers explicitly set
allowPrivilegeEscalation: false.
Example pod spec snippet you should ensure for each container:
spec:
containers:
- name: my-container
image: my-image:tag
securityContext:
allowPrivilegeEscalation: false
Apply updated workload manifests using your normal deployment process, or:
kubectl apply -f <your-updated-workload-manifest>.yaml
- Verification (run on any machine with kubectl):
kubectl get pods --all-namespaces -o custom-columns=POD_NAME:.metadata.name,POD_NAMESPACE:.metadata.namespace --no-headers | while read -r pod_name pod_namespace
do
kubectl get pod "${pod_name}" --namespace "${pod_namespace}" -o json | jq -c '.spec.containers[]' | while read -r container
do
container_name=$(echo ${container} | jq -r '.name')
container_allowprivesc=$(echo ${container} | jq -r '.securityContext.allowPrivilegeEscalation' | sed -e 's/null/notset/g')
if [ "${container_allowprivesc}" = "false" ] || [ "${container_allowprivesc}" = "notset" ]; then
echo "***pod_name: ${pod_name} container_name: ${container_name} pod_namespace: ${pod_namespace} is_container_allowprivesc: ${container_allowprivesc} is_compliant: true"
else
echo "***pod_name: ${pod_name} container_name: ${container_name} pod_namespace: ${pod_namespace} is_container_allowprivesc: ${container_allowprivesc} is_compliant: false"
fi
done
done
Automation
#!/usr/bin/env bash
#
# Enforce: Minimize the admission of containers with allowPrivilegeEscalation=true
# Scope: Any machine with kubectl access to the cluster
#
# Strategy:
# - For every namespace that is intended for user workloads, create/update a
# Pod Security admission label to enforce the "restricted" policy at
# enforce level. The restricted profile blocks allowPrivilegeEscalation by default.
# - This script is idempotent and safe to re-run.
#
# IMPORTANT:
# - You must adjust the NAMESPACE_FILTER below to match your environment.
# By default, this script targets all namespaces EXCEPT a small set of
# common system namespaces, which is often what "user workloads" means.
# - The benchmark is MANUAL: you must review which namespaces should be
# protected before running this.
set -euo pipefail
# ------------- CONFIGURATION (EDIT TO SUIT YOUR CLUSTER) --------------------
# Regex pattern of namespaces to EXCLUDE from restricted policy enforcement.
# These are assumed to be system/control-plane namespaces.
EXCLUDE_NS_REGEX='^(kube-system|kube-public|kube-node-lease|kube-*|default|istio-system|linkerd|cilium-system|tigera-operator|calico-system|monitoring|logging)$'
# Pod Security Admission label key/value for restricted policy at enforce level.
PSA_ENFORCE_KEY="pod-security.kubernetes.io/enforce"
PSA_ENFORCE_VALUE="restricted"
# ---------------------------------------------------------------------------
# Ensure kubectl is available and we can reach the cluster.
if ! command -v kubectl >/dev/null 2>&1; then
echo "ERROR: kubectl not found in PATH. Install kubectl and ensure it can reach the cluster." >&2
exit 1
fi
if ! kubectl version --request-timeout=5s >/dev/null 2>&1; then
echo "ERROR: Unable to talk to the Kubernetes API with kubectl." >&2
exit 1
fi
echo "Discovering namespaces intended for user workloads..."
# List all namespaces, then filter out excluded/system namespaces.
USER_NS_LIST=$(
kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' \
| grep -Ev "${EXCLUDE_NS_REGEX}" || true
)
if [ -z "${USER_NS_LIST}" ]; then
echo "No user-workload namespaces matched. Nothing to do."
exit 0
fi
echo "Namespaces selected for restricted Pod Security enforcement:"
echo "${USER_NS_LIST}" | sed 's/^/ - /'
# Apply/Update Pod Security Admission labels on each user namespace
for ns in ${USER_NS_LIST}; do
echo "Applying PSA 'restricted' policy to namespace: ${ns}"
# Check existing label value (if any)
current_value=$(kubectl get ns "${ns}" -o jsonpath="{.metadata.labels.${PSA_ENFORCE_KEY}}" 2>/dev/null || true)
if [ "${current_value}" = "${PSA_ENFORCE_VALUE}" ]; then
echo " Namespace ${ns} already has ${PSA_ENFORCE_KEY}=${PSA_ENFORCE_VALUE} (no change)."
continue
fi
if [ -n "${current_value}" ]; then
echo " Updating ${PSA_ENFORCE_KEY} from '${current_value}' to '${PSA_ENFORCE_VALUE}' on namespace ${ns}."
else
echo " Setting ${PSA_ENFORCE_KEY}=${PSA_ENFORCE_VALUE} on namespace ${ns}."
fi
kubectl label ns "${ns}" "${PSA_ENFORCE_KEY}=${PSA_ENFORCE_VALUE}" --overwrite
done
echo
echo "Verification: Pod Security Admission labels in user-workload namespaces"
kubectl get ns ${USER_NS_LIST} -o custom-columns=NAME:.metadata.name,ENFORCE:.metadata.labels.pod-security\\.kubernetes\\.io/enforce
echo
echo "Additional verification of running Pods' allowPrivilegeEscalation values:"
kubectl get pods --all-namespaces -o custom-columns=POD_NAME:.metadata.name,POD_NAMESPACE:.metadata.namespace --no-headers | while read -r pod_name pod_namespace
do
kubectl get pod "${pod_name}" --namespace "${pod_namespace}" -o json | jq -c '.spec.containers[]' | while read -r container
do
container_name=$(echo "${container}" | jq -r '.name')
container_allowprivesc=$(echo "${container}" | jq -r '.securityContext.allowPrivilegeEscalation' | sed -e 's/null/notset/g')
if [ "${container_allowprivesc}" = "false" ] || [ "${container_allowprivesc}" = "notset" ]; then
echo "***pod_name: ${pod_name} container_name: ${container_name} pod_namespace: ${pod_namespace} is_container_allowprivesc: ${container_allowprivesc} is_compliant: true"
else
echo "***pod_name: ${pod_name} container_name: ${container_name} pod_namespace: ${pod_namespace} is_container_allowprivesc: ${container_allowprivesc} is_compliant: false"
fi
done
done
echo
echo "NOTE:"
echo "- New Pods in the labeled namespaces must comply with the 'restricted' profile,"
echo " which disallows privilege escalation unless explicitly configured otherwise."
echo "- Existing non-compliant Pods may continue running until they are recreated."