Introduction
Remember Pod Security Policies (PSPs)? They were a great way to enforce customizable security standards for pods. However, authoring PSPs were left completely up to administrators and/or organizations; this meant that every organization using Kubernetes was left to discover, understand, and implement best-practices for pod security on their own. Because of useability issues (detailed in this blog) PSPs were officially removed in Kubernetes v1.25.
The good news is that there is a better and easier way to enforce best-practice based security standards for your pods: Pod Security Admission which became stable in v1.25.
What is Pod Security Admission?
Pod Security Admission is a built-in admission controller in Kubernetes that enforces pod security standards at the admission phase before pods are scheduled or run on a cluster. It acts as a gatekeeper, ensuring that pods meet certain minimum security criteria.
Why is Pod Security Admission Important?
The primary purpose of Pod Security Admission is to minimize the potential attack surface within a Kubernetes cluster by enforcing best practices and security standards for pod creation and deployment. It provides a structured approach to applying security settings, helping cluster administrators control the security features that pods can use. This ensures pods operate within the bounds of the configured security policies, reducing the risk of vulnerabilities and security breaches.
How Does Pod Security Admission Work?
Pod Security Admission works by evaluating pod creation and modification API requests against predefined Pod Security Standards (PSS) security profiles (predefined policies eliminate the guesswork previously required by PSPs). When a pod request is made, the Pod Security Admission controller checks the request against the applicable policies for the namespace where the pod is being deployed. If the pod specification meets policy requirements, the request is allowed. If not, the request may be denied, logged, or the user may receive a warning.
Admission Controllers
Admission controllers are part of the triple-A (Authentication, Authorization, and Admission) process in Kubernetes. They are responsible for intercepting and processing requests to the Kubernetes API server, enforcing policies and security standards before the requests are allowed to proceed. They can be mutating, validating, or both. There are many controllers. Some of them are enabled by default, and others are not.
Here is how you can check which plugins are enabled by default:
$ kube-apiserver -h | grep enable-admission-plugins
--enable-admission-plugins strings admission plugins that should be enabled in addition to default enabled ones (NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, PodSecurity, Priority, DefaultTolerationSeconds,....
Enable Admission Controllers
To enable the Pod Security Admission controller, you need to add it to the list of enabled admission plugins in the kube-apiserver configuration. You can do this by modifying the kube-apiserver manifest file or using the --enable-admission-plugins flag when starting the kube-apiserver.
Disable Admission Controllers
To disable the Pod Security Admission controller, remove it from the list of enabled admission plugins in the kube-apiserver configuration. You can do this by modifying the kube-apiserver manifest file or using the --disable-admission-plugins flag when starting the kube-apiserver.
Pod Security Admission Controller
Did you notice that the PodSecurity admission controller is among the list of admission controllers enabled by default? This is because it is part of the default admission plugins in Kubernetes. This means the PodSecurity admission controller is always active and enforces pod security standards by default.
Now that you have a good understanding of Pod Security Admission, let’s look at how you can enforce security policies in your Kubernetes cluster.
Pod Security Standards in Action
Pod Security Admission (PSA) introduces a straightforward and manageable approach to applying security standards across different parts of your Kubernetes cluster. By leveraging namespace labels, cluster administrators can enforce pod security at the namespace level. This method allows for granular control over the security posture of pods based on their operational requirements and the sensitivity of their workloads.
PSS namespace labels
Namespace labels indicate which predefined Pod Security Standards should be applied to all pods within that namespace. The labels need two things: a MODE and a LEVEL.
Here is an example of a namespace label:
pod-security.kubernetes.io/<MODE>: <LEVEL>
PSS MODE
pod-security.kubernetes.io/enforce: defines the standard that should be enforced for all pods in the namespace.pod-security.kubernetes.io/audit: defines the standard that should be audited for all pods in the namespace.pod-security.kubernetes.io/warn: defines the standard that, when not met, will trigger a warning for all pods in the namespace but not block their deployment.
PSS LEVELS
PSS are categorized into three distinct levels: privileged, baseline, and restricted, each catering to different security requirements and use cases.
The three profiles are designed to cover a broad range of use cases and provide a good starting point for securing your pods. These profiles are part of the Kubernetes codebase and are not directly modifiable as they are intended to represent a consensus on best practices in pod security.
Privileged profile
The privileged profile provides the least restrictive environment for pods, allowing for the broadest set of capabilities. This profile is typically used for pods that require a high level of system access and permissions to function correctly.
Real-world use cases: the privileged profile is suitable for system-level components, such as network or storage drivers, that require extensive access to host resources.
Baseline profile
The baseline profile is designed as a middle ground, offering a balance between operational flexibility and security. It applies a default set of restrictions that are reasonable for most pods while still allowing certain privileges that are commonly required for applications to run.
Real-world use cases: this profile is intended for general-purpose applications that do not require extensive access to host resources. It is suitable for most workloads, providing a secure environment without overly restricting functionality.
Restricted profile
The restricted profile imposes the strictest set of restrictions on pod capabilities, following current Kubernetes Pod Security Standards best practices to enhance security.
Real-world use cases: this profile is ideal for pods that handle sensitive data or run in multi-tenant environments where strict security boundaries are required. It is designed to enforce the principle of least privilege, ensuring that pods have only the permissions they need to operate.
Applying PSS
Now, let’s combine the LEVEL and the MODE to create a label that will enforce the baseline profile. Here is how a namespace manifest looks with the appropriate label:
apiVersion: v1
kind: Namespace
metadata:
name: secure-workload
labels:
pod-security.kubernetes.io/enforce: "baseline"
We can also extend it and add the audit and warn modes:
apiVersion: v1
kind: Namespace
metadata:
name: secure-workload
labels:
pod-security.kubernetes.io/enforce: "baseline"
pod-security.kubernetes.io/audit: "restricted"
pod-security.kubernetes.io/warn: "privileged"
Now, this namespace will enforce the baseline profile, audit the restricted profile, and warn about the privileged profile.

PSS namespace tricks
Here are some tricks you can use with the namespace labels:
Use a specific Kubernetes version:
apiVersion: v1
kind: Namespace
metadata:
name: secure-workload
labels:
pod-security.kubernetes.io/enforce: "baseline"
pod-security.kubernetes.io/audit: "restricted"
pod-security.kubernetes.io/audit-version: v1.29
pod-security.kubernetes.io/warn: "privileged"
pod-security.kubernetes.io/warn-version: v1.29
Add labels to existing namespaces using kubectl:
$ kubectl label namespace secured-zone pod-security.kubernetes.io/enforce=baseline
Applying to all namespaces
$ kubectl label namespace --all pod-security.kubernetes.io/enforce=baseline pod-security.kubernetes.io/audit=restricted
Updating namespace labels
$ kubectl label namespace secured-zone pod-security.kubernetes.io/enforce=baseline --overwrite
Hands-on
In this section, we will demonstrate how to apply Pod Security Standards to a Kubernetes namespace using labels. We will create a new namespace and apply the baseline profile to it. We will then deploy a pod to the namespace and verify that the Pod Security Admission controller enforces the security standards.
Step 1: Create a new namespace
First, let’s create a new namespace called secure-workload using the following yaml:
apiVersion: v1
kind: Namespace
metadata:
name: secure-workload
labels:
pod-security.kubernetes.io/enforce: "baseline"
Create the namespace using the following command:
$ kubectl apply -f secure-workload.yaml
namespace/secure-workload created
Here is how we can verify that the namespace was created successfully. Examine the labels which are the important piece:
$ kubectl describe ns secure-workload
Name: secure-workload
Labels: kubernetes.io/metadata.name=secure-workload
pod-security.kubernetes.io/enforce=baseline
Annotations: <none>
Status: Active
No resource quota.
No LimitRange resource.
Another variant is to output everything to yaml:
$ kubectl get ns secure-workload -o yaml
apiVersion: v1
kind: Namespace
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"labels":{"pod-security.kubernetes.io/enforce":"baseline"},"name":"secure-workload"}}
creationTimestamp: "2024-02-14T21:52:56Z"
labels:
kubernetes.io/metadata.name: secure-workload
pod-security.kubernetes.io/enforce: baseline
name: secure-workload
Step 2: Deploy a pod to the namespace
Now we will deploy a simple pod to the secure-workload namespace using the following yaml:
apiVersion: v1
kind: Pod
metadata:
name: pod-psa
namespace: secure-workload
spec:
containers:
- name: secure-workload-container
image: nginx:latest
securityContext:
privileged: true
Try creating the pod using the following command:
$ kubectl apply -f pod-psa.yaml
Error from server (Forbidden): error when creating "pod-psa.yaml": pods "pod-psa" is forbidden: violates PodSecurity "baseline:latest": privileged (container "secure-workload-container" must not set securityContext.privileged=true)
Ooops! The Pod Security Admission controller denied the pod creation request because it violates the baseline profile. The error message indicates that the pod is not allowed to set securityContext.privileged=true. This is exactly what we expected, as the baseline profile does not allow privileged containers.
We can check the controls and the policy from the Kubernetes docs Pod Security Standards page here, where you can find all the settings for all profiles. For example, if you scroll down, under the Baseline heading you will see the settings for Privileged Containers, and the allowed value is false. In our pod, we have securityContext.privileged: true, which violates the policy. That is why our pod cannot start.
Let’s fix that; edit the pod-psa.yaml, and change privileged to false:
apiVersion: v1
kind: Pod
metadata:
name: pod-psa
namespace: secure-workload
spec:
containers:
- name: secure-workload-container
image: nginx:latest
securityContext:
privileged: false ## Change this to false
Let’s now apply the pod again.
$ kubectl apply -f pod-psa.yaml
pod/pod-psa created
Let’s check the pods in our secure-workload namespace.
$ kubectl get pods -n secure-workload
NAME READY STATUS RESTARTS AGE
pod-psa 1/1 Running 0 29s
As you can see, the pod is running!
Conclusion
You can apply Pod Security Standards to a Kubernetes namespace using labels. By enforcing security standards at the namespace level, you can ensure that all pods within the namespace adhere to the specified security profiles. This approach provides a structured and manageable way to apply security settings to your pods, helping maintain your Kubernetes cluster’s security and integrity.
Bust-a-kube challenge
Want to try this on your own? Try out our related bust-a-kube challenge. It’s fun, a bit tricky, and full of surprises. Think you can crack it? Give it a try and see what you find! Check out Bust-a-kube here.