Implementing a Secure-First Pod Security Policy Architecture

Shazad Brohi
ITNEXT
Published in
4 min readNov 2, 2020

--

Photo by Miłosz Klinowski on Unsplash

Pod Security Policies

There are a myriad of ways to secure a Kubernetes cluster, whether through implementing Network Policies to control ingress/egress traffic, Role Based Access Control, or multi-tenancy. One of the most effective ways to manage what gets run on your cluster is through the creation of Pod Security Policies.

A Pod Security Policy defines a set of conditions a pod must run with in order to run on the cluster. These conditions span host-level access, to a range of UIDs a container can run as, and even what volumes a pod can use.

In this article, I will lay out a blueprint for applying a secure-first mindset for your cluster through the implementation of Pod Security Policies. With a secure or restricted-first mindset, you will by default, lock-down your cluster to run secure workloads and through review, make exceptions for those workloads which require privileged access.

Default to Restricted

As we are approaching our cluster from a secure-first mindset, we need to define a default Pod Security Policy that extends to all authenticated users and service accounts. Provided below is a sample restricted PSP you can use to get started and then tweak based on your needs:

Execute the following command to create your new Pod Security Policy:

kubectl create -f restricted-psp.yaml

Next, we’ll want to ensure that this Pod Security Policy applies to all service accounts as we’re approaching this from a secure-first mindset. Use the RBAC resources below to accomplish this:

kubectl create -f restricted-psp-rbac.yaml

The above resources will first create a ClusterRole resource that is authorized to use the restricted-psp Pod Security Policy. We then create a ClusterRoleBinding which binds our ClusterRole to all service accounts across the cluster. This effectively means that when you deploy any pod on the cluster, it must confine to the conditions set forth by our restricted-psp Pod Security Policy.

Privileged Access is the Exception

Now that we have applied a default restrictive Pod Security Policy, we are now ready to create our privileged PSP to allow workloads which require elevated levels of access to run. Some examples of these workloads include the control plane pods like kube-proxy, as well as ingress pods such as nginx.

Create the following privileged PSP using the template below, you can tweak it as needed based on your requirements:

kubectl create -f privileged-psp.yaml

This PSP effectively allows privileged access and escalation, allows containers to run as any user, allows containers to use any kind of volume, allows host access (filesystem and network), and allows any linux capability. You must exercise great judgement when determining how much privilege your workloads need. You should first understand what the minimum set of privileges those workloads need to run, then refine the PSP accordingly.

Next, we need to define a ClusterRole which is authorized to use our privileged PSP:

kubectl create -f privileged-cluster-role.yaml

Now, we need to be able to determine which workloads require privileged access and then bind those workloads to our privileged PSP. This should be done on a case by case basis for your cluster, so as not to open the entire cluster up to privileged access.

To accomplish this, I would look at 2 questions to ask:

  1. Is there a namespace on your cluster (e.g. kube-system) where all workloads operate similarly and will require privileged access?
  2. Are there only specific workloads in a namespace which require privileged access?

For scenario 1, use the following RBAC resource template to allow all service accounts in a specific namespace to use the privileged pod security policy:

kubectl create -f namespaced-privileged-access.yaml

For scenario 2, use the following RBAC resource template to allow a specific service account in a namespace to use the privileged pod security policy:

kubectl create -f workload-specific-binding.yaml

Enable the Pod Security Policy Admission Controller

Now that we have created our pod security policies and RBAC resources, we need to enable the Pod Security Policy admission controller on the Kubernetes API Server. Make sure that all of these resources have been created, otherwise, no workloads will be able to run once the admission controller is enabled (it requires that at least 1 Pod Security Policy be present).

This is done by updating the enable-admission-plugins flag on the Kubernetes API Server to include PodSecurityPolicy in the list. If you are using a managed Kubernetes provider (EKS, AKS, etc), your provider is responsible for ensuring this is enabled, otherwise, you can use the steps above.

To see what admission plugins are currently available, run:

kube-apiserver -h | grep enable-admission-plugins

Validation

To can see what PodSecurityPolicy your pod is using by executing the following command:

kubectl describe <pod-name> -n <your-namespace>

Conclusion

In summary, pod security policies allow you to define a set of conditions that workloads must confine to in order to run. You have access to a wide array of conditions you can define for a policy, offering great flexibility in enforcing a secure architecture:

  • Volume Types
  • Host Filesystem and Network Access
  • Privileged Access and Escalation
  • Linux Capabilities
  • RunAsUser for containers

And much more…

With the blueprint above, you will be able to operate your Kubernetes cluster from a secure-first mindset, while still excepting privileged access where needed.

Resources

Pod Security Policies: Kubernetes Docs

--

--

Shazad is a Sr Software Engineer and DevOps architect at Apple.