This is the sixth tutorial from the Kubernetes Tutorial Series. In this article we will learn how Role Based Access Control works in Kubernetes. Other articles from this series:

Introduction

You can’t just give every user full Administrator privileges for your Kubernetes Cluster. This is not a best practice and also your cluster is more vulnerable this way. You need some way by which you can achieve the below points:

  • Have multiple users with different properties, establishing a proper authentication mechanism.
  • Have full control over which operations each user or group of users can execute.
  • Have full control over which operations each process inside a pod can execute.
  • Limit the visibility of certain resources of namespaces.

And, Kubernetes has API Objects which can help us in specifying fine-grained access to users. These are called Roles and RoleBindings.

Before going into detail of Roles and Rolebindings, we need to have knowledge about three essential elements:

  • Subject: The set of users and processes that want to access the Kubernetes API.
  • Resources: The set of Kubernetes API Objects available in the cluster. Examples include Pods, Deployments, Services, Nodes, and PersistentVolumes, among others.
  • Verbs: The set of operations that can be executed to the resources above. Different verbs are available (examples: get, watch, create, delete, etc.), but ultimately all of them are Create, Read, Update or Delete (CRUD) operations.

With these three elements in mind, the key idea of RBAC is to connect subjects, resources and verbs. In other words, we want to specify, given a user, which operations can be executed over a set of resources.

Subject, Verb, Resource

Let’s dive deeper into how Roles and RoleBindings help us in achieving this.

Role and ClusterRole

In the RBAC API, a role contains rules that represent a set of permissions. Permissions are purely additive (there are no “deny” rules). A role can be defined within a namespace with a Role, or cluster-wide with a ClusterRole.

A Role can only be used to grant access to resources within a single namespace.

A ClusterRole can be used to grant the same permissions as a Role, but at a cluster level. This means that a ClusterRole can be used grant permission across all the namespaces, nodes etc.

Let’s look at some examples:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

The above Role grants read access (get, list, watch) to Pods in the default namespace. Let’s now look at a ClusterRole.

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  # "namespace" omitted since ClusterRoles are not namespaced
  name: pod-reader-ns
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

The above ClusterRole grants read access to Pods across all the namespaces. Notice how we haven’t specified any namespace in the above yaml file.

Now, you have learned how to connect resource with verbs (operations). Let’s now look how to connect these Roles with RoleBindings.

RoleBinding and ClusterRoleBinding

A role binding grants the permissions defined in a role to a user or set of users. It holds a list of subjects (users, groups, or service accounts), and a reference to the role being granted. Permissions can be granted within a namespace with a RoleBinding.

ClusterRoleBinding may be used to grant permission at the cluster level and in all namespaces.

Let’s look at some examples.

# This role binding allows "sam" to read pods in the "default" namespace.
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: User
  name: sam # Name is case sensitive
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role #this must be Role or ClusterRole
  name: pod-reader # this must match the name of the Role or ClusterRole you wish to bind to
  apiGroup: rbac.authorization.k8s.io

The above RoleBinding grants the “pod-reader” role which we created earlier to the user “sam” within the “default” namespace. This allows “sam” to read pods in the “default” namespace. Let’s break down the above yaml file:

  • kind is RoleBinding
  • apiVersion is rbac.authorization.k8s.io/v1
  • In the metadata section we specify the name of the RoleBinding and the namespace within which it will be applicable.
  • The subjects sections specifies the user or group that needs the permission.
  • roleRef is the most important part of this file. It is responsible for actually creating the binding. The kind will be either Role or ClusterRole, and the name will reference the name of the specific Role or ClusterRole you want. In the example above, the RoleBinding is using roleRef to bind the user “sam” to the Role created above named pod-reader.

Let’s now look at a ClusterRoleBinding. The following ClusterRoleBinding is same as the above RoleBinding, just that it allows any user in the group “dev” to read pods in any namespace.

# This cluster role binding allows anyone in the "dev" group to read pods in any namespace.
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: read-pods-global
subjects:
- kind: Group
  name: dev # Name is case sensitive
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: pod-reader-ns
  apiGroup: rbac.authorization.k8s.io

Let’s see them in action

Now that you have learnt about Roles and RoleBindings let’s see this in action by creating a user and then assigning Roles and RoleBindings to that user.

But before creating a user and giving it permissions, we need to know few things about Kubernetes user Management

Kubernetes provides no API Objects for users.

User Management must be configured by Cluster Administrator. Examples:

  • Certificate-based Authentication
  • Token-based Authentication
  • Basic Authentication
  • OAuth2

In this tutorial we will use Certificate-based Authentication to add users.

Certificate-based Authentication

  • Kubernetes is created using a Certificate Authority(CA). In our case, we have created our Kubernetes Cluster using kops. So we can find the key and crt files in S3 bucket. In my case crt file is located in kops-bucket-sam/ha.kopscms.tk/pki/issued/ca/ and key file is located in kops-bucket-sam/ha.kopscms.tk/pki/private/ca/. I have copied the contents of these files in my machine.
  • Every SSL certificate signed with this CA will be accepted by the Kubernetes API.
  • Possible options for creating certificates: OpenSSL or CloudFlare’s PKI Toolkit. In this tutorial we will use OpenSSL
  • Two important fields in the SSL certificates: Common Name(CN): Kubernetes will interpret this value as the User. Organization(O): Kubernetes will interpret this value as the Group.

Copy and paste the below commands:

# Create private key
openssl genrsa -out sam.key 2048
# Create Certificate Signing Request (CSR)
openssl req -new -key sam.key -out sam.csr -subj "/CN=sam/O=devs"
# Create certificate from CSR using the Cluster Authority
openssl x509 -req -in sam.csr \
-CA ca.crt \
-CAkey ca.key -CAcreateserial -out sam.crt -days 365

After running the above commands you should see all these files.

Certificates

Now, we need to do one more thing, that is to create a Kubernetes Configuration for this new user.

# Create Kubernetes configuration
kubectl config set-credentials sam \
--client-certificate=sam.crt \
--client-key=sam.key

Now run the below command to switch the context to our new user:

kubectl config use-context sam
kubectl get pods

You should get the below output:

This is happening because we haven’t assigned any Roles and RoleBindings to this user. Let’s create the Role and RoleBindings and assign them to the user that we just created.

Run the below command to create a ClusterRole and a RoleBinding which gives access to user sam to list pods in default namespace. Be sure to switch to the appropriate context. In my case it’s kubectl config use-context ha.kops.cms.tk

cat << EOF | kubectl create -f -
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  # "namespace" omitted since ClusterRoles are not namespac
  name: pod-reader-ns
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: User
  name: sam # Name is case sensitive
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole #this must be Role or ClusterRole
  name: pod-reader-ns # this must match the name of the Role or ClusterRole you wish to bind to
  apiGroup: rbac.authorization.k8s.io
EOF

Now you should be able to list the pods in default namespace. If you try to list pods in other namespace you should get access denied. Run the below commands to test this.

kubectl config use-context sam
kubectl get pods
kubectl get pods -n kube-system

With this you have learnt all about RBAC’s in Kubernetes, Roles and RoleBindings. Next up is Kubernetes Ingress.

Kubernetes Tutorial Series: Ingress

Please let me know if you have any queries in the comments section below.

One thought to “Kubernetes Tutorial Series: RBAC in Kubernetes”

Leave a comment

Your email address will not be published. Required fields are marked *