Minimize Admission Privileged Containers
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 Critical Security Controls v8
- CIS EKS
- 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
-
Identify namespaces that should host only non-privileged workloads (typically all user workload namespaces; exclude system namespaces like
kube-system,kube-public,kube-node-leaseif needed). On any machine with kubectl access:kubectl get ns -
For each target namespace, enforce the Restricted Pod Security Admission policy to block privileged containers. Replace
NAMESPACEwith the actual namespace name. On any machine with kubectl access:kubectl label --overwrite ns NAMESPACE pod-security.kubernetes.io/enforce=restricted -
(Optional but recommended) Configure a cluster-wide warning for less strict baseline violations on all namespaces to help discover workloads that would be affected if you tighten policies further. On any machine with kubectl access:
kubectl label --overwrite ns --all pod-security.kubernetes.io/warn=baseline -
Attempt to create a privileged pod in a Restricted namespace to confirm admission is blocked. On any machine with kubectl access, replace
NAMESPACEas appropriate:kubectl run privileged-test \--image=busybox \--restart=Never \--namespace NAMESPACE \--overrides='{"apiVersion":"v1","kind":"Pod","metadata":{"name":"privileged-test"}, "spec":{"containers":[{"name":"c","image":"busybox","command":["sh","-c","sleep 3600"],"securityContext":{"privileged":true}}]}}'You should see an admission error indicating the pod is not allowed due to Pod Security restrictions.
-
Clean up the test pod (if it was created) from the test namespace. On any machine with kubectl access:
kubectl delete pod privileged-test -n NAMESPACE --ignore-not-found -
Verification (cluster-wide): confirm no currently running containers are privileged. On any machine with kubectl access:
kubectl get pods --all-namespaces -o json | \jq -r 'if any(.items[]?.spec.containers[]?; .securityContext?.privileged == true) then "PRIVILEGED_FOUND" else "NO_PRIVILEGED" end'The output should be:
NO_PRIVILEGED
Using kubectl
On any machine with kubectl access:
-
Identify namespaces with user workloads (example:
team-a,team-b,prod-apps). Adjust the list below to your cluster. -
Enforce
restrictedPod Security Admission (PSA) on those namespaces (blocks privileged pods):
kubectl label --overwrite ns team-a pod-security.kubernetes.io/enforce=restricted
kubectl label --overwrite ns team-b pod-security.kubernetes.io/enforce=restricted
kubectl label --overwrite ns prod-apps pod-security.kubernetes.io/enforce=restricted
- (Optional) Set a cluster‑wide warning level so you see PSA warnings everywhere without blocking:
kubectl label --overwrite ns --all pod-security.kubernetes.io/warn=baseline
- Verify labels are in place:
kubectl get ns --show-labels | grep pod-security.kubernetes.io
- Verify no privileged containers remain (same as audit):
kubectl get pods --all-namespaces -o json | \
jq -r 'if any(.items[]?.spec.containers[]?; .securityContext?.privileged == true) then "PRIVILEGED_FOUND" else "NO_PRIVILEGED" end'
Automation
#!/usr/bin/env bash
set -euo pipefail
# This script:
# - Identifies namespaces that currently allow privileged containers
# - Applies Pod Security Admission labels to minimize privileged containers
# - Verifies that no privileged containers are admitted
#
# Run from: any machine with kubectl access and jq installed.
# 1) Safety checks
if ! command -v kubectl >/dev/null 2>&1; then
echo "kubectl not found in PATH" >&2
exit 1
fi
if ! command -v jq >/dev/null 2>&1; then
echo "jq not found in PATH" >&2
exit 1
fi
# Ensure we can talk to the cluster
kubectl cluster-info >/dev/null
echo "=== Detecting namespaces with privileged containers ==="
# 2) Detect namespaces that currently have privileged containers
# (for operator awareness; labeling is applied broadly below)
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| select(any(.spec.containers[]?; .securityContext?.privileged == true))
| .metadata.namespace
' | sort -u || true
echo "=== Applying Pod Security Admission labels to restrict privileged containers ==="
# 3) Enforce 'restricted' PSA level on all namespaces that may host user workloads
# Adjust the namespace selector as appropriate for your environment.
# Below we:
# - enforce=restricted on all namespaces that are NOT in a small system list
# - warn=baseline on all namespaces (for visibility)
#
# Edit SYSTEM_NAMESPACES if you need a different set.
SYSTEM_NAMESPACES=("kube-system" "kube-public" "kube-node-lease" "default")
# Build a regex of system namespaces for grep -Ev
SYSTEM_REGEX="$(printf '%s\n' "${SYSTEM_NAMESPACES[@]}" | paste -sd '|' -)"
# Label all namespaces with warn=baseline (idempotent)
echo "Labeling all namespaces with pod-security.kubernetes.io/warn=baseline= (idempotent)..."
kubectl label ns --all pod-security.kubernetes.io/warn=baseline --overwrite
# Label non-system namespaces with enforce=restricted (idempotent)
echo "Labeling non-system namespaces with pod-security.kubernetes.io/enforce=restricted (idempotent)..."
USER_NAMESPACES=$(kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' \
| grep -Ev "^(${SYSTEM_REGEX})$" || true)
if [ -n "$USER_NAMESPACES" ]; then
# shellcheck disable=SC2086
kubectl label ns $USER_NAMESPACES pod-security.kubernetes.io/enforce=restricted --overwrite
else
echo "No user namespaces detected to label with enforce=restricted."
fi
echo "=== Current PSA labels per namespace ==="
kubectl get ns --show-labels
# 4) Verification - ensure no privileged containers are admitted
echo "=== Verifying no privileged containers are present ==="
VERIFY_OUTPUT=$(kubectl get pods --all-namespaces -o json | \
jq -r 'if any(.items[]?.spec.containers[]?; .securityContext?.privileged == true)
then "PRIVILEGED_FOUND" else "NO_PRIVILEGED" end')
if [ "$VERIFY_OUTPUT" = "NO_PRIVILEGED" ]; then
echo "Verification passed: NO_PRIVILEGED"
exit 0
else
echo "Verification failed: PRIVILEGED_FOUND"
echo "There are still pods running with securityContext.privileged=true."
echo "Inspect them with:"
echo " kubectl get pods --all-namespaces -o json | \\"
echo " jq -r ''.items[] | select(any(.spec.containers[]?; .securityContext?.privileged == true)) | .metadata.namespace + \"/\" + .metadata.name'''"
exit 1
fi