Ensure Pod Security Policy Is Enabled And Set As Appropriate
More Info:
Pod Security Policy Should Be Used To Prevent Privileged Containers Where Possible And Enforce Namespace And Workload Configurations.
Risk Level
Low
Address
Security
Compliance Standards
- CIS GKE
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
Identify clusters and current PSP setting
- On any machine with
gcloudconfigured for your GCP project, list clusters and check whether PSP is enabled:gcloud container clusters list --format="table(name,location,releaseChannel.channel)"gcloud container clusters describe CLUSTER_NAME --zone ZONE \--format="value(podSecurityPolicyConfig.enabled)" - If the value is empty or
false, PSP is not enabled on that cluster.
- On any machine with
-
Review current use of privileged features in workloads
- On any machine with
gcloudandkubectlaccess, inspect workloads that might require elevated privileges:kubectl get pods --all-namespaces -o json \| jq '.items[]| {ns:.metadata.namespace, name:.metadata.name,privileged:(.spec.containers[]?.securityContext.privileged // false),hostPID:(.spec.hostPID // false),hostNetwork:(.spec.hostNetwork // false),hostIPC:(.spec.hostIPC // false)}' \| uniq - Note namespaces and workloads that rely on privileged, hostPID, hostNetwork, hostIPC, or hostPath volumes; these will need either exceptions or refactoring before strict policies are enforced.
- On any machine with
-
Decide PSP (or modern equivalent) strategy for the cluster
- For clusters running a GKE version that still supports PodSecurityPolicy and where you want to enforce it at the control-plane level, plan PSPs that:
- Deny privileged containers and host namespaces by default.
- Allow only specific system namespaces (for example,
kube-system) or known DaemonSets to use required privileges.
- For newer clusters or where PSP is deprecated/removed, decide whether to instead use the built‑in Pod Security Admission (
pod-security.kubernetes.io/*labels on namespaces) or a policy engine such as GKE Policy Controller (OPA/Gatekeeper).
- For clusters running a GKE version that still supports PodSecurityPolicy and where you want to enforce it at the control-plane level, plan PSPs that:
-
Enable or adjust Pod Security / policy enforcement at the control-plane
- If the cluster supports PSP and you decide to use it, enable PSP via the control-plane configuration from any machine with
gcloudaccess:gcloud beta container clusters update CLUSTER_NAME \--zone ZONE \--enable-pod-security-policy - If PSP cannot be enabled (for example, because it is not supported in your GKE version), configure an alternative:
- Namespace Pod Security Admission levels:
kubectl label namespace NAMESPACE \pod-security.kubernetes.io/enforce=baseline \pod-security.kubernetes.io/enforce-version=latest
- Or enable and configure GKE Policy Controller via the GKE console or
gcloud alpha container hub config-managementcommands, according to your organization’s policy.
- Namespace Pod Security Admission levels:
- If the cluster supports PSP and you decide to use it, enable PSP via the control-plane configuration from any machine with
-
Implement and test policy scope to avoid disruption
- Begin with non-production namespaces:
- Apply restrictive settings (PSP or Pod Security Admission labels / Policy Controller constraints).
- Attempt to deploy workloads that should be allowed and disallowed, and confirm behavior matches expectations.
- For workloads that legitimately need higher privileges, design narrowly scoped exceptions (dedicated PSPs, less restrictive namespace labels, or specific policy constraints) and validate those workloads can still run.
- Begin with non-production namespaces:
-
Verify and document the final configuration
- Confirm PSP is enabled at the cluster level (if applicable):
gcloud container clusters describe CLUSTER_NAME --zone ZONE \--format="value(podSecurityPolicyConfig.enabled)"
- List active Pod Security Policies (if in use):
kubectl get psp
- For Pod Security Admission, verify namespace labels:
kubectl get ns --show-labels
- For Policy Controller, list constraint templates and constraints:
kubectl get constrainttemplates --all-namespaceskubectl get constraints --all-namespaces
- Record which mechanism is in use, which namespaces are protected, and any approved exceptions for future audits.
- Confirm PSP is enabled at the cluster level (if applicable):
Using kubectl
kubectl cannot enable or configure Pod Security Policy because this setting is controlled at the GKE cluster (managed control plane) level via gcloud/console/IaC. To remediate, follow the guidance in the Manual Steps section, which covers enabling Pod Security Policy through the cloud provider configuration.
Automation
#!/usr/bin/env bash
#
# Audit Pod Security Policy (PSP) usage and risk indicators in a GKE cluster.
# Runs read-only checks using kubectl.
#
# Requirements:
# - Run on any machine with kubectl access and context set to the target cluster.
# - kubectl must be authorized with cluster-admin or equivalent read access.
set -euo pipefail
echo "=== 1) CLUSTER-LEVEL INDICATORS (GKE FEATURES) ==="
echo
echo "NOTE: Enabling/disabling Pod Security Policy itself is done via gcloud, not kubectl."
echo " This script only inspects PSP objects and workload risk indicators."
echo
echo "--- a) Check for PodSecurityPolicy resources ---"
kubectl get podsecuritypolicies.policy 2>/dev/null || \
kubectl get psp 2>/dev/null || \
echo "No PodSecurityPolicy resources found (or PSP API disabled)."
echo
echo "Interpretation:"
echo " - If no PSPs are listed but the cluster is configured to use PSPs, pods may be blocked"
echo " from scheduling unless other admission controls are in place."
echo " - If the cluster is not configured to use PSPs (gcloud --enable-pod-security-policy not set),"
echo " then this benchmark finding is NOT satisfied: PSP is not enabled at the control plane."
echo
echo "--- b) List PSPs with key security-relevant settings ---"
# This surfaces PSPs that allow privileged or broad host access
kubectl get podsecuritypolicies.policy -o custom-columns=NAME:.metadata.name,PRIV:.spec.privileged,HOSTPID:.spec.hostPID,HOSTIPC:.spec.hostIPC,HOSTNET:.spec.hostNetwork,ALLOW_PRIV_ESC:.spec.allowPrivilegeEscalation,SELINUX:.spec.seLinux.rule,RUNASUSER:.spec.runAsUser.rule,FSGROUP:.spec.fsGroup.rule,SUPPGRP:.spec.supplementalGroups.rule 2>/dev/null || true
echo
echo "Problem indicators here include:"
echo " - PRIV=true : PSP allows privileged containers."
echo " - HOSTPID/HOSTIPC/HOSTNET=true : PSP allows host namespace sharing."
echo " - ALLOW_PRIV_ESC=true or empty : PSP allows privilege escalation."
echo " - SELINUX/RUNASUSER/FSGROUP/SUPPGRP = RunAsAny : no restriction on IDs/labels."
echo
echo "=== 2) RBAC BINDINGS TO PSPs (WHO CAN USE WHICH PSP) ==="
echo
echo "--- a) ClusterRoleBindings referencing use of PSPs ---"
kubectl get clusterrolebindings -o json | \
jq -r '
.items[]
| select(.roleRef.kind=="ClusterRole")
| . as $crb
| $crb
| .metadata.name as $crbName
| $crb
| .roleRef.name as $roleName
| "CRB:\($crbName) -> ClusterRole:\($roleName)"
' 2>/dev/null || echo "jq not available; skipping detailed RBAC inspection."
echo
echo "--- b) ClusterRoles that grant use of PSPs ---"
kubectl get clusterroles -o json 2>/dev/null | \
jq -r '
.items[]
| . as $cr
| select(
(.rules[]? | .resources[]? == "podsecuritypolicies" and .verbs[]? == "use")
)
| "ClusterRole:\(.metadata.name)"
' 2>/dev/null || true
echo
echo "Review guidance:"
echo " - Any ClusterRole with rules on resource=podsecuritypolicies, verb=use grants PSP usage."
echo " - Check which subjects (users/groups/serviceaccounts) are bound to those ClusterRoles."
echo " - A problem is indicated if broad groups (e.g., system:authenticated, system:masters, or"
echo " large app teams) are bound to overly-permissive PSPs."
echo
echo "--- c) Show which subjects can use each PSP (approximate) ---"
echo "This uses RBAC info to approximate PSP usage:"
kubectl get clusterroles -o json 2>/dev/null | \
jq -r '
.items[]
| . as $cr
| select(
(.rules[]? | .resources[]? == "podsecuritypolicies" and .verbs[]? == "use")
)
| "ClusterRole:\($cr.metadata.name)"
' 2>/dev/null | while read -r role; do
rname="${role#ClusterRole:}"
echo
echo "ClusterRole: ${rname}"
echo " Bound via ClusterRoleBinding(s):"
kubectl get clusterrolebindings -o json 2>/dev/null | \
jq -r --arg ROLE "$rname" '
.items[]
| select(.roleRef.kind=="ClusterRole" and .roleRef.name==$ROLE)
| " CRB:\(.metadata.name) subjects: " +
( .subjects // [] | map(.kind + "/" + .name) | join(", ") )
' || true
done
echo
echo "Problem indicators in this section:"
echo " - ClusterRoles that allow use of PSPs with PRIV=true or broad host access,"
echo " bound to wide subjects like system:authenticated."
echo " - Service accounts used by less-trusted workloads bound to very permissive PSPs."
echo
echo "=== 3) WORKLOAD RISK SAMPLING (PODS THAT WOULD REQUIRE PERMISSIVE PSPs) ==="
echo
echo "--- a) List pods running privileged or with host namespaces ---"
kubectl get pods --all-namespaces -o json | \
jq -r '
.items[]
| .metadata as $m
| .spec as $s
| .status as $st
| [
($m.namespace),
($m.name),
([$s.initContainers[], $s.containers[]]?
| map(
{
name: .name,
privileged: (.securityContext.privileged // false),
hostPID: ($s.hostPID // false),
hostIPC: ($s.hostIPC // false),
hostNetwork: ($s.hostNetwork // false),
allowPrivEsc: (.securityContext.allowPrivilegeEscalation // "null")
}
)
)
]
| select(.[2] != null)
| . as [$ns, $pod, $cs]
| $cs[]
| select(.privileged == true or .hostPID == true or .hostIPC == true or .hostNetwork == true or .allowPrivEsc == true)
| "NS=\($ns) POD=\($pod) CONTAINER=\(.name) privileged=\(.privileged) hostPID=\(.hostPID) hostIPC=\(.hostIPC) hostNetwork=\(.hostNetwork) allowPrivEsc=\(.allowPrivEsc)"
' 2>/dev/null || echo "jq not available; skipping pod-level risk sampling."
echo
echo "Problem indicators here:"
echo " - Non-system workloads (namespaces other than kube-system, gke-system, etc.)"
echo " running privileged or sharing host namespaces."
echo " - If such workloads exist and require permissive PSPs, strong segregation and"
echo " explicit justification are required."
echo
echo "=== 4) SUMMARY OF WHAT INDICATES A PROBLEM FOR THIS BENCHMARK ==="
echo
echo "The benchmark finding is NOT satisfied if ANY of the following apply:"
echo " 1) The cluster control-plane is not configured with Pod Security Policy admission"
echo " (gcloud --enable-pod-security-policy not set for the cluster)."
echo " 2) PSPs exist but:"
echo " - Default / commonly used PSPs allow privileged=true or broad host* access,"
echo " AND are bound to wide subjects (e.g. system:authenticated)."
echo " - Most workloads could run with stricter PSPs but are not constrained."
echo
echo "To remediate the control-plane setting itself, use the provider tooling, e.g.:"
echo " gcloud beta container clusters update CLUSTER_NAME --zone COMPUTE_ZONE --enable-pod-security-policy"
echo
echo "This script only helps you identify the current state and potential misconfigurations."