Skip to main content

Namespaces Should Enforce Pod Security Admission Baseline

More Info:

Verifies each namespace is labeled with pod-security.kubernetes.io/enforce set to baseline or restricted so the built-in Pod Security Admission controller rejects unsafe pods.

Risk Level

High

Address

Security

Compliance Standards

  • Cloudanix Best Practice

Triage and Remediation

Remediation

Manual Steps
  1. On any machine with kubectl access, list all namespaces and identify ones missing an enforce label or with an incorrect value:

    kubectl get ns --show-labels
  2. For a single non-excluded namespace (example: my-app), set the enforce level to baseline (or restricted if you choose stricter):

    kubectl label namespace my-app pod-security.kubernetes.io/enforce=baseline --overwrite
  3. To label all non-excluded namespaces at once with baseline, run:

    for ns in $(kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' \
    | grep -Ev '^(kube-system|kube-public|kube-node-lease)$'); do
    kubectl label namespace "$ns" pod-security.kubernetes.io/enforce=baseline --overwrite
    done
  4. If you prefer restricted for specific namespaces (example: prod-app), override as needed:

    kubectl label namespace prod-app pod-security.kubernetes.io/enforce=restricted --overwrite
  5. (Optional) Review labels on a specific namespace to confirm:

    kubectl get ns my-app -o jsonpath='{.metadata.labels}'
  6. Verification (on any machine with kubectl access):

    kubectl get namespaces -o json | jq -r '
    [ .items[]
    | select(.metadata.name as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
    | .metadata as $m
    | (($m.labels // {}) | to_entries | map("\(.key):\(.value)") | join(",")) as $labels
    | (($m.labels // {})["pod-security.kubernetes.io/enforce"] // "") as $lvl
    | "kind=Namespace name=\($m.name) uid=\($m.uid) apiVersion=v1"
    + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
    + (if $labels == "" then "" else " labels=\($labels)" end)
    + " enforce=\(if $lvl == "" then "none" else $lvl end)"
    + " is_compliant=\(if ($lvl == "baseline" or $lvl == "restricted") then "true" else "false" end)"
    ] as $rows
    | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
Using kubectl

On any machine with kubectl access to the cluster:

  1. Create a manifest to enforce Pod Security Admission (choose baseline or restricted as appropriate). Example for baseline:
cat > enforce-psa-namespaces.yaml << 'EOF'
apiVersion: v1
kind: Namespace
metadata:
name: default
labels:
pod-security.kubernetes.io/enforce: baseline
---
apiVersion: v1
kind: Namespace
metadata:
name: my-apps
labels:
pod-security.kubernetes.io/enforce: baseline
EOF

Edit the file to include all target namespaces and the desired level (baseline or restricted). Do not include kube-system, kube-public, or kube-node-lease unless you have explicitly decided to.

  1. Apply the labels declaratively:
kubectl apply -f enforce-psa-namespaces.yaml

If you prefer imperative labeling for a few namespaces, you can run (example for restricted):

kubectl label namespace default pod-security.kubernetes.io/enforce=restricted --overwrite
kubectl label namespace my-apps pod-security.kubernetes.io/enforce=restricted --overwrite
  1. Verification (same logic as the audit):
kubectl get namespaces -o json | jq -r '
[ .items[]
| select(.metadata.name as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
| .metadata as $m
| (($m.labels // {}) | to_entries | map("\(.key):\(.value)") | join(",")) as $labels
| (($m.labels // {})["pod-security.kubernetes.io/enforce"] // "") as $lvl
| "kind=Namespace name=\($m.name) uid=\($m.uid) apiVersion=v1"
+ (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
+ (if $labels == "" then "" else " labels=\($labels)" end)
+ " enforce=\(if $lvl == "" then "none" else $lvl end)"
+ " is_compliant=\(if ($lvl == "baseline" or $lvl == "restricted") then "true" else "false" end)"
] as $rows
| if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
Automation
#!/usr/bin/env bash
set -euo pipefail

# PURPOSE:
# Ensure every non-system namespace has
# pod-security.kubernetes.io/enforce set to at least "baseline"
# (leaves "restricted" as-is, does not touch excluded namespaces).
#
# REQUIREMENTS:
# - Run on any machine with kubectl access and current context set.
# - jq must be installed.

# 1) Identify target namespaces (exclude core system ones)
echo "[INFO] Discovering namespaces to label..."
mapfile -t TARGET_NAMESPACES < <(
kubectl get namespaces -o json | jq -r '
.items[]
| select(.metadata.name as $n
| ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
| .metadata.name'
)

if [ "${#TARGET_NAMESPACES[@]}" -eq 0 ]; then
echo "[INFO] No non-system namespaces found. Nothing to do."
exit 0
fi

echo "[INFO] Namespaces considered for enforcement:"
printf ' - %s\n' "${TARGET_NAMESPACES[@]}"

# 2) Apply/ensure enforce=baseline where needed
for ns in "${TARGET_NAMESPACES[@]}"; do
current_level="$(
kubectl get namespace "$ns" -o json \
| jq -r '.metadata.labels["pod-security.kubernetes.io/enforce"] // ""'
)"

case "$current_level" in
restricted)
echo "[SKIP] $ns already at 'restricted' (stricter than baseline)."
;;
baseline)
echo "[OK] $ns already enforced at 'baseline'."
;;
"")
echo "[FIX] Setting enforce=baseline on namespace: $ns"
kubectl label namespace "$ns" \
pod-security.kubernetes.io/enforce=baseline \
--overwrite
;;
*)
echo "[INFO] Namespace $ns currently has enforce='$current_level'."
echo "[INFO] Leaving as-is to avoid downgrading/overriding custom policy."
;;
esac
done

# 3) Verification (adapted from audit command)
echo
echo "[VERIFY] Current Pod Security Admission enforcement per namespace:"
kubectl get namespaces -o json | jq -r '
[ .items[]
| select(.metadata.name as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
| .metadata as $m
| (($m.labels // {}) | to_entries | map("\(.key):\(.value)") | join(",")) as $labels
| (($m.labels // {})["pod-security.kubernetes.io/enforce"] // "") as $lvl
| "kind=Namespace name=\($m.name) uid=\($m.uid) apiVersion=v1"
+ (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
+ (if $labels == "" then "" else " labels=\($labels)" end)
+ " enforce=\(if $lvl == "" then "none" else $lvl end)"
+ " is_compliant=\(if ($lvl == "baseline" or $lvl == "restricted") then "true" else "false" end)"
] as $rows
| if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'