GKE’s Pod Security Standards (PSS) are a set of configurable security policies that prevent common security misconfigurations in your Kubernetes pods.
Here’s a GKE cluster with PSS enabled, showing a PodSecurityPolicy definition that enforces a restrictive level:
apiVersion: podsecurity.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: gke-restricted-pod-security
spec:
crd:
spec:
names:
kind: GKEPodSecurityRestricted
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8spsppolicy
violation[{"msg": msg, "details": {"missing_capabilities": missing}}] {
container := input.review.object.spec.containers[_]
not container.securityContext.capabilities.add[_]
missing := {"NET_RAW"} # Example: disallow NET_RAW capability
msg := "container disallowed capabilities"
}
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
container.securityContext.privileged == true
msg := "privileged containers are not allowed"
}
This ConstraintTemplate uses Rego, the policy language for Open Policy Agent (OPA), to define the rules. When applied to a cluster via a Constraint object, it will enforce these rules during pod creation.
The core problem PSS solves is the inherent flexibility of Kubernetes, which can inadvertently allow for insecure configurations. Without PSS, a user could deploy a pod that runs as root, has full host access, or uses elevated Linux capabilities, creating significant security risks. PSS provides a declarative way to harden your cluster against these common vulnerabilities.
Internally, GKE leverages Gatekeeper, an OPA-based policy enforcement engine, to implement PSS. When a pod is created or updated, Gatekeeper intercepts the request and evaluates it against the defined ConstraintTemplates. If any policy is violated, Gatekeeper denies the admission request, preventing the insecure pod from being deployed.
You control PSS through a combination of ConstraintTemplates and Constraint resources. A ConstraintTemplate defines the structure and logic of a policy (written in Rego), while a Constraint applies that template to specific resources in your cluster, often with specific parameters. For example, you might have a Constraint that applies the GKEPodSecurityRestricted template only to pods running in a particular namespace or with specific labels.
The Pod Security Standards themselves are defined by Kubernetes and implemented by the admission controller. GKE offers several predefined profiles: privileged, baseline, and restricted. The restricted profile is the most secure, enforcing tightest controls, while baseline offers a balance between security and usability. The privileged profile essentially disables PSS, allowing all configurations.
Here’s how you might apply the restricted profile to your cluster using a Constraint:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: GKEPodSecurityRestricted
metadata:
name: pss-restricted-enforce
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaces:
- "default" # Apply to the 'default' namespace
This Constraint activates the GKEPodSecurityRestricted template (defined earlier) and targets pods in the default namespace. The spec.match field allows you to scope the policy to specific namespaces, labels, or even fields within the pod definition.
A less obvious aspect of PSS is that policies can be enforced at different levels. While enforce will reject violating pods, warn will only generate audit logs, allowing you to identify potential issues without immediately blocking deployments. This is crucial for a phased rollout of stricter security policies. You can also set dryrun to test policies without actually enforcing them.
When you encounter a pod rejection due to PSS, the error message will often point to the specific policy violated. For instance, a message like "container disallowed capabilities" might be followed by details indicating NET_RAW was attempted. This direct feedback is invaluable for understanding and correcting the pod’s security context.
The next logical step after enforcing Pod Security Standards is to explore network policies, which control the traffic flow between pods and external services.