Skip to main content

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

Manual Steps
  1. Identify clusters and current PSP setting

    • On any machine with gcloud configured 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.
  2. Review current use of privileged features in workloads

    • On any machine with gcloud and kubectl access, 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.
  3. 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).
  4. 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 gcloud access:
      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-management commands, according to your organization’s policy.
  5. 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.
  6. 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-namespaces
      kubectl get constraints --all-namespaces
    • Record which mechanism is in use, which namespaces are protected, and any approved exceptions for future audits.
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."

Additional Reading: