Skip to main content

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

Manual Steps
  1. Identify namespaces that should host only non-privileged workloads (typically all user workload namespaces; exclude system namespaces like kube-system, kube-public, kube-node-lease if needed). On any machine with kubectl access:

    kubectl get ns
  2. For each target namespace, enforce the Restricted Pod Security Admission policy to block privileged containers. Replace NAMESPACE with the actual namespace name. On any machine with kubectl access:

    kubectl label --overwrite ns NAMESPACE pod-security.kubernetes.io/enforce=restricted
  3. (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
  4. Attempt to create a privileged pod in a Restricted namespace to confirm admission is blocked. On any machine with kubectl access, replace NAMESPACE as 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.

  5. 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
  6. 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:

  1. Identify namespaces with user workloads (example: team-a, team-b, prod-apps). Adjust the list below to your cluster.

  2. Enforce restricted Pod 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
  1. (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
  1. Verify labels are in place:
kubectl get ns --show-labels | grep pod-security.kubernetes.io
  1. 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

Additional Reading: