Golden Gate Bridge

It's a tale as old as time. You have a sparkling new Kubernetes cluster, and you want to give some of your users access to it. But you don't want to give them the keys to the kingdom. You want to give them just enough access to do what they need to do, and no more. This is where Role-Based Access Control (RBAC) comes in. RBAC is a method of regulating access to computer or network resources based on the roles of individual users within your organization. It's a way to ensure that only the right people have access to the right resources at the right times. In this post, we'll take a look at how RBAC works in Kubernetes, and how you can use it to secure your cluster.

In Kubernetes, roles come in two flavors: Role and ClusterRole. On the surface they are very similiar, but they have on major distinciton: scope. A Role is specific to a namespace, while a ClusterRole grants access cluster-wide. Let's take a look at a simple example of a Role. Let's say our developer friend needs only needs to get access to exec into pods in their namespace exciting-app to debug code related issues. We can create a Role that grants them just the access they need and no more. As an example we could create a Role that looks like this:

  

---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: exciting-app
  name: pod-exec
rules:
- apiGroups: [""]
  resources: ["pods", "pods/logs"]
  verbs:
    - get
    - list
    - watch
- apiGroups: [""]
  resources: ["pods/exec"]
  verbs:
    - create

  

This role grants the developer access to get, list, and watch pods and pod logs, as well as exec into pods. Since specifed the namespace as exciting-app, this role will only apply to that namespace. If we wanted to grant the developer access to exec into pods cluster-wide, we would use a ClusterRole instead. Now that we have the role we can bind it to a user or group using a RoleBinding or ClusterRoleBinding. These users and groups will have been created in your organization's identity provider, such as Active Directory or LDAP or added to the cluster using something like EKS's auth-config configMap. Let's take a look at an example of a RoleBinding that binds our previously created group exciting-app-developers to the pod-exec role we created earlier.

A few good thing to note about the Role and ClusterRole is the apiGroups field. This field is used to specify the API group that the resources belong to. How do you know what API group a resource belongs to? You can get a nice list of all the API groups and resources in your cluster by running the following command. It will give you an exhaustive list of all the resources in your cluster, including their API group, if they are namespaced, shortnames and the verbs you can use on them. This is one of my favorite commands to run when I'm working with a new cluster. It's a great way to get a lay of the land.

  

$ k api-resources -o wide
NAME                              SHORTNAMES           APIGROUP                       NAMESPACED   KIND                             VERBS
...
pods                              po                                                  true         Pod                              [create delete deletecollection get list patch update watch]
resourcequotas                    quota                                               true         ResourceQuota                    [create delete deletecollection get list patch update watch]
secrets                                                                               true         Secret                           [create delete deletecollection get list patch update watch]
serviceaccounts                   sa                                                  true         ServiceAccount                   [create delete deletecollection get list patch update watch]
validatingwebhookconfigurations                        admissionregistration.k8s.io   false        ValidatingWebhookConfiguration   [create delete deletecollection get list patch update watch]
customresourcedefinitions         crd,crds             apiextensions.k8s.io           false        CustomResourceDefinition         [create delete deletecollection get list patch update watch]
controllerrevisions                                    apps
...

  

This is a highly truncated list of the resources in a cluster, but it gives you a good idea of how to read the output. The NAME column is the name of the resource, the SHORTNAMES column is a list of shortnames for the resource, but the APIGROUP and VERBS columns are the most important. The APIGROUP column gives you the information you'll need to use to fill in the apiGroups field in your Role or ClusterRole. The VERBS column gives you the last bit of the information you need to configure the role. Now that we know where all the information is coming from, let's take a look at the RoleBinding.

  

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-exec-binding
  namespace: exciting-app
subjects:
- kind: Group
  name: exciting-app-developers
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-exec
  apiGroup: rbac.authorization.k8s.io

  

The RoleBinding is pretty straightforward. We're binding the exciting-app-developers group to the pod-exec role. There is no real magic here. It's just a way to bind a user or group to a Role or ClusterRole. If we wanted to bind the group to a ClusterRole, we would change the kind from RoleBinding to a ClusterRoleBinding. Once we apply these resources to the cluster, the exciting-app-developers group will have the access they need to exec into pods in the exciting-app namespace. And that's it! That's all there is to it. You've now granted secure access to your developers to exec into pods in their namespace.

Let's try to take this one step further. We've configured the Role and RoleBinding, but how can we test that it's working? Without forcing the end user to try and exec into a pod, we can use the kubectl auth can-i command to test if the user has the access they need. Here is how we as admins can test if the exciting-app-developers group really has the access they need to do their jobs. Let's run the command and verify access before we hand it off to the developers.

  

$ k auth can-i exec pod -n exciting-app --as exciting-app-developers
yes

  

Awesome, now we know that we can hand off our configuration with confidence. We've tested it and we know it works.

Posts + Projects