RBAC in kubernetes

Reading Time: 4 minutes

Starting with Kubernetes version 1.6.0, cluster security was ramped up considerably. In earlier versions, if you managed to acquire the authentication token from one of the pods, you could use it to do anything you want in the cluster. RBAC in kubernetes prevents unauthorized users from viewing or modifying the cluster state. The default ServiceAccount isn’t allowed to view cluster state, let alone modify it in any way, unless you grant it additional privileges. In addition to RBAC, Kubernetes also includes other authorization plugins, such as the Attribute-based access control (ABAC) plugin, a WebHook plugin and custom plugin implementations. RBAC is the standard, though. 

 RBAC authorization plugin

The Kubernetes API server can be configured to use an authorization plugin to check whether an action is allowed to be performed by the user requesting the action. Because the API server exposes a REST interface, users perform actions by sending HTTP requests to the server. Therefore, users authenticate themselves by including credentials in the request (an authentication token, username and password, or a client certificate).

Understanding Actions

As we know, REST clients send GET, POST, PUT, DELETE, and other types of HTTP requests to specific URL paths, which represent specific REST resources. In Kubernetes, those resources are Pods, Services, Secrets, and so on. Here are a few examples of actions in Kubernetes:  

  1. Get Pods  
  2. Create Services
  3. Update Secrets

The verbs in those examples (get, create, update) map to HTTP methods (GET, POST, PUT) performed by the client. The nouns (Pods, Service, Secrets) obviously map to Kubernetes resources. An authorization plugin such as RBAC, which runs inside the API server, determines whether a client is allowed to perform the requested verb on the requested resource or not.

RBAC resources in kubernetes

The RBAC authorization rules in Kubernetes are configured through four resources, which can be grouped into two groups: 

  • Roles and ClusterRoles, which specify which verbs can be performed on which resources.  
  • RoleBindings and ClusterRoleBindings, which bind the above roles to specific users, groups, or ServiceAccounts. 

Roles define what can be done, while bindings define who can do it. 

The distinction between a Role and a ClusterRole, or between a RoleBinding and a ClusterRoleBinding, is that the Role and RoleBinding are namespaced resources, whereas the ClusterRole and ClusterRoleBinding are cluster-level resources (not namespaced). 

DEMO:

Let’s start by creating namespaces, ns-1 and ns-2:

kubectl create namespace ns-1 
kubectl create namespace ns-2 

I assume you have created a service account with default configurations. 
Currently SA does not have a permission to view pods, so let’s provide the permissions to view pods in ns-1.

Create a role:

kubectl create role pod-reader \
--verb=get \
--verb=list \
--verb=watch \
--resource=pods \
--namespace=ns-1

Create role binding:

kubectl create rolebinding <role-binding-name> --role=<role-name> --user=<service-account> --namespace=ns-1

This role-binding will bind the role to the service account. 

Example:
kubectl create rolebinding pod-reader-binding --role=pod-reader --user=user1@rbac-412504.iam.gserviceaccount.com --namespace=ns-1

This role provides the service account with the permissions to get, list and watch the pods running in namespace ns-1. 

Now, you can check the pods running in ns-1 from the service account.
kubectl get pods --namespace=ns-1
No resources found.

It will give the above message because we haven’t deployed any pods yet.

Let’s try to create a nginx pod from the service account.
kubectl run nginx --image=nginx:latest --namespace=ns-1

It will result in the following error message:
Error from server (Forbidden): pods is forbidden: User “user1@rbac-412504.iam.gserviceaccount.com” cannot create resource “pods” in API group “” in the namespace “ns-1”: requires one of [“container.pods.create”] permission(s).

The above message will be displayed because the user has got no permissions to create a pod. It clearly says so in the above statement as well: requires one of [“container.pods.create”] permission(s).

Run the nginx pod from the admin account:

kubectl run nginx --image=nginx:latest --namespace=ns-1

Check the pods from the Service account: 
kubectl get pods --namespace=ns-1

NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0         5s


This is what you get because the service account has the permissions to list the pods in namespace ns-1.


Let us try binding the same role in a different namespace ns-2.

kubectl create rolebinding pod-reader-binding2 --role=pod-reader --user=user2@shadow-297604.iam.gserviceaccount.com --namespace=ns-2 

It will give a message that it has bound successfully, but it won’t work. You can check by listing the pods from the service account in namespace ns-2.
It will give an error message saying that this account is not authorised to perform this action and it would require permissions.

That simply means that you cannot attach a role that is created in a different namespace to bind in another namespace. 

Therefore, we require cluster roles that are not specific to namespaces.

Create a cluster role:

kubectl create clusterrole deployment-reader \
    --verb=get \
     --verb=list \
     --verb=watch \
     --resource=deployments


Notice here, we need not to specify any namespace since the cluster role is not restricted to a namespace. If we create a role and do not specify a namespace, that automatically goes to default namespace and is therefore restricted to that namespace. So we explicitly mention clusterrole.

Create a role binding for namespace=ns-1
kubectl create clusterrolebinding deployment-reader-binding --clusterrole=deployment-reader --user=user1@rbac-412504.iam.gserviceaccount.com --namespace=ns-1

Create a role binding for namespace=ns-2
kubectl create clusterrolebinding deployment-reader-binding --clusterrole=deployment-reader --user=user2@rbac-289351.iam.gserviceaccount.com --namespace=ns-2

Check the deployments in namespaces ns-1 and ns-2
kubectl get deployments --namespace=ns-1
kubectl get deployments --namespace=ns-2


Both will result in No resources found, as we have not created any deployments yet.
Additionally, to check the roles in all namespaces:
kubectl get roles --all-namespaces

Combinations of roles and bindings:
For accessingRole Type to useBinding Type to use
Cluster-level resources (Nodes, PersistentVolumes, …)ClusterRoleClusterRoleBinding
Non-resource URLs (/api, /healthz, …)ClusterRoleClusterRoleBinding
Namespaced resources in any namespace (and across all namespaces)ClusterRoleClusterRoleBinding
Namespaced resources in a specific namespace (reusing the same ClusterRole in multiple namespaces)ClusterRoleRoleBinding
Namespaced resources in a specific namespace (Role must be defined in each namespace)RoleRoleBinding

References:

https://kubernetes.io/docs/
Book: Kubernetes in Action

Written by 

Vidushi Bansal is a Software Consultant [Devops] at Knoldus Inc. She is passionate about learning and exploring new technologies.