The Spice Kaffein must flow

Kubernetes RBAC Concepts

A brief introduction to Kubernetes RBAC and its associated logical application identity objects. This model provides a different perspective than “standard” human identity User and Group definitions.

Jan 11, 2022

What is RBAC?

RBAC (role based access control) is a security approach to restricting system resources to specific subjects via access lists. RBAC in Kubernetes allows admins to delegate specific types of permissions against specific API objects to other specific API objects. This is accomplished via interactions between three specific object types:

  • Role/ClusterRole
  • RoleBinding/ClusterRoleBinding
  • ServiceAccount/User/Group

ServiceAccounts, Users, and Groups are ways to assign an identity to a subject. ServiceAccounts are basically proxy actors that can be assigned to pods to help grant them a concrete RBAC identity and thus a way to be granted access to specific resources. These are the primary identity object that Kubernetes admins interact with. ServiceAccounts are explicitly namespaced, so multiple ServiceAccounts with the same name can be created across different namespaces and each is actually a distinct identity. Along with User and Groups objects, these guys define the who.

Note: User and Group objects are kind of weird and annoying because there’s not a way to directly query them and see which Users and Groups exist and which permissions they have. So I’m going to effectively ignore them from here on out.

Roles and ClusterRoles are effectively buckets for rules that define the specific API objects (resources) within different API groups (apiGroups) that are able to be acted upon and describe how (verbs) they can be acted upon. Roles are scoped to specific namespaces, while ClusterRoles are scoped to entire clusters. These guys define the what.

RoleBindings and ClusterRolesBindings act like the glue that connect the who to the what.

Give me an example

Alright sure, let’s talk specifics. Argocd is a popular gitops project that provides automation mechanisms to make deployments in kubernetes truly declarative and continuous.

Really awesome stuff.

Anyways, it has a few different installation flavors (which is not really relevant to this discussion so we won’t go into the details here), but for this example we are specifically looking at the server component’s installation manifests.

With our reference material in place to follow along with, the overall process for creating RBAC components and associating them to workloads looks like this:

  1. Give your workload an identity via a ServiceAccount
  2. Attach the identity to your workload
  3. Figure out what API resources you want your workload to be able to access, and define those interactions in a Role
  4. Explicitly connect the permissions to the workload identity using a RoleBinding

1. I’m gonna need to see some ID

A ServiceAccount is pretty straightforward, it acts as an authentication identity the same way your drivers license does when you’re trying to get into that exclusive club that just opened up downtown (“Alright you can come in”). It also acts as a thing to attach specific permissions to (“Yes you’re granted access to the VIP lounge”).

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/name: argocd-server
    app.kubernetes.io/part-of: argocd
    app.kubernetes.io/component: server
  name: argocd-server

2. I’m rubber and you’re glue

A workload can only be associated with a single ServiceAccount identity at any given time (although the inverse is not true), which is done by explicitly declaring the ServiceAccount to load in the workload manifest.

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: argocd-server
    app.kubernetes.io/part-of: argocd
    app.kubernetes.io/component: server
  name: argocd-server
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: argocd-server
  template:
    metadata:
      labels:
        app.kubernetes.io/name: argocd-server
    spec:
      serviceAccountName: argocd-server
#<.... Truncated for brevity ....>

Any workload that does not define a ServiceAccount actually just inherits the namespaces default ServiceAccount.

3. Role-o oh Role-o, wherefore art thou Role-o

The argocd server needs to operate on specific Kubernetes API objects in order to do its job and provide value to the team who wants to use it, but we want to give the argocd server only as much permission as it needs and nothing extra. So we create a Role object and inside describe exactly what API objects the argocd server can interface with and what actions the workload can take on them.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  labels:
    app.kubernetes.io/name: argocd-server
    app.kubernetes.io/part-of: argocd
    app.kubernetes.io/component: server
  name: argocd-server
rules:
- apiGroups:
  - ""
  resources:
  - secrets
  - configmaps
  verbs:
  - create
  - get
  - list
  - watch
  - update
  - patch
  - delete
- apiGroups:
  - argoproj.io
  resources:
  - applications
  - appprojects
  verbs:
  - create
  - get
  - list
  - watch
  - update
  - delete
  - patch
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - list

This looks like a lot is going on here but once you break it down it’s actually quite straightforward. Here we are defining a list of permissions named argocd-server and this list of permissions is granting:

  • full permissions to argocd for Secret and ConfigMap API objects
  • full permissions on some new argocd-specific custom resource objects Applications and AppProjects
  • the ability to create and list Kubernetes Events

4. That rug RoleBinding really tied the room together

RoleBindings act as pure glue in this loosely coupled system, connecting a Role to a ServiceAccount subject (or multiple ServiceAccounts if need be!).

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  labels:
    app.kubernetes.io/name: argocd-server
    app.kubernetes.io/part-of: argocd
    app.kubernetes.io/component: server
  name: argocd-server
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: argocd-server
subjects:
- kind: ServiceAccount
  name: argocd-server

In this case we are assigning the argocd-server Role to the argocd-server ServiceAccount subject, and the link between the two is the argocd-server RoleBinding.