Pod Security Policy
Overview
Pod Security Policy (PSP) is a cluster-level resource and it's one of the admission controllers that allows you to control the security of the Kubernetes pods. It allows you to define a set of conditions that a pod must meet in order to run in the cluster.
In Kubernetes v1.21, PSP is being deprecated and removed from Kubernets v1.25. There are multiple ways to replace PSPs
- Policy-as-code (PAC) solutions within the Kubernetes ecosystem. For example, Kyverno, Open Policy Agent (OPA), Gatekeeper, etc
- The Kubernetes Pod Security Standards (PSS) with Pod Security Admission (PSA)
apiVersion: v1
kind: Pod
metadata:
name: kube-apiserver-kind-cluster-control-plane
namespace: kube-system
spec:
containers:
- command:
- kube-apiserver
- --advertise-address=10.89.0.2
- --allow-privileged=true
- --authorization-mode=Node,RBAC
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --enable-admission-plugins=NodeRestriction,PodSecurityPolicy
...
image: registry.k8s.io/kube-apiserver:v1.30.0
We have to add the PodSecurityPolicy admission controller to the kube-apiserver. So we add PodSecurityPolicy to the --enable-admission-plugins flag.
Usage and Concept of Pod Security Policy
apiVersion: v1
kind: Pod
metadata:
name: sample
spec:
containers:
- name: ubuntu
image: ubuntu
securityContext:
privileged: true # privileged user
runAsUser: 0 # root user
capabilities:
add: ["CAP_SYS_BOOT"]
volumes:
- name: data-volume
hostPath:
path: /data
Take the above example, the pod is running as a privileged user, which means it allows the processes running in the container to have root privileges on the host. It also run as root user and has the CAP_SYS_BOOT capability, which allows the container to reboot the host. Besides, it mounts the hostPath volume, which allows the container to access the host filesystem. All these configurations are insecure and dangerous.
Step 1: Create Pod Security Policy
Therefore, we can create a Pod Security Policy to restrict the pod from running or prevent to create the pod with the above configurations. Pod Security Policy not only restricted the pod from creation but also enforced or mutated (defaultAddCapabilities) the pod's configuration to meet the policy.
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted-psp
spec:
privileged: false
seLinux:
rule: RunAsAny
runAsUser:
rule: MustRunAsNonRoot
fsGroup:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
volumes:
- 'persistentVolumeClaim'
requiredDropCapabilities:
- 'CAP_SYS_BOOT'
defaultAddCapabilities: # default add capabilities to the pod
- 'CAP_SYS_TIME'
- This will reject the pod if the pod privileged flag set to
true
- This will reject the pod if the pod runAsUser set to
0
- This will reject the pod if the pod is using
hostPath
volume, as it's not in the volumes list, which only allowspersistentVolumeClaim
volume - This will reject the pod if the pod has the
CAP_SYS_BOOT
capability - This will add the
CAP_SYS_TIME
capability to the pod default even if the pod doesn't have it
Step 2: Authorized the Pod Security Policy using RBAC
So, the PodSecurityPolicy will check the pod's configuration before creating the pod. If the pod's configuration violates the policy, the pod will be rejected and not created. However, we just enabled the PodSecurityPolicy admission controller, but we do not authorize any security policies yet. In this case, the admission controller will not able to communicate with the pod security policies API and eventually will reject all the pods creation, even if the pod's configuration is meet the policy.
Now, we know that every pod has a service account (default) when created even if we don't specify it, as this comes from the namespace. So, we can authorize the default service account from the namespace to access the security policies by creating a Role and RoleBinding, so that the pod can be validated again the PodSecurityPolicy.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: psp-role
rules:
- apiGroups: ['policy']
resources: ['podsecuritypolicies']
resourceNames: ['restricted-psp'] # Replace with your PodSecurityPolicy name
verbs: ['user']
Step 3: Create the Pod with correct configuration
Now, we can create the pod with the correct configuration that meets the PodSecurityPolicy.
apiVersion: v1
kind: Pod
metadata:
name: sample
spec:
containers:
- name: ubuntu
image: ubuntu
securityContext:
privileged: false # must be false as per the policy
runAsUser: 1000 # must be non-root user as per the policy
volumes:
- name: data-volume
persistentVolumeClaim: # must use persistentVolumeClaim as per the policy
claimName: my-pvc # replace with your actual PVC name