How to set up Kubernetes RBAC

Pierre RAFFA
5 min readFeb 13, 2024

RBAC (Role-Based Access Control) in Kubernetes is a security mechanism, granting or restricting access based on user roles and permissions.
It ensures a fine-grained approach to safeguard Kubernetes clusters, preventing unauthorized actions.

RBAC can define permissions for:

  • users
  • groups
  • service accounts

Mastering RBAC in Kubernetes becomes essential for maintaining a secure and well-organized deployment. As company and teams grow, it’s important to restrict access to some developers/teams.

First, let’s dive into the RBAC components…

Here are the RBAC components managed by the Kubernetes API server:

ClusterRoles/Roles
These resources define sets of permissions within a namespace (Roles) or across the entire cluster (ClusterRoles). They specify what actions (verbs) are allowed on specific resources (API groups, resources, and subresources).

But… an important point here which can be counter intuitive…
ClusterRoles can also also be created as common sets of permissions bound to multiple namespaces.
Managing a smaller number of ClusterRoles compared to numerous Roles can simplify RBAC management, especially in larger clusters. It reduces the need to duplicate role definitions across multiple namespaces.

ClusterRoleBindings/RoleBindings
These resources associate roles or cluster roles with specific users, groups, or service accounts. RoleBindings are used to grant permissions within a namespace, while ClusterRoleBindings apply permissions globally across the entire cluster.

Native Cluster Roles

cluster-admin
Allows full access to all resources.
When used in a ClusterRoleBinding, it applies for all namespaces
When used in a RoleBinding, it applies only for a specific namespace.

I would have liked cluter-view to exist. If you need such clusterrole, you will have to build it by yourself, probably inspired from view Role + custom permissions for cluster-scope resources.

Native Roles

admin
Allows admin access, intended to be granted within a namespace using a RoleBinding with the ability to create roles and role bindings within the namespace.

edit
Allows read/write access to most objects in a namespace, intended to be granted within a namespace.
This role does not allow viewing or modifying roles or role bindings.

view
Allows read-only access to see most objects in a namespace, intended to be granted within a namespace. It does not allow viewing roles or role bindings.

With the ClusterRoles/Roles above, you have pretty much what you need to set the permissions for the different teams!

Let’s set up the permissions for production…

Our Engineering department is split into squads, and all squads share the namespace apps. Platform Engineers have super-user access.

Developers:

  • read-only access to list the namespaces (most of them uses Lens as Kubernetes IDE and this requires to get access to the list of namespaces)
  • read-only access to apps namespace

We need a specific ClusterRole for listing the namespaces. Let’s call it cluster-basic

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: company:cluster-basic
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list", "watch"]
- apiGroups:
- "apiextensions.k8s.io"
resources:
- "customresourcedefinitions"
verbs:
- "get"
- "list"
- "watch"

It’s also a good practice to prefix the RBAC components such as company:role-name

Let’s bind the ClusterRoles/Roles:

# Bind cluster-basic to the group `developers`
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: company:group:developers:cluster-basic
subjects:
- kind: Group
name: developers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: company:cluster-basic
apiGroup: rbac.authorization.k8s.io

As you can see, this configuration binds the cluster role company:cluster-basic to the group developers
We don’t specify any namespace because we grant privileges for cluster-scoped resources.

# Bind view to the group `developers`
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
name: company:group:developers:view
namespace: apps
data:
subjects:
- kind: Group
name: developers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: view
apiGroup: rbac.authorization.k8s.io

This configuration binds the Role viewto the group developers for the restricted namespace apps

Squad Leads:

  • read-only access to the cluster
  • elevated privileges with an adminaccess to appsnamespace
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: company:group:leads:cluster-basic
subjects:
- kind: Group
name: leads
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: company:cluster-basic
apiGroup: rbac.authorization.k8s.io

This bounds cluster-basic to leads

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: company:group:leads:view
subjects:
- kind: Group
name: leads
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: view
apiGroup: rbac.authorization.k8s.io

We could create a custom cluster-view for the Squad Leads but using view (normally used for namespaced resources) is good enough for us at the moment.
This gives read-only access to all namespaced resources but no access to cluster-scoped resources.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: company:group:leads:cluster-admin
namespace: apps
roleRef:
kind: Role
name: admin
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: Group
name: leads
apiGroup: rbac.authorization.k8s.io

This gives admin access to the restricted namespace apps
Note that you could have also bound cluster-admin to give access to the restricted namespace to achieve the same result. The cluster Role would act as a Role giving permissions to the namespaced resources

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: company:group:leads:cluster-admin
namespace: apps
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: Group
name: leads
apiGroup: rbac.authorization.k8s.io

Platform Engineers / Administrators:

  • super-user access to perform any action on any resource.

Pretty straight forward here as Kubernetes comes natively with the ClusterRole cluster-admin

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: company:group:platform:cluster-admin
subjects:
- kind: Group
name: platform
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io

Do you have Custom Resources some teams need to have privileges to?

No problem. You can combine rules from other ClusterRoles/Roles into ANY existing ClusterRole/Role by setting this annotation:

rbac.example.com/aggregate-to-{ROLE_NAME}: "true"

Remember the 3 natives Roles admin, edit, view I mentioned previously? We can automatically append new rules to them!
And this is really great in order to manage the bindings to the groups as we just need to bind one Role to a Group and this Role gets its rules updated.

Example with a ClusterRole set up to manipulate my Custom Resource Tenants.
Thanks to the annotation rbac.authorization.k8s.io/aggregate-to-admin, the rules will be appended automatically to admin Role.
Same for editRole.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: your-customer-role
labels:
app.kubernetes.io/component: rbac
app.kubernetes.io/created-by: my-operator
app.kubernetes.io/part-of: my-operator
rbac.authorization.k8s.io/aggregate-to-admin: "true"
rbac.authorization.k8s.io/aggregate-to-edit: "true"
rules:
- apiGroups:
- company.com
resources:
- tenants
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- company.com
resources:
- tenants/status
verbs:
- get

Once applied to your cluster, double check the rules for admin and edit Roles and you will see they got updated.

I hope this article will help you understand RBAC and how to use it to grant or restrict access to your teams.

Next time, I will show you how to test the RBAC configuration and make sure there is no regression.

--

--