As organizations adopt Kubernetes to manage their containerized applications, the need for robust security mechanisms has become more critical than ever. One of the foundational components of Kubernetes security is Role-Based Access Control (RBAC). This article delves into what RBAC is, how it works, and why it is indispensable for securing Kubernetes clusters.
What is RBAC?
Role-Based Access Control (RBAC) is a method of regulating access to resources based on the roles of individual users within an organization. In Kubernetes, RBAC is used to define what actions users or service accounts can perform on specific resources in the cluster. It provides a fine-grained control mechanism, ensuring that only authorized entities can access or modify resources.
How it works?
In Kubernetes, there are two types of accounts
User Account
Service Account
User account: User accounts are used to log into a Kubernetes cluster and manipulate resources therein. Each user account is associated with a unique set of credentials, which are used to authenticate the service’s requests.
Service Account: Kubernetes Service Accounts are specialised accounts used by applications and services running on Kubernetes to interact with the Kubernetes API.
Here are the simple terms to understand user & service accounts:
User Account: Represents a person accessing the cluster (e.g., via kubectl).
Service Account: Represents an application or pod accessing the cluster.
User Authentication: Managed externally (e.g., OIDC, certificates).
Service Account Authentication: Managed by Kubernetes with tokens.
User Scope: Cluster-wide.
Service Account Scope: Usually tied to a namespace.
Which account type should you use?
Use a User Account: When a human needs to interact with the Kubernetes cluster, such as developers, admins, or operators using tools like kubectl
.
Use a Service Account: When an application or workload running inside the cluster needs to access Kubernetes resources programmatically.
Ex: A pod might use a service account to access ConfigMaps or Secrets within a specific namespace.
Lets do some hands on:
Lets create a user, But Kubernetes API will not allow us to create user directly. so there are multiple ways to create user
client certificates
bearer tokens
authenticating proxy
HTTP basic auth.
I will choose client certificate to create a user which is very easy to create.
This certificates are used to create users. When a user perform any command like kubectl get po then K8's API will authenticate and authorize the request.
authentication: permission to login.
authorization: permission to work on resources.
Steps to create certificate:
lets create a folder:
mkdir mustafa-user && cd mustafa-user
Generate a key using openssl :
openssl genrsa -out mustafa.key 2048
Generate a Client Sign Request (CSR) :
openssl req -new -key mustafa.key -out mustafa.csr -subj "/CN=mustafa/O=group1"
Generate the certificate (CRT):
openssl x509 -req -in mustafa.csr -CA ~/.minikube/ca.crt -CAkey ~/.minikube/ca.key -CAcreateserial -out mustafa.crt -days 500
Steps to create user.
lets create a user:
kubectl config set-credentials mustafa --client-certificate=mustafa.crt --client-key=mustafa.key
Till now we created user and certificates, but we didn’t add that user to our cluster. Lets do it!
Set a context entry in kubeconfig:
kubectl config set-context my-context --cluster=minikube --user=mustafa
Context is used to switch the users in K8s cluster. Because in K8s we cant switch using users, we will add users to context and we will use context to switch b/w users.
To see the user:
kubectl config view
Switch to devops user:
kubectl config use-context my-context
Now lets check to create some resources
kubectl get po
kubectl run pod-1 --image=nginx
kubectl create ns dev
ok! thats cool, thats won’t work, just come back to minikube config and perform same commands, that will work. (kubectl config use-context minikube)
because we created user and attached that user to cluster. But we didn’t mention permissions for that user. minikube context is a admin user which will have all permissions by default
so lets create a role and attach that role to user.
There are four components to RBAC in Kubernetes:
roles
Cluster roles
role bindings
ClusterRolesBinding
- Roles are the basic building blocks of RBAC. A role defines a set of permissions for a user or group. For example, you might create a role called “admin” that gives the user or group full access to all resources in the cluster.
(or)
Role is a set of permissions that define what actions (verbs) are allowed on specific resources (API groups and resources) within a particular Namespace.
Roles are Namespace-scoped, meaning they apply only to resources within that Namespace.
ClusterRoles are special roles that apply to all users in the cluster. For example, you might create a ClusterRole called “cluster-admin” that gives the user or group full access to all resources in the cluster. These are not Namespace-specific. They define permissions for cluster-wide resources.
Role bindings connect users/groups to roles. For example, you might bind the “admin” role to the “admin” user. This would give the “admin” user all the permissions defined in the “admin” role.
It grants the permissions to particular namespaces only.
ClusterRoleBindings similar to RoleBindings, ClusterRoleBindings associate ClusterRoles with users/groups across the entire cluster.
These are not Namespace-specific. They grants the permissions for cluster-wide resources.
Lets create a namespace called dev :
kubectl create ns dev
Now lets create a role that gives permissions to K8s resources
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev
name: dev-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
apply it:
kubectl create -f role.yml
Imperative way :
kubectl create role admin --verb=get,list,watch,create,update,delete --resource=pods,deployments -n dev
Check it :
kubectl get role -n dev
Let me tell you the differences between get, list and watch
get:
Purpose: Allows you to retrieve a single resource or a specific instance of a resource.
Ex: kubectl get pod pod-name
list:
Purpose: Allows you to retrieve a list of resources, such as all pods in a namespace.
Ex: kubectl get pods
watch:
Purpose: Allows you to continuously monitor and receive updates when the state of a resource changes.
Ex: kubectl get pods --watch
Now attach this dev-role to user (Role binding):
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: dev-role-binding
namespace: dev
subjects:
- kind: User
name: mustafa
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: dev-role
apiGroup: rbac.authorization.k8s.io
apply it:
kubectl create -f rolebinding.yml
Imperative way :
kubectl create rolebinding role-binding-name --role=role-name --user=user-name
we can also check with the permissions :
check it:
kubectl get rolebinding -n dev
To check the permissions:
kubectl auth can-i delete pod --as mustafa
So far we added role and attached that role to user (role binding), Now when we go to dev namespace and login as devops user, we will able to work with pods and deployments only.
Switch to dev ns:
kubectl config set-context --current --namespace=dev
Login as devops user using context :
kubectl config use-context my-context
make sure to check check the configs before going to test the role
kubectl config view --minify
Now we can able to list or get the pods
Note: for only one namespace (dev).
Mustafa user cant get any resources from any other namespaces because we used rolebinding.
If mustafa want to access the resources from all namespaces we can use clusterrolebinding
Working on Cluster Role:
First lets change the context to minikube and go to default namespace
change the contex:
kubectl config use-context minikube
change the default namespace:
kubectl config set-context --current --namespace=default
Lets create cluster role:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: mustafa-cluster-role
rules:
- apiGroups: [""]
resources: ["pods", "deployments"]
verbs: ["get", "watch", "list", "create"]
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "watch", "list", "create", "delete"
apply it:
kubectl create -f clusterrole.yml
Imperative way :
kubectl create clusterrole my-cluster-role --verb=get,list,create,update,delete --resource=pods,services
Check it :
kubectl get clusterrole
Lets create cluster role binding:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-role-binding
subjects:
- kind: User
name: mustafa
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: mustafa-cluster-role
apiGroup: rbac.authorization.k8s.io
After creating the clusterrole and attached that role to cluster role binding, its time to check weather mustafa user can have access to work with resources in all namespaces or not.
Best Practices for RBAC Implementation
Follow the Principle of Least Privilege: Grant users only the permissions they absolutely need.
Use Namespaces: Leverage namespaces to scope access controls effectively.
Audit and Monitor: Regularly audit RBAC policies and monitor access logs to identify potential vulnerabilities.
Automate Policy Management: Use tools like Helm or Kubernetes operators to automate and enforce RBAC policies.
Regular Reviews: Periodically review and update roles and bindings to adapt to changing requirements.
Common Mistakes to Avoid
Over-Permissioning Users: Assigning overly broad permissions, such as granting admin roles to non-administrative users.
Ignoring Service Accounts: Neglecting to secure service accounts can lead to unintended access.
Unmonitored RoleBindings: Failing to track and monitor RoleBindings and ClusterRoleBindings.
Conclusion
RBAC is a cornerstone of Kubernetes security, providing the control needed to safeguard resources in a multi-user environment. By implementing RBAC effectively and adhering to best practices, you can significantly enhance the security posture of your Kubernetes clusters.
Ready to implement RBAC in your Kubernetes setup? Let me know your thoughts or questions in the comments below!
If you love stories that inspire learning, growth, and productivity, consider subscribing for more! If this article added value to your journey, your support would mean the world to me — only if it’s within your means. Let’s stay connected on LinkedIn too. Thank you for reading!