Skip to main content

Minimize The Admission Of Privileged Containers

More Info:

Privileged containers can access host devices and escape isolation. Enforce Pod Security Admission policies in each namespace with user workloads to restrict privileged container admission.

Risk Level

Critical

Address

Security

Compliance Standards

  • CIS OKE

Triage and Remediation

Remediation

Manual Steps
  1. List all namespaces and identify user-workload namespaces

    • Run on: any machine with kubectl access
    kubectl get ns --show-labels
    • From the output, determine which namespaces contain user workloads (excluding system/control namespaces such as kube-system, kube-public, kube-node-lease, kube-admin, and any provider-specific system namespaces).
  2. Review existing Pod Security Admission labels on user-workload namespaces

    • Run on: any machine with kubectl access
    kubectl get ns <USER_NAMESPACE> -o jsonpath='{.metadata.labels}' | jq
    • For each user namespace, check whether pod-security.kubernetes.io/enforce is present and whether its value is at least restricted for namespaces where privileged workloads must not be allowed.
  3. Identify current privileged pod usage and decide on required policy level

    • Run on: any machine with kubectl access
    kubectl get pods -A -o jsonpath='{range .items[?(@.spec.containers[*].securityContext.privileged==true)]}{.metadata.namespace}{"\t"}{.metadata.name}{"\n"}{end}'
    • For each user namespace, decide if privileged containers are truly required. If privileged pods are in use and needed, you may need to keep a less strict policy (e.g., baseline or no enforce label yet) or redesign those workloads. If they are not required, plan to enforce restricted.
  4. Apply or adjust Pod Security Admission labels per namespace

    • Run on: any machine with kubectl access
    • For namespaces where privileged containers must be prevented:
      kubectl label --overwrite ns <USER_NAMESPACE> pod-security.kubernetes.io/enforce=restricted
    • Optionally, to introduce a gentler rollout by warning before enforcing, you can use:
      kubectl label --overwrite ns <USER_NAMESPACE> pod-security.kubernetes.io/warn=restricted
  5. Optionally set default warnings cluster-wide, then tighten per-namespace

    • Run on: any machine with kubectl access
    kubectl label --overwrite ns --all pod-security.kubernetes.io/warn=baseline
    • Then override critical user namespaces individually with pod-security.kubernetes.io/enforce=restricted as in step 4, once you are confident workloads comply.
  6. Verify namespaces are correctly labeled and privileged pods are blocked

    • Run on: any machine with kubectl access
    kubectl get ns -L pod-security.kubernetes.io/enforce -L pod-security.kubernetes.io/warn
    • In a namespace where you set pod-security.kubernetes.io/enforce=restricted, attempt to create a privileged pod and confirm it is rejected:
    kubectl run privileged-test \
    --image=alpine \
    --restart=Never \
    --overrides='{"spec":{"containers":[{"name":"c","image":"alpine","securityContext":{"privileged":true}}]}}' \
    -n <USER_NAMESPACE>
    • Ensure the API server denies this pod, confirming privileged containers are minimized in that namespace.
Using kubectl
# 1) List all namespaces and their Pod Security Admission labels
# Run on: any machine with kubectl access
kubectl get ns \
-o custom-columns='NAME:.metadata.name,ENFORCE:.metadata.labels.pod-security\.kubernetes\.io/enforce,WARN:.metadata.labels.pod-security\.kubernetes\.io/warn,AUDIT:.metadata.labels.pod-security\.kubernetes\.io/audit' \
--sort-by=.metadata.name

Problem indication:

  • ENFORCE is empty (<none>) for namespaces that host user workloads.
  • ENFORCE is set to privileged in any user-workload namespace.
  • There is no WARN/AUDIT configuration where you expect at least visibility of violations.

Identify user workload namespaces (exclude system/control-plane):

# 2) List non-system namespaces (candidate user namespaces)
kubectl get ns \
--no-headers \
| awk '!/^(kube-system|kube-public|kube-node-lease|default)$/ {print $1}'

Problem indication:

  • Any namespace returned here that, when checked in step 1, has no pod-security.kubernetes.io/enforce label, or has it set to privileged, needs review.

Drill into a single namespace’s PSA config:

# 3) Inspect labels on a specific namespace
NAMESPACE=example-namespace
kubectl get ns "$NAMESPACE" --show-labels

Problem indication:

  • Missing pod-security.kubernetes.io/enforce label, or value not aligned with your policy (e.g., not restricted for sensitive/user-facing workloads).
  • Conflicting or unexpected combinations of enforce, warn, and audit labels.

Review currently admitted privileged workloads:

# 4) List pods that request privileged containers cluster-wide
kubectl get pods -A -o json \
| jq -r '
.items[]
| {ns: .metadata.namespace, pod: .metadata.name, containers: [.spec.containers[], (.spec.initContainers // [])[]]}
| .ns as $ns
| .pod as $pod
| .containers[]
| select(.securityContext.privileged == true)
| "\($ns) \($pod) \(.name) privileged=true"
'

Problem indication:

  • Any line in the output shows a privileged container. For those namespaces:
    • Check whether PSA enforce is absent or too permissive (from steps 1–3).
    • Decide if those privileged pods are truly justified; if not, the namespace’s PSA policy is likely too weak.
Automation
#!/usr/bin/env bash
set -euo pipefail

# This script runs on: any machine with kubectl access

echo "=== Pod Security Admission (PSA) status per namespace ==="
echo

# Show all namespaces with their PSA labels
echo "Current PSA labels on all namespaces:"
kubectl get ns -o custom-columns=NAME:.metadata.name,ENFORCE:.metadata.labels.pod-security\\.kubernetes\\.io/enforce,ENFORCE-VERSION:.metadata.labels.pod-security\\.kubernetes\\.io/enforce-version,WARN:.metadata.labels.pod-security\\.kubernetes\\.io/warn,AUDIT:.metadata.labels.pod-security\\.kubernetes\\.io/audit --sort-by=.metadata.name
echo

# Highlight namespaces that likely contain user workloads and lack a strong enforce policy
# Heuristics: exclude kube-system, kube-public, kube-node-lease, default, and any beginning with "kube-"
echo "Namespaces that MAY contain user workloads and do NOT enforce 'restricted':"
kubectl get ns -o json \
| jq -r '
.items[]
| select(.metadata.name
| test("^kube-") | not
and . != "kube-system"
and . != "kube-public"
and . != "kube-node-lease")
| {
name: .metadata.name,
enforce: (.metadata.labels["pod-security.kubernetes.io/enforce"] // "NONE")
}
| select(.enforce != "restricted")
| "\(.name)\tENFORCE=\(.enforce)"
' | sort || true
echo

# Report any existing pods that are privileged
echo "=== Pods currently running with privileged containers (cluster-wide) ==="
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| . as $pod
| [
$pod.metadata.namespace,
$pod.metadata.name,
(
[
($pod.spec.containers[]?, $pod.spec.initContainers[]?)
| select(.securityContext.privileged == true)
| .name
] | unique | join(",")
)
]
| select(.[2] != "")
| @tsv
' | awk 'BEGIN { OFS="\t"; print "NAMESPACE","POD","PRIVILEGED_CONTAINERS" } { print }' || true
echo

cat <<'EOF'
How to interpret results:

1) Namespace PSA label table:
- Problem indicators:
- ENFORCE is empty (no pod-security.kubernetes.io/enforce label).
- ENFORCE is set to "privileged" or "baseline" instead of "restricted"
for namespaces where you want to minimize privileged containers.

2) "Namespaces that MAY contain user workloads and do NOT enforce 'restricted'":
- This list is a REVIEW QUEUE, not an automatic violation:
- Each listed namespace may host user workloads but does not have
pod-security.kubernetes.io/enforce=restricted.
- For each, decide if enforcing 'restricted' is appropriate
(consider legacy workloads, operational needs, and migration plans).

3) "Pods currently running with privileged containers":
- Any line here indicates a pod with at least one container
having securityContext.privileged=true.
- For each such pod, review:
- Whether privilege is strictly required.
- Whether it’s in a namespace that should enforce 'restricted'.
- Whether it can be refactored to use less-privileged mechanisms.
EOF