Understanding RBAC in Kubernetes

Understand how RBAC (Role Based Access Control) works in Kubernetes. Implement RBAC and make sure things are working as expected.

Understanding RBAC in Kubernetes

RBAC overview

RBAC or Role Based Access Control is one way of implementing access control in Kubernetes. RBAC can be scoped either to a specific namespace or the whole cluster.

Namespace scoped RBAC

The RBAC rules are scoped to a specific Kubernetes namespace and apply only for resources belonging to that namespace. We use this for instance when we want to give a user or service account permissions to do something on some resources only inside a specific namespace. To implement namespace scoped RBAC, we use the Role and RoleBinding resources.

The Role and RoleBinding resources have to be created inside the namespace we want to limit RBAC in.

The Role resource defines the permissions. For instance, the permission to list pods. The RoleBinding resource associate permissions to a user, a group or a service account. The associated user, group or service account will then be granted permissions defined inside the Role resource and therefore be authorized to perform the associated actions inside a specific namespace.

Cluster scoped RBAC

The RBAC rules are not limited to specific namespaces and apply to the whole Kubernetes cluster. We use this for instance when we want to give a user, service account... permissions to do something on some resources inside the entire cluster. To implement cluster scoped RBAC, we use the ClusterRole and ClusterRoleBinding resources.

The ClusterRole resource defines the permissions. For instance, the permission to list pods. The ClusterRoleBinding resource associate permissions to a user, a group or a service account. The associated user, group or service account will then be granted permissions defined inside the ClusterRole resource and therefore be authorized to perform the associated actions at the cluster level.

Implementing RBAC

Role or ClusterRole resources

Here is a sample Role or ClusterRole resource manifest :

kind: Role # or ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: podsReader
  namespace: mynamespace # only for Role resource 
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]

This sample can be used to create a Role or ClusterRole resource by simply setting the appropriate kind (Role or ClusterRole) and not using metadata.namespace for ClusterRole resource as that resource can't be put into namespaces.

The rules section is the most interesting one because that's where we define the permissions. We need the following elements to define the permissions :

  • apiGroups : a list of API groups of the resources we want to set access control for, for instance apps, batch... Next paragraph describes how to easily find this information for specific resources
  • resources : a list of resources types we want to set access control for (deployments, secrets, pods...)
  • verbs : actions that can be performed on the resources. We can find a list of available verbs, their descriptions and HTTP verbs equivalent here

To show a list of resources supported by our Kubernetes cluster and the associated apiGroups, we can use the kubectl api-resources command. Here is an example :

$ kubectl api-resources
NAME                         SHORTNAMES   APIVERSION    NAMESPACED   KIND
(...)
namespaces                   ns           v1            false        Namespace
nodes                        no           v1            false        Node
persistentvolumeclaims       pvc          v1            true         PersistentVolumeClaim
persistentvolumes            pv           v1            false        PersistentVolume
pods                         po           v1            true         Pod
(...)
controllerrevisions                       apps/v1       true         ControllerRevision
daemonsets                   ds           apps/v1       true         DaemonSet
deployments                  deploy       apps/v1       true         Deployment
replicasets                  rs           apps/v1       true         ReplicaSet
statefulsets                 sts          apps/v1       true         StatefulSet
(...)

The NAME column indicates the name of the resources supported by our Kubernetes cluster. The APIVERSION column is composed of the apiGroups followed by a version after the slash separator. For the deployments resource for instance, the apiGroups value is apps.

Sometimes the apiGroups value is not present inside the APIVERSION column. This is the case for instance for the pods resource. This means that the resource belong to the core API group and the value to use for apiGroups in our Role/ClusterRole resource definition is "", as shown in the previous Role/ClusterRole sample resource manifest.

RoleBinding or ClusterRoleBinding resources

Here is a sample RoleBinding or ClusterRoleBinding resource manifest :

kind: RoleBinding # or ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: podsReader
  namespace: mynamespace # only for RoleBinding resource 
subjects:
- kind: ServiceAccount # or User or Group
  name: myserviceaccount
  namespace: mynamespace
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role # or ClusterRole
  name: podsReader

This sample can be used to create a RoleBinding or ClusterRoleBinding resource by simply setting the appropriate kind (RoleBinding or ClusterRoleBinding) and not using metadata.namespace for ClusterRoleBinding resource as that resource can't be put into namespaces.

It associates an existing Role or ClusterRole resource to an existing service account, in order to grant the service account, permissions defined inside the Role or ClusterRole resource.

Here is an explanation of the contents of subjects and roleRef fields :

  • subjects : define the subject(s) on which to bound a specific Role or ClusterRole resource
    • kind : the type of the subject. Can be User, Group or ServiceAccount
    • name : the name of the subject (a User name, Group name or ServiceAccount name)
    • namespace : the namespace where to find the subject (only for ServiceAccount Kind)
  • roleRef : the Role or ClusterRole that will be bound to the subject
    • apiGroup : most of the time rbac.authorization.k8s.io
    • kind : the type of the role reference. Can be Role or ClusterRole
    • name : the name of the Role or ClusterRole that will be bound to the subject

Testing RBAC using impersonation

Once we have configured RBAC to authorize access to specific Kubernetes resources for some users, groups or service accounts, the next thing to do is to test that everything is working as expected.

Having a way to do so whithout asking users to perform specific actions or setting up pods with specific service accounts to verify the access is more convenient. This is where Kubernetes impersonation feature comes in.

Thanks to Kubernetes impersonation feature, we can take the identity of another user, a group or a service account to perform specific actions (list pods inside a specific namespace for instance) and therefore make sure RBAC is properly configured.

The user we perform actions as can be a real user from an identity provider system (GCP IAM user for instance) or a non existing/virtual one. The user taking identity of another user (real or fake/virtual user), a group or a service account, first have to be authorized to do so with a ClusterRole and associated ClusterRoleBinding as follows :

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: impersonation
rules:
- apiGroups: [""] # the core API group
  resources: ["user"] # or group or serviceaccount
  # Users, groups or serviceaccount name(s)
  resourceNames: ["user-to-impersonate@mycompany.com"] 
  verbs: ["impersonate"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: impersonation
subjects:
- kind: User # or Group or ServiceAccount
  name: user-that-impersonate@mycompany.com
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: impersonation

User and group resources, most of the time are custom resources available only when we use Managed Kubernetes service from Cloud Providers like GCP, AWS... and correspond to users and groups available inside the IAM (Identity and Access Management) service they provide for users, groups and services access management.

The previous sample manifest allows the user identified by user-that-impersonate@mycompany.com email address to take the identity of the user identified by user-to-impersonate@mycompany.com email address. We can use the same sample manifest to also authorize impersonation of a group or service account.

Then, user-that-impersonate@mycompany.com can configure RBAC for user-to-impersonate@mycompany.com and test the configuration by taking the identity of user-to-impersonate@mycompany.com using the following kubectl commands :

# Run a Kubectl command as another user (--as) or group (--as-group)
$ kubectl --as user-to-impersonate@mycompany.com get pods -n frontend

# Test if a specific Kubectl command will work... whithout actually running it
kubectl auth can-i get pods -n frontend

# Same thing by taking another user account identity
kubectl auth can-i get pods -n frontend --as user-to-impersonate@mycompany.com

That's all. We now have the essentials knowledges required to understand, implement and test RBAC in Kubernetes.