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
Remediation
Manual Steps
-
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 -
For a single non-excluded namespace (example:
my-app), set the enforce level tobaseline(orrestrictedif you choose stricter):kubectl label namespace my-app pod-security.kubernetes.io/enforce=baseline --overwrite -
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)$'); dokubectl label namespace "$ns" pod-security.kubernetes.io/enforce=baseline --overwritedone -
If you prefer
restrictedfor specific namespaces (example:prod-app), override as needed:kubectl label namespace prod-app pod-security.kubernetes.io/enforce=restricted --overwrite -
(Optional) Review labels on a specific namespace to confirm:
kubectl get ns my-app -o jsonpath='{.metadata.labels}' -
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:
- Create a manifest to enforce Pod Security Admission (choose
baselineorrestrictedas appropriate). Example forbaseline:
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.
- 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
- 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'