Skip to main content

Minimize The Admission Of Privileged Containers

More Info:

Privileged containers run with elevated host capabilities and can compromise the underlying node. Use Pod Security Admission policies to restrict their admission.

Risk Level

Critical

Address

Security

Compliance Standards

  • CIS EKS

Triage and Remediation

Remediation

Manual Steps
  1. Identify namespaces with user workloads
    Run on: any machine with kubectl access

    kubectl get ns

    Decide which namespaces are user / application namespaces (exclude system namespaces like kube-system, kube-public, kube-node-lease, etc., unless you explicitly want PSA there).

  2. Enforce restricted Pod Security Admission on each user namespace
    Run on: any machine with kubectl access
    For each chosen namespace, run (replace MY-NAMESPACE with the actual name):

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

    This blocks creation of pods that request privileged containers in that namespace.

  3. Optionally add warning-only policy cluster‑wide
    Run on: any machine with kubectl access
    This does not block pods, but surfaces warnings where they violate baseline:

    kubectl label --overwrite ns --all pod-security.kubernetes.io/warn=baseline
  4. Handle existing privileged pods (if any) by policy decision
    Run on: any machine with kubectl access
    List privileged pods:

    kubectl get pods --all-namespaces -o json | \
    jq -r '.items[] | select(any(.spec.containers[]?; .securityContext?.privileged == true)) |
    "\(.metadata.namespace) \(.metadata.name)"'

    For each listed pod:

    • Decide if it is truly required; if not, delete it:
      kubectl delete pod POD_NAME -n POD_NAMESPACE
    • If required, plan a safer replacement (e.g., remove privileged: true and use more granular capabilities) and update the Deployment/DaemonSet/StatefulSet manifest that owns it.
  5. Recreate workloads with compliant securityContext
    Run on: any machine with kubectl access
    For each owning controller (Deployment/DaemonSet/StatefulSet, etc.) that used privileged containers, edit its manifest to remove privileged: true, then apply:

    kubectl apply -f UPDATED-MANIFEST.yaml

    The controller will recreate pods that comply with the restricted policy.

  6. Verification
    Run 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'

    Confirm the output is:

    NO_PRIVILEGED
Using kubectl
# 1) Identify namespaces that host user workloads (adjust the label selector as needed)
# Run on: any machine with kubectl access
kubectl get ns --show-labels

# 2) Enforce RESTRICTED Pod Security Admission on specific user-workload namespaces
# Replace these namespace names with the actual ones in your cluster
# Run on: any machine with kubectl access
kubectl label --overwrite ns production \
pod-security.kubernetes.io/enforce=restricted

kubectl label --overwrite ns staging \
pod-security.kubernetes.io/enforce=restricted

kubectl label --overwrite ns development \
pod-security.kubernetes.io/enforce=restricted

# (Optional) For all current and future namespaces where you are comfortable
# with at least baseline restrictions, set a cluster-wide warning level
kubectl label --overwrite ns --all \
pod-security.kubernetes.io/warn=baseline

# 3) Verify: no privileged containers are currently running
# Run 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'
Automation
#!/usr/bin/env bash
#
# Enforce Pod Security Admission (PSA) restricted policy on all user namespaces
# and verify that no privileged containers are running.
#
# Requirements:
# - Run on any machine with kubectl access to the cluster.
# - kubectl and jq must be installed and configured.
#
# Idempotent: safe to re-run; labels are applied with --overwrite.

set -euo pipefail

########################
# Configuration
########################

# System / control-plane namespaces to EXCLUDE from "enforce=restricted".
# Adjust only if you knowingly run system components elsewhere.
EXCLUDE_NAMESPACES=(
"kube-system"
"kube-node-lease"
"kube-public"
"kube-fed-system"
"kubernetes-dashboard"
"local-path-storage"
"tigera-operator"
"calico-system"
"cilium-system"
)

########################
# Helper Functions
########################

is_excluded_ns() {
local ns="$1"
for e in "${EXCLUDE_NAMESPACES[@]}"; do
if [[ "$ns" == "$e" ]]; then
return 0
fi
done
return 1
}

########################
# Step 1: Enforce "restricted" on user namespaces
########################

echo "[INFO] Applying pod-security.kubernetes.io/enforce=restricted to user namespaces..."

# Get all namespaces
ALL_NS=$(kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}')

for ns in $ALL_NS; do
if is_excluded_ns "$ns"; then
echo "[INFO] Skipping system namespace: $ns"
continue
fi

echo "[INFO] Labeling namespace '$ns' with enforce=restricted"
kubectl label --overwrite ns "$ns" pod-security.kubernetes.io/enforce=restricted=restricted
done

########################
# Step 2: Optionally warn baseline on all namespaces
########################

echo "[INFO] Ensuring pod-security.kubernetes.io/warn=baseline on all namespaces..."
kubectl label --overwrite ns --all pod-security.kubernetes.io/warn=baseline=baseline

########################
# Step 3: Verification
########################

echo "[INFO] Verifying that no privileged containers are currently running..."

RESULT=$(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 [[ "$RESULT" == "NO_PRIVILEGED" ]]; then
echo "[PASS] Verification succeeded: NO_PRIVILEGED"
exit 0
else
echo "[WARN] Verification found privileged containers: PRIVILEGED_FOUND"
echo " Review and remediate privileged pods before re-running this script."
exit 1
fi