alcide

Alcide Blog

Cloud-native Security Provider

Pod Security Policy

Oct 24, 2019 10:53:44 AM / by Adi Sapir

for bllog article page-Pod Security Policy

What is Pod Security Policy?

The Pod Security Policy, sometimes called PSP in short, is a Kubernetes resource that allows the enforcement of policy rules during the creation phase of a Pod.
When a PodSecurityPolicy resource is created, it does nothing. In order to use it, the requesting user or target pod’s service account must be authorized to use the policy, by allowing the use verb on the policy.

 

Most Kubernetes pods are not created directly by users. Instead, they are typically created indirectly as part of a Deployment, ReplicaSet, or other templated controller via the controller manager. Granting the controller access to the policy would grant access for all pods created by that controller, so the preferred method for authorizing policies is to grant access to the pod’s service account 

For example, if one wishes to make sure that Pod with root privileges can only be created by the cluster administrator and not by any other user then the following operations will do the trick:

  • Define a Pod Security Policy that deny the creation of Pod with root privileges
  • Associate the Pod Security Policy with Role or a Cluster Role that is binded to non-admin        users
  • Define a Pod Security Policy that allows the creation of Pod with root privileges
  • Associate the Pod Security Policy with Role or a Cluster Role that is binded to admin users

 

The below diagram illustrates that place of the Pod Security Policy within the different Kubernetes objects

diagram for blog

 

 

 

 

 

 

 

 

The Pod Security Policy Object (PodSecurityPolicy) is bound either to a User (User) or to a Service Account (ServiceAccount

The binding to the User or the Service Account is done Associating the Pod SecurityPolicy to a Role (Role) or the Cluster Role (ClusterRole) that is binded via the Role Binding (RoleBinding) or the Cluster Role Binding (ClusterRoleBinding) to the User or the Service Account.

See the Pod Security Policy documentation for the full details.

 

Activating the Pod Security Policy

The Pod Security Policy is part of Kubernetes admission control mechanism, so in order to have the Pod Security Policy take effect, the Kubernetes Admission Control needs to be activated.

When the User or the Service Account access the Kubernetes API for creating a Pod, the Admission Control is invoked and checks if the Pod attributes conform with the rules defined in the Pod Security Policy. In case there is a mismatch the API server will fail the operation.

 

Controlling Container Runtime

One way to control the Kubernetes worker node’s Container Runtime is to gain access to it’s API interface by connecting to a local file system unix socket, which can be done by mounting the socket to another container - In docker for example the default unix socket file is located in   /var/run/docker.sock 

Volumes:

- /var/run/docker.sock:/var/run/docker.sock

 

Docker CLI client uses this socket to execute docker commands by default. You can override these settings as well.

There may be different valid applications that require access to  the container runtime . For example logging agents such as fluentd, worker node monitoring agents such as Datadog, or security agents.. An uncommon usage can be the creation of new containers on the worker node directly through the container runtime and not through Kubernetes APIs
This increases attack surface so one should avoid  mounting the container runtime unix-socket based API endpoint inside a Pod in order not to compromise the host that is running docker daemon, since Docker by default launches all containers as root.

 

New call-to-action

 

Example:  Protecting Docker Container Runtime API

In the following example we will see how can the Pod Security Policy be used to protect against mounting docker.sock into a container. We will first define a namespace, psp-example, where our example will run, a service account malicious-user, that will represent the user that is trying to create a Pod that can access the docker.sock 

kubectl create namespace psp-example

kubectl create serviceaccount -n psp-example malicious-user

 

Step 1: Define the Pod Security Policy

First let's define the Pod Security Policy that will limit the allowed volumes:

apiVersion: policy/v1beta1

kind: PodSecurityPolicy

metadata:

  name: psp-protect-docker

spec:

  privileged: false  # Don't allow privileged pods!

  allowPrivilegeEscalation: false

  # The rest fills in some required fields.

  seLinux:

    rule: RunAsAny

  supplementalGroups:

    rule: RunAsAny

  runAsUser:

    rule: RunAsAny

  fsGroup:

    rule: RunAsAny

  volumes:

  - configMap

  - emptyDir

  - secret

  - projected

  - downwardAPI

  allowedHostPaths:

  # This specifies a whitelist of host paths that are allowed to be used by hostPath volumes. An empty list means there is no restriction on host paths used.

  - pathPrefix: "/tmp"

    readOnly: true

Note the use of the allowedHostPaths to limit the allows files on the host. 

 

Next we will create the Policy:

kubectl create -f example_psp.yaml

 

Step 2: Create a Role and Attach the Pod Security Policy

Now we will create a Role and attach the Pod Security Policy to the Role:

apiVersion: rbac.authorization.k8s.io/v1

kind: ClusterRole

metadata:

  name: role-unprivileged

  # "namespace" omitted since ClusterRoles are not namespaced

rules:

- apiGroups:

  - policy

  resourceNames:

  - psp-protect-docker

  resources:

  - podsecuritypolicies

  verbs:

  - use

- apiGroups: [""]

  resources: ["pods"]

  verbs: ["get", "list", "watch", "create"]

 

Next we will create the Role:

kubectl create -f example_role.yaml

 

Step 3: Bind the Role to the User

Now we will bind the role to a user, a service account in our case:

apiVersion: rbac.authorization.k8s.io/v1

kind: ClusterRoleBinding

metadata:

  name: role-binding-unprivileged

roleRef:

  apiGroup: rbac.authorization.k8s.io

  kind: ClusterRole

  name: role-unprivileged

subjects:

  - kind: ServiceAccount

    name: malicious-user

    namespace: psp-example

Next we will run the binding:

kubectl create -f example_role_binding.yaml 

 

Running the Example

Lets define a pod:

apiVersion: v1

kind: Pod

metadata:

  name: attacking-pod

spec:

  volumes:

  - name: docker-socket

    hostPath:

      path: /var/run/docker.sock

  containers:

  - name:  pause

    image: k8s.gcr.io/pause

    volumeMounts:

    - mountPath: /my-docker

      name: docker-socket

    securityContext:

      allowPrivilegeEscalation: true

 

Now we enable the Admission control to enable Pod Security Policy. For example the gcloud command for my-cluster would be:

gcloud beta container clusters update my-cluster --enable-pod-security-policy --zone us-east1-d

 

Next we will run the Pod creation:

kubectl create -f attaching_pod.yaml --as=system:serviceaccount:psp-example:malicious-user -n psp-example'

 

We will get an error message indicating that the pod creation violates the Pod Security Policy:

Error from server (Forbidden): error when creating "attacking_pod.yaml": pods "attacking-pod" is forbidden: unable to validate against any pod security policy: [spec.volumes[0]: Invalid value: "hostPath": hostPath volumes are not allowed to be used spec.containers[0].securityContext.allowPrivilegeEscalation: Invalid value: true: Allowing privilege escalation for containers is not allowed]

 

Topics: kubernetes, network security, pod, Kubernetes security