6.5.Kubernetes Pod Security Policies
This deploys the demo application to Kubernetes using cluster-wide pod security policy to enforce that the docker container must run unprivileged using non-root user.
RBAC
Before diving into the pod security policy let's check how the authorization using RBAC (Role Based Access Control) works.
Authentication
Kubernetes has the notion of users and service account to access resources. A user is associated with a key and certificate to authenticate API requests. The most common technique to authenticate requests is through X.509 certificates.
Authorization with RBAC
Once an API request is authenticated, the next step is to determine whether the operation is allowed or not.
For authorizing a request, Kubernetes Role Based Access Control (RBAC) looks at three aspects: 1.the username of the requester 2.the requested action 3.and the object affected by the action
The username is extracted from the token embedded in the header, the action is one of the HTTP verbs like GET, POST, PUT, DELETE mapped to CRUD operations, and the object is one of the valid Kubernetes objects such as a pod or a service.
The requester can be of type:
user
group
serviceaccount
You can evaluate what you are allowed to perform in Kubernetes using:
This command is limited to ask from a users' prospective. If you want to ask the other way around you may use kubectl-who_can:
or evaluate role bindings for a subject using rbac-lookup:
Service accounts
While X.509 certificates are used for authenticating external requests, service accounts are meant to authenticate processes running within the cluster. Service accounts are associated with pods that make internal calls to the API server.
Every Kubernetes installation has a service account called default that is automatically associated with every running pod.
By issuing the following command you can check which role bindings and effective roles are bound to the default service account:
You can list all service accounts using this:
Such service account is pointing to a secret that is mounted inside every pod. This secret contains the token expected by the API Server:
To see the authorization in action we will spin up a special container with a shell:
Now let us explore the serviceaccount folder with the mounted secret as token and then set some environment variables for
CA_CERT: Pointing to the certificate for authentication
TOKEN: Pointing to the token for the authorization
NAMESPACE: The target kubernetes namespace
Now we can try to reach the API server of kubernetes with a request:
This should return a similar response to this:
Kubernetes follows the convention of the least privilege principle which means that by default no user or service account has any permissions.
This is why we get the 403 status and are not authorized for this request.
Now exit this container and let's fix this issue.
To authorize the default service account to list all the services via the Kubernetes API server usually you would create a special role just to view services and bind this role to the service account.
To make it easier for now we just bind our service account to the predefined view cluster role.
You may look into the created role binding:
Now restart the same container again as before an retry the same steps inside the container as before.
Then set again the required environment variables:
Now again try to reach the API server of kubernetes with a request:
This time the request should succeed and should return a similar response like this:
Note: Parts of this paragraph have been taken from a tutorial series at TheNewStack.
Deploy the application
The corresponding container image is pulled from andifalk/hello-rootless-jib docker hub repository.
The application is deployed using the following deployment yaml file deploy.yaml:
Please note that the all security context settings have been removed here as the same will be enforced by a cluster-wide pod security policy instead later.
Deploy the application using Pod Security Policy
Add a Security policy
Before enabling the Pod Security Policy admission controller there has to be at least one Pod Security Policy in place that our Pod must authorize against.
Otherwise if we would enable the admission controller beforehand the Pod would be declined to run completely.
We will add a new policy prohibiting privileged containers with root access completely:
To add this policy just execute:
Then we have to create a corresponding role for the policy.
After this we have to create a new service account (which we will use in our deployment later).
Now we can finally create a role binding between the policy role and the service account:
Now this has to be applied to K8s:
Now we can update the kubernetes cluster to enable pod security policy admission controller:
After the update is finished (takes some minutes) we can deploy our application:
Now this should successfully be deployed as it is compliant and authorized for the new pod security policy.
Deploy the application without Pod Security Policy
If you deploy the application via deploy-without-policy.yaml you will notice that this application deployment denied due to the pod security policy.
Last updated