Enable Kubernetes Pod Security Policy with kube-psp-advisor.

By Kaizhe Huang - FEBRUARY 6, 2019

Kubernetes Pod Security Policy is a mechanism to enforce best security practices in Kubernetes. In this tutorial, we will explain how to enable Kubernetes Pod Security Policy across your cluster using kube-psp-advisor to address the practical challenges of building an adaptive and fine-grained security policy on Kubernetes in production.

What is a Kubernetes Pod Security Policy? An example

A Kubernetes Pod Security Policy is a cluster-level resource that controls security sensitive aspects of the pod specification limiting access privileges of a Kubernetes pod. For example you can use Kubernetes PSP for restricting:

  • Running privileged containers
  • The user that the container is running as
  • Access the host process or network namespace
  • Access the host filesystem
  • Linux capabilities, Seccomp or SELinux profiles

A Pod Security Policy definition will look like the following:

apiVersion: policy/v1beta1 kind: PodSecurityPolicy metadata: name: example spec: allowedCapabilities: - NET_ADMIN - IPC_LOCK allowedHostPaths: - pathPrefix: /dev - pathPrefix: /run - pathPrefix: / fsGroup: rule: RunAsAny hostNetwork: true privileged: true runAsUser: rule: RunAsAny seLinux: rule: RunAsAny supplementalGroups: rule: RunAsAny volumes: - hostPath - secret
Code language: PHP (php)

This PSP is quite relaxed: allows the NET_ADMIN and IPC_LOCK capabilities, mount /, /dev and /run from the host and Kubernetes secret volumes. Doesn’t enforce any file system group ID nor supplemental groups. Allows to run the container as any user, access the host network namespace and run as a privileged container. No SELinux policy is enforced.

How to enable Kubernetes Pod Security Policy

Implementing a Kubernetes Pod Security Policy is just like creating any other Kubernetes resource in your cluster:

$ kubectl apply -f example-psp.yaml

Then, to verify the Pod Security Policy has been created successfully:

$ kubectl get psp
Code language: JavaScript (javascript)

The output will be look like following:

Code language: JavaScript (javascript)

But how do you know what your Pod Security Policy should be like? Does it restrict everything that we do not need? We can end up with a policy that is either too restricted or too loose.

Kubernetes Pod Security Policy best practices and challenges of implementing in production

We all know the theory of Kubernetes security best practices:

  1. Do not run privileged containers
  2. Do not run containers as root
  3. Do not allow access to the host namespace
  4. Restrict Linux capabilities

However, building a Pod Security Policy based on Kubernetes security best practices might not be realistic for a bunch of reasons.

Let me give you a few real live examples that you can find out in the wild:

For performance reasons, the IPC_LOCK capability might be required. We can see this in multi-process applications like Cassandra, MySQL, etc.

Monitoring and security components usually require extended access privileges in order to see everything they need. For example, PacketBeat requires NET_ADMIN capability to capture network traffic. Sysdig, our container security product, requires to be run as a privileged container to hook into the kernel to capture system calls and access to the host namespace to see all the running containers that we want to monitor and secure. If you want to debug a Golang application using Delve, then you will need add the SYS_PTRACE capability to the pod.

A production security policy depends on the requirements of the software run and how it was built. Implementing a Kubernetes Pod Security policy is a joint effort between DevSecOps and software development teams. They both need to come up with a way that adapts the theory of Kubernetes security best practices with the many different access privilege requirements from diverse applications.

Kubernetes Security Policy made easy with kube-psp-advisor

Kubernetes Pod Security Policy Advisor (a.k.a kube-psp-advisor) is an opensource tool from Sysdig, like Sysdig Inspect or Falco. kube-psp-advisor scans the existing security context from Kubernetes resources like deployments, daementsets, replicasets, etc taken as the reference model we want to enforce and then automatically generates the Pod Security Policy for all the resources in the entire cluster.

kube-psp-advisor will look at different attributes to create the recommended Pod Security Policy:

  • allowPrivilegeEscalation
  • allowedCapabilities
  • allowedHostPaths
  • hostIPC
  • hostNetwork
  • hostPID
  • privileged
  • readOnlyRootFilesystem
  • runAsUser
  • Volume

Using kube-psp-advisor is really simple. First clone and build the project:

$ git clone https://github.com/sysdiglabs/kube-psp-advisor $ cd kube-psp-advisor && make build
Code language: PHP (php)

Now we are ready to use it. kube-psp-advisor can accept a few parameters:

--namespace. By default, the Pod Security Policy is generated for the resources in the entire cluster. With this flag just analyzes and generates the policy for the dedicated namespace.

--report. Prints the resources that are making use of each Kubernetes security feature, e.g.: which pods, deployments, etc are using hostIPC, hostNetwork, etc.

--kubeconfig. Absolute path to the kubeconfig file, defaults to $HOME/.kube/config.

kube-psp-advisor loaded the kubeconfig file, connect to the kubernetes cluster API server and then conduct the scan which print through stdout the generated PSP, like this:

$ ./kube-psp-advisor --namespace=psp-test apiVersion: policy/v1beta1 kind: PodSecurityPolicy metadata: creationTimestamp: null name: pod-security-policy-20181130114734 spec: allowedCapabilities: - SYS_ADMIN - NET_ADMIN allowedHostPaths: - pathPrefix: /bin - pathPrefix: /tmp - pathPrefix: /usr/sbin - pathPrefix: /usr/bin fsGroup: rule: RunAsAny hostIPC: false hostNetwork: false hostPID: false privileged: true runAsUser: rule: RunAsAny seLinux: rule: RunAsAny supplementalGroups: rule: RunAsAny volumes: - hostPath - configMap - secret
Code language: PHP (php)

To finish, we will review and apply the generated Kubernetes Pod Security Policy:

$ ./kube-psp-advisor --namespace psp-test > psp-test.yaml && cat psp-test.yaml $ kubectl apply -f psp-test.yaml

If we want to know more on how it was built, we will use the --report flag:

$ ./kube-psp-advisor --namespace=psp-test --report | jq .podSecuritySpecs { "hostIPC": [ { "metadata": { "name": "busy-rs", "kind": "ReplicaSet" }, "namespace": "psp-test", "hostPID": true, "hostMetwork": true, "hostIPC": true, "volumeTypes": [ "configMap" ] }, { "metadata": { "name": "busy-job", "kind": "Job" }, "namespace": "psp-test", "hostIPC": true, "volumeTypes": [ "hostPath" ], "mountedHostPath": [ "/usr/bin" ] } ], "hostNetwork": [ { "metadata": { "name": "busy-rs", "kind": "ReplicaSet" }, "namespace": "psp-test", "hostPID": true, "hostMetwork": true, "hostIPC": true, "volumeTypes": [ "configMap" ] }, { "metadata": { "name": "busy-pod", "kind": "Pod" }, "namespace": "psp-test", "hostMetwork": true, "volumeTypes": [ "hostPath", "secret" ], "mountedHostPath": [ "/usr/bin" ] } ], "hostPID": [ { "metadata": { "name": "busy-deploy", "kind": "Deployment" }, "namespace": "psp-test", "hostPID": true, "volumeTypes": [ "hostPath" ], "mountedHostPath": [ "/tmp" ] }, { "metadata": { "name": "busy-rs", "kind": "ReplicaSet" }, "namespace": "psp-test", "hostPID": true, "hostMetwork": true, "hostIPC": true, "volumeTypes": [ "configMap" ] } ] }
Code language: JavaScript (javascript)


Building a Kubernetes Pod Security Policy can be hard. Not all application might work following all the Kubernetes security best practices by the book. That doesn’t mean that you should ignore and skip implementing PSP at all. If an specific Pod requires some additional access, still being able to implement a Pod Security Policy that restricts further access privileges is definitely a good security approach. This is actually something that you will find in most production environments.

kube-psp-advisor makes implementing Kubernetes Pod Security Policy a simple and straightforward process, so you can get running in almost no time, adapting to your application requirements and specifically fine-grained for each one to allow only the least access privilege.