Skip to main content

Minimize The Admission Of Privileged Containers

More Info:

Privileged containers effectively have root access to the host node. Pod Security Admission policies should restrict their admission across namespaces.

Risk Level

Critical

Address

Security

Compliance Standards

  • CIS AKS

Triage and Remediation

Remediation

Manual Steps
  1. List and review existing Pod Security Admission labels per namespace
    Run on any machine with kubectl access:

    kubectl get ns -L pod-security.kubernetes.io/enforce \
    -L pod-security.kubernetes.io/audit \
    -L pod-security.kubernetes.io/warn

    Identify application namespaces that either have no PSA labels or do not use restricted for enforce.

  2. Identify namespaces that must allow privileged workloads (exceptions)
    Still on any kubectl machine, list all namespaces and note system/infra ones that may legitimately need privileges (e.g. kube-system, gatekeeper-system, azure-arc, azure-extensions-usage-system, CNI/CSI/operator namespaces):

    kubectl get ns

    Build a short list of namespaces that should be exempt from strict restricted enforcement and will instead use baseline or only warn.

  3. Detect currently running privileged pods for risk assessment
    Check which pods are privileged or use host namespaces, per namespace, to understand current usage before tightening policy:

    kubectl get pods -A -o json | \
    jq -r '.items[] |
    . as $pod |
    .spec.containers[]? as $c |
    select(
    ($c.securityContext.privileged == true)
    or ($c.securityContext.allowPrivilegeEscalation == true)
    or ($c.securityContext.runAsUser == 0)
    or ($pod.spec.hostPID == true)
    or ($pod.spec.hostNetwork == true)
    or ($pod.spec.hostIPC == true)
    ) |
    "\($pod.metadata.namespace) \($pod.metadata.name) \($c.name)"'

    For each listed pod, decide whether it is strictly required and in which namespace it runs.

  4. Apply or tighten PSA enforcement on standard application namespaces
    For each application namespace where privileged containers are not required, enforce restricted per the remediation:

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

    Optionally, to ensure at least baseline warnings everywhere while you roll out restricted gradually:

    kubectl label --overwrite ns --all pod-security.kubernetes.io/warn=baseline
  5. Adjust or confirm labels for exception namespaces
    For each namespace identified in step 2 that must allow some privileged behavior, ensure it does NOT have enforce=restricted unless validated safe. You can either remove or relax labels as appropriate, for example:

    # Example: relax to baseline for an infra namespace
    kubectl label --overwrite ns kube-system pod-security.kubernetes.io/enforce=baseline

    Re-review privileged pods from step 3 in these namespaces to confirm they are intentional and documented.

  6. Verify the final configuration and admission behavior
    a) Confirm labels:

    kubectl get ns -L pod-security.kubernetes.io/enforce \
    -L pod-security.kubernetes.io/audit \
    -L pod-security.kubernetes.io/warn

    b) (Optional but recommended) Attempt to create a clearly privileged test pod in a restricted namespace and ensure it is rejected; for example:

    kubectl -n <RESTRICTED_NAMESPACE> apply -f - << 'EOF'
    apiVersion: v1
    kind: Pod
    metadata:
    name: privileged-test
    spec:
    containers:
    - name: busybox
    image: busybox
    securityContext:
    privileged: true
    command: ["sh", "-c", "sleep 3600"]
    EOF

    Confirm that admission is denied by the Pod Security Admission controller, demonstrating that privileged pods are minimized as intended.

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

How to review

  • Problem indicators:
    • Empty or missing pod-security.kubernetes.io/enforce for regular (non-system) namespaces.
    • pod-security.kubernetes.io/enforce set to privileged or baseline where you expect restricted.
    • No pod-security.kubernetes.io/warn label on namespaces where you want a cluster-wide baseline/warn posture.

# 2) Show full labels for all namespaces for detailed inspection
# Run on: any machine with kubectl access

kubectl get ns --show-labels

How to review

  • Problem indicators:
    • Business / application namespaces without any pod-security.kubernetes.io/* labels.
    • PSA labels only on a few namespaces, implying many are unprotected.
    • Sensitive namespaces (e.g., production) not set to enforce=restricted.

# 3) Identify namespaces that allow or already run privileged pods
# (sample admission test using a dry-run privileged pod)
# Run on: any machine with kubectl access

for ns in $(kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}'); do
echo "=== Testing namespace: $ns ==="
kubectl apply -n "$ns" -f - --dry-run=server <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: privileged-test
spec:
containers:
- name: c
image: busybox
command: ["sh", "-c", "sleep 3600"]
securityContext:
privileged: true
restartPolicy: Never
EOF
echo
done

How to review

  • Problem indicators:
    • Namespaces where the dry-run succeeds (no PSA-related error): these currently admit privileged pods.
    • Namespaces where the dry-run fails specifically due to Pod Security Admission (forbidden/denied) are configured to block privileged pods, which is usually desired (except for intentionally exempt system namespaces).

# 4) Inspect existing pods that are privileged or host-level
# Run on: any machine with kubectl access

kubectl get pods -A -o jsonpath='
{range .items[*]}
{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}
{.spec.securityContext.runAsUser}{"\t"}
{range .spec.containers[*]}
{"container="}{.name}{": privileged="}{.securityContext.privileged}{" capAdd="}{.securityContext.capabilities.add}{" "}
{end}
{"\n"}
{end}' | column -t

How to review

  • Problem indicators:
    • Application namespaces (not kube-system or other intentionally privileged namespaces) where:
      • Any container shows privileged=true.
      • Unnecessary extra capabilities are added (e.g., SYS_ADMIN) that may require higher policies.
    • Pods relying on privileged mode instead of fine-grained securityContext settings.

# 5) Focus on non-system namespaces (where you usually want enforce=restricted)
# Run on: any machine with kubectl access

kubectl get ns -o jsonpath='{range .items[?(@.metadata.name!="kube-system" && @.metadata.name!="kube-public" && @.metadata.name!="kube-node-lease")]}{.metadata.name}{"\t"}{.metadata.labels.pod-security\.kubernetes\.io/enforce}{"\n"}{end}' \
| column -t

How to review

  • Problem indicators:
    • Empty or null enforce value in business / app namespaces.
    • Enforce set to anything weaker than your chosen standard (commonly restricted) for those namespaces.

These commands surface the current posture; based on your environment’s needs, you must decide which namespaces should be tightened (e.g., label with enforce=restricted) and which must remain exempt (e.g., kube-system, admission controllers), before making any changes.

Automation
#!/usr/bin/env bash
# Report namespaces and pods that may allow privileged containers,
# plus current Pod Security Admission (PSA) labels.

set -euo pipefail

echo "=== Pod Security Admission labels per namespace ==="
# Shows which namespaces have PSA labels set (or missing).
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 \
--no-headers | sort

cat <<'EOF'

Interpretation:
- ENFORCE empty or not 'restricted' on application namespaces = needs review.
- System namespaces (e.g., kube-system, gatekeeper-system, azure-arc, azure-extensions-usage-system)
may intentionally differ but should still be reviewed.

EOF

echo "=== Namespaces WITHOUT an enforce=restricted PSA label ==="
kubectl get ns \
-o jsonpath='{range .items[?(!@.metadata.labels.pod-security\.kubernetes\.io/enforce)]}{.metadata.name}{"\n"}{end}'

echo
echo "=== Namespaces with enforce label NOT set to 'restricted' ==="
kubectl get ns \
-o jsonpath='{range .items[?(@.metadata.labels.pod-security\.kubernetes\.io/enforce!=="restricted")]}{.metadata.name}{"\t"}{.metadata.labels.pod-security\.kubernetes\.io/enforce}{"\n"}{end}'

cat <<'EOF'

Interpretation:
- Any non-system namespace listed above is a potential problem:
it is not enforcing the 'restricted' PSA level and may admit privileged pods.

EOF

echo "=== Pods that request privileged=true (across all namespaces) ==="
# Lists any container or initContainer with securityContext.privileged=true.
kubectl get pods --all-namespaces -o json | \
jq -r '
[
.items[]
| {
ns: .metadata.namespace,
pod: .metadata.name,
containers: (
(.spec.containers // []) + (.spec.initContainers // [])
| map({name, sc: .securityContext})[]
)
}
| select(.containers.sc.privileged == true)
| "\(.ns)\t\(.pod)\t\(.containers.name)\tprivileged=true"
] | unique[]' 2>/dev/null || echo "jq not available; skipping privileged container scan."

cat <<'EOF'

Interpretation:
- Any line here shows a pod/container that is explicitly privileged.
- If such pods exist in namespaces that are *not* exempt system namespaces,
this is typically a policy violation.

EOF

echo "=== Pods that can escalate capabilities (allowPrivilegeEscalation=true) ==="
kubectl get pods --all-namespaces -o json | \
jq -r '
[
.items[]
| {
ns: .metadata.namespace,
pod: .metadata.name,
containers: (
(.spec.containers // []) + (.spec.initContainers // [])
| map({name, sc: .securityContext})[]
)
}
| select(.containers.sc.allowPrivilegeEscalation == true)
| "\(.ns)\t\(.pod)\t\(.containers.name)\tallowPrivilegeEscalation=true"
] | unique[]' 2>/dev/null || echo "jq not available; skipping allowPrivilegeEscalation scan."

cat <<'EOF'

Interpretation:
- Not strictly 'privileged=true', but often disallowed under stricter policies.
- Use this as additional context when reviewing namespaces and workloads.

EOF

What output indicates a problem

Run on any machine with kubectl access and jq installed.

Problem indicators you should manually review and decide on:

  1. Namespaces:

    • Appearing under:
      • “Namespaces WITHOUT an enforce=restricted PSA label”
      • or “Namespaces with enforce label NOT set to 'restricted'”
    • And they are not intentionally exempt system namespaces.
    • These namespaces may admit privileged containers and should be considered for:
      kubectl label --overwrite ns <NAMESPACE> pod-security.kubernetes.io/enforce=restricted
  2. Pods:

    • Any lines under:
      • “Pods that request privileged=true (across all namespaces)”
    • Especially in non-exempt namespaces.
    • These workloads either need:
      • design justification and documented exception, or
      • remediation to run without privileged: true under a restricted policy.

This script only reports the state; you must decide which namespaces/pods are acceptable exceptions and then apply labels or change manifests accordingly.