Kubernetes(K8s) role-based access control is a powerful tool in restricting access to resources within a Kubernetes cluster. In this post, we shall briefly discuss what role-based access control is, and how to set it up in Kubernetes. I promise, it's not as long a process as you may think.
Role-based access control(RBAC) is a security model in which users are assigned roles, and can then be granted access to certain resources based on those roles. For example, an organisation can have a role-based access control system that allows DevOps engineers to perform privileged operations within the entire Kubernetes cluster, while restricting the application developers to only viewing information about their applications deployed in a given namespace.
Before setting up RBAC in Kubernetes, let's review some of the key concepts that we are going to be dealing with:
Now let us see how we can set up RBAC in Kubernetes.
First, let us create a namespace which we are going to be working with. Let's call it dev-env.
kubectl create namespace dev-env
Enter fullscreen mode Exit fullscreen mode
Next, create a service account called app-dev which we shall use all through out.
kubectl create serviceaccount app-dev --namespace dev-env
Enter fullscreen mode Exit fullscreen mode
We shall follow this up by creating an admin role that has all rights within the dev-env
namespace. Below is its manifest, which is also available on GitHub.
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: admin
namespace: dev-env
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
Enter fullscreen mode Exit fullscreen mode
Apply the file to create the admin role.
kubectl apply -f https://raw.githubusercontent.com/123MwanjeMike/k8s-rbac/main/admin-role.yaml
Enter fullscreen mode Exit fullscreen mode
Note: We shall be creating the rest of the Kubernetes resources in this tutorial from the pre-written manifest files in this repository as we have done above. However, you may also edit these manifests if you wish to create K8s resources tailored to your needs.
A list of Kubernetes resources for setting up of role-based access control in the article Set up Kubernetes role based access control
Next,create a rolebinding, app-dev-rolebinding, of the admin
role to the app-dev
service account. Below is the manifest.
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: app-dev-rolebinding
namespace: dev-env
subjects:
- kind: ServiceAccount
name: app-dev
namespace: dev-env
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: admin
Enter fullscreen mode Exit fullscreen mode
Run the command below to create it.
kubectl apply -f https://raw.githubusercontent.com/123MwanjeMike/k8s-rbac/main/rolebinding.yaml
Enter fullscreen mode Exit fullscreen mode
Our service account is now an admin within the dev-env
namespace. We can even go further and define access rights for it across the entire cluster. Let's say, basing on our DevOps engineer and application developer example we had at the start, that we want our application developers to view any resource cluster wide and even to use the Kubernetes dashboard. How we can we do this?
For the first part, we're in luck! Kubernetes has a default view clusterrole which can be used for viewing of all resources in a cluster; and so we shall just leverage this. We shall create a clusterrolebinding, app-dev-view
, that does just that.
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: app-dev-view
subjects:
- kind: ServiceAccount
name: app-dev
namespace: dev-env
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: view
Enter fullscreen mode Exit fullscreen mode
Create the clusterrolebinding
kubectl apply -f https://raw.githubusercontent.com/123MwanjeMike/k8s-rbac/main/clusterrolebindings/view.yaml
Enter fullscreen mode Exit fullscreen mode
Now, for app-dev
to access the Kubernetes dashboard, we could easily just create a bind the edit
default clusterrole to it since it has the access rights needed for this. However, this would also give the service account more permissions than it should have and so we want to use a more fine-grained clusterrole in accordance to the principle of least privileges.
So, we shall create a custom clusterrole with only the required permissions needed to access the K8s dashboard on top of those already held by the service account through default view
clusterrole.
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: view-addition-for-k8s-dashboard-access
rules:
- apiGroups: [""]
resources: ["pods/attach", "pods/exec", "pods/portforward", "pods/proxy", "services/proxy"]
verbs: ["get", "list", "watch", "create"]
- apiGroups: [""]
resources: ["services"]
verbs: ["proxy"]
Enter fullscreen mode Exit fullscreen mode
Run the command below to create the view-addition-for-k8s-dashboard-access
clusterrole with the above definition.
kubectl apply -f https://raw.githubusercontent.com/123MwanjeMike/k8s-rbac/main/custom-clusterrole.yaml
Enter fullscreen mode Exit fullscreen mode
We can now bind view-addition-for-k8s-dashboard-access
clusterrole to the app-dev
service account for it access the K8s dashboard. Let's have a look at the clusterrolebinding manifest for this.
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: app-dev-use-k8s-dashboard
subjects:
- kind: ServiceAccount
name: app-dev
namespace: dev-env
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: view-addition-for-k8s-dashboard-access
Enter fullscreen mode Exit fullscreen mode
Create the app-dev-use-k8s-dashboard
clusterrolebinding
kubectl apply -f https://raw.githubusercontent.com/123MwanjeMike/k8s-rbac/main/clusterrolebindings/use-k8s-dashboard.yaml
Enter fullscreen mode Exit fullscreen mode
Our app-dev
service account can now be used by our "application developers" to create applications in the dev-env
namespace and conveniently access the k8s dashboard.
We are going to need a token for the app-dev
service account and so to get it, run the commands below
export NAMESPACE="dev-env"
export SERVICE_ACCOUNT="app-dev"
kubectl -n ${NAMESPACE} describe secret $(kubectl -n ${NAMESPACE} get secret | (grep ${SERVICE_ACCOUNT} || echo "$_") | awk '{print $1}') | grep token: | awk '{print $2}'\n
Enter fullscreen mode Exit fullscreen mode
Your output will be some long string. It should start with something similar to what I have below. Save that token somewhere temporarily.
Next, get the certificate data by running the command below in the same terminal where you had defined the NAMESPACE and SERVICE_ACCOUNT variables.
kubectl -n ${NAMESPACE} get secret `kubectl -n ${NAMESPACE} get secret | (grep ${SERVICE_ACCOUNT} || echo "$_") | awk '{print $1}'` -o "jsonpath={.data['ca\.crt']}"
Enter fullscreen mode Exit fullscreen mode
Your output will be another long string whose beginning is something similar to what I have below. Save that certificate data somewhere temporarily.
With these two, we let's create our kubectl config file. You might already have a *.kube/config *which you might still need. So, we shall back it up as .kube/config.bak and create a new one for the app-dev
. Run the commands below to do precisely that.
cd
mv .kube/config .kube/config.bak
nano .kube/config
Enter fullscreen mode Exit fullscreen mode
This will open the nano text editor. Fill in the template below paste in the editor. Make sure to substitute the certificate-data, server-ip-address, cluster-name, and token with the correct values before saving the changes. Remember to delete the token and certificate data from where you had temporarily saved them.
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: <certificate-data>
server: https://<server-ip-address>:6443
name: <cluster-name>
contexts:
- context:
cluster: <cluster-name>
namespace: dev-env
user: app-dev
name: <cluster-name>
current-context: dev-env
kind: Config
preferences: {}
users:
- name: app-dev
user:
client-key-data: <certificate-data>
token: <token>
Enter fullscreen mode Exit fullscreen mode
Run kubectl proxy
and click here to access the dashboard.
Sign in with the .kube/config we created in the previous step.
Attempt to create a user role in the dev-env namespace with the manifest below. All should go on well.
kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: test-admin namespace: dev-env rules:
Enter fullscreen mode Exit fullscreen mode
Attempt to create the user role in the kube-public namespace with the manifest below.
kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: test-admin namespace: kube-public rules:
Enter fullscreen mode Exit fullscreen mode
Tadaa
We did it. app-dev
has no such rights outside the dev-env
namespace. All application developers can now use that .kube/config file to gain controlled access to the cluster
In this post, we looked at how we can implement RBAC not only at the namespace level, but also at the cluster level. We specifically used a service account given that it is managed by Kubernetes taking away this task from us. It is also important to note that Kubernetes also user accounts as much as it does service accounts. One key difference between the two is that user accounts represent actual Kubernetes users unlike the service accounts.
I hope you enjoyed this article and that you'll show support of some sort as I'd greatly appreciate that. And if you have any thoughts or questions in relation to this, feel free to drop them via the comments section. I'd love to hear from you.
Happy hacking
Also published here.