Skip to main content

Minimize The Admission Privileged Container

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 AKS
  • CIS Critical Security Controls v8
  • 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. List existing Pod Security labels on all namespaces
    Run on: any machine with kubectl access

    kubectl get ns --show-labels

    Identify namespaces lacking pod-security.kubernetes.io/enforce, pod-security.kubernetes.io/warn, or pod-security.kubernetes.io/audit labels, or where these are set weaker than desired (e.g., not restricted or baseline).

  2. Identify namespaces that must be excluded from strict enforcement
    Run on: any machine with kubectl access

    kubectl get ns

    From the list, note system/infra namespaces (e.g., kube-system, gatekeeper-system, azure-arc, azure-extensions-usage-system, and any vendor/operator namespaces). Plan to either:

    • Leave them without enforce=restricted, or
    • Use warn/audit levels first instead of strict enforcement.
  3. Apply restricted enforcement to selected application namespaces
    For each non-excluded application namespace you want to lock down:
    Run on: any machine with kubectl access

    kubectl label --overwrite ns <NAMESPACE> pod-security.kubernetes.io/enforce=restricted

    Replace <NAMESPACE> with the actual name (e.g., prod-app, staging-app). This will block future admission of privileged containers and other disallowed settings under the Restricted profile.

  4. Set a cluster-wide baseline warning level for all namespaces
    Run on: any machine with kubectl access

    kubectl label --overwrite ns --all pod-security.kubernetes.io/warn=baseline

    This does not block workloads, but it will surface warnings when workloads violate the Baseline policy, helping you detect remaining privileged or near-privileged configurations.

  5. Review existing workloads that might be using privileged containers
    Run on: any machine with kubectl access

    kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{" "}{.spec.containers[*].name}{" "}{.spec.containers[*].securityContext.privileged}{"\n"}{end}' \
    | grep ' true' || echo "No containers with privileged=true found"

    For any pods reported with privileged true, review their necessity with the workload owners and plan remediation (e.g., remove securityContext.privileged: true or migrate to capabilities/hostPath alternatives).

  6. Verify PSA labels and re-check after changes
    Run on: any machine with kubectl access

    • Verify namespace labels:
      kubectl get ns --show-labels
    • If desired, attempt to deploy a test privileged pod into a restricted namespace to confirm admission is blocked (expect failure due to enforce=restricted).
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

Problem indication:

  • Namespaces with an empty value in both enforce and warn columns have no PSA policy configured.
  • Namespaces where enforce is not restricted (e.g., empty, baseline, or another value) are not enforcing the strict policy that blocks privileged containers.
  • Namespaces where only warn is set (and not enforce) rely only on warnings, not enforcement.
# 2) Show full labels for a specific namespace (replace <namespace>)
kubectl get ns <namespace> --show-labels

Problem indication:

  • Missing pod-security.kubernetes.io/enforce=restricted on namespaces where you expect strict blocking of privileged containers.
  • Absence of any pod-security.kubernetes.io/* labels on application namespaces suggests privileged pods may be admitted unless controlled elsewhere.
# 3) Identify namespaces that are likely "system" or exempt candidates
kubectl get ns | egrep 'kube-system|gatekeeper-system|azure-arc|azure-extensions-usage-system'

Usage:

  • These namespaces are commonly excluded from strict enforcement. Their presence does not indicate a problem by itself; they need human review to decide whether exemption is appropriate.
# 4) Spot-check for existing privileged pods (read-only review)
kubectl get pods -A -o jsonpath='{range .items[?(@.spec.containers[*].securityContext.privileged==true)]}{.metadata.namespace}{"\t"}{.metadata.name}{"\n"}{end}'

Problem indication:

  • Any output here means there are currently pods running with securityContext.privileged=true.
  • If these pods are in namespaces without enforce=restricted, that namespace is a candidate for stricter PSA configuration (subject to application needs and exemptions).
# 5) Verify after you adjust labels (re-run relevant commands)
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

Verification:

  • Namespaces where you decided to enforce restricted PSA should now show restricted under the enforce column.
  • System/exempt namespaces should match your intended policy decision (e.g., no enforce=restricted if you chose to exempt them).
Automation
#!/usr/bin/env bash
# Report namespaces that do NOT have PSA labels enforcing restricted or warning on baseline.
# Run on: any machine with kubectl access and correct KUBECONFIG.

set -euo pipefail

echo "=== Pod Security Admission (PSA) labels per namespace ==="
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}' \
| awk 'BEGIN{print "NAMESPACE\tENFORCE\tWARN"}1' | column -t

echo
echo "=== Namespaces WITHOUT enforce=restricted ==="
kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.labels.pod-security\.kubernetes\.io/enforce}{"\n"}{end}' \
| awk '$2 != "restricted" {print $1}' | sort

echo
echo "=== Namespaces WITHOUT warn=baseline ==="
kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.labels.pod-security\.kubernetes\.io/warn}{"\n"}{end}' \
| awk '$2 != "baseline" {print $1}' | sort

echo
echo "=== Namespaces with pods currently running privileged containers ==="
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| {ns:.metadata.namespace, name:.metadata.name, c:.spec.containers}
| select(.c != null)
| .c[]
| select(.securityContext.privileged == true)
| "\(.name)\t\(.securityContext.privileged)\t\(. | tostring)" as $cinfo
| "\(.ns)\t\(.name)\t" + $cinfo
' 2>/dev/null \
| awk 'BEGIN{print "NAMESPACE\tPOD\tCONTAINER\tPRIVILEGED\tCONTAINER_SPEC"}1' | column -t

How to interpret the output:

  • In the first table, any namespace with an empty ENFORCE field is missing pod-security.kubernetes.io/enforce=restricted. These namespaces are not enforcing the restricted policy and may admit privileged containers.
  • In the “Namespaces WITHOUT enforce=restricted” list, every namespace shown is a candidate to tighten (unless it is intentionally excluded, e.g. kube-system, gatekeeper-system, azure-arc, azure-extensions-usage-system or other infrastructure namespaces you have decided to exempt).
  • In the “Namespaces WITHOUT warn=baseline” list, namespaces shown do not even have a baseline warning; these are higher priority for review.
  • In the final section, any line indicates a pod that is currently running at least one privileged container; these namespaces and workloads should be reviewed and either:
    • moved to exempt namespaces where privileged is explicitly allowed and justified, or
    • refactored to run without securityContext.privileged: true.

Additional Reading: