How Authorization Works in Kubernetes: RBAC

February 08, 2020

6 min read

How Authorization Works in Kubernetes: RBAC

Center of your Kubernetes cluster is an API Server. Which is a core of kubernetes as it provides REST API for managing resources on kubernetes. All the core components like kubelet, scheduler, controller manager etc. uses API Server to get and store data they needs.

RBAC (Role-Based Access Control) is a method of regulating network and computer resources based on the role given to a particular user within an enterprise.

As of 1.8, RBAC mode is stable and backed by the rbac.authorization.k8s.io/v1 API.

To enable RBAC, start the apiserver with --authorization-mode=RBAC.

To get some hands dirty, I am assuming that you have access to kubernetes cluster. If you don't then create a kind cluster by following their installation guide.

  • The RBAC is a way to provide authorization to the API Server. The way RBAC is implemented in kubernetes is through RBAC API which declares four top-level types.

Those types are, as following:

  • Role
  • ClusterRole
  • RoleBinding
  • ClusterRoleBinding

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).
  • The only difference between Role and ClusterRole is that Role is defined for a single namespace whereas ClusterRole is a cluster-wide. Role: A Role can only be used to grant access to resources within a single namespace. Here’s an example Role in the default namespace that can be used to grant read access to pods:
1apiVersion: rbac.authorization.k8s.io/v1
2kind: Role
3metadata:
4 namespace: default
5 name: pod-reader
6rules:
7- apiGroups: [""] # "" indicates the core API group
8 resources: ["pods"]
9 verbs: ["get", "watch", "list"]

This is how you can define a Role in YAML. The important part is the rules block. which list all the action that this role can do on resources. Here, resource name is a pods and action will be ["get", "watch", "list"].

The full list of verbs (actions) are:  

  • get
  • list
  • update
  • patch
  • create
  • watch
  • delete  

The available apiGroups and resources can be listed using kubectl as following:

1kubectl api-resources
2
3 NAME SHORTNAMES APIGROUP NAMESPACED KIND
4 bindings true Binding
5 componentstatuses cs false ComponentStatus
6 configmaps cm true ConfigMap
7 endpoints ep true Endpoints
8 events ev true Event
9 limitranges limits true LimitRange
10 namespaces ns false Namespace
11 nodes no false Node
12 persistentvolumeclaims pvc true PersistentVolumeClaim
13 persistentvolumes pv false PersistentVolume
14 pods po true Pod
15 podtemplates true PodTemplate
16 replicationcontrollers rc true ReplicationController
17 resourcequotas quota true ResourceQuota
18 secrets true Secret
19 serviceaccounts sa true ServiceAccount
20 services svc true Service
21 mutatingwebhookconfigurations admissionregistration.k8s.io false MutatingWebhookConfiguration
22 validatingwebhookconfigurations admissionregistration.k8s.io false ValidatingWebhookConfiguration
23 customresourcedefinitions crd,crds apiextensions.k8s.io false CustomResourceDefinition
24 apiservices apiregistration.k8s.io false APIService
25 controllerrevisions apps true ControllerRevision
26 daemonsets ds apps true DaemonSet
27 deployments deploy apps true Deployment
28 replicasets rs apps true ReplicaSet
29 statefulsets sts apps true StatefulSet
30 tokenreviews authentication.k8s.io false TokenReview
31 localsubjectaccessreviews authorization.k8s.io true LocalSubjectAccessReview
32 selfsubjectaccessreviews authorization.k8s.io false SelfSubjectAccessReview
33 selfsubjectrulesreviews authorization.k8s.io false SelfSubjectRulesReview
34 subjectaccessreviews authorization.k8s.io false SubjectAccessReview
35 horizontalpodautoscalers hpa autoscaling true HorizontalPodAutoscaler
36 cronjobs cj batch true CronJob
37 jobs batch true Job
38 certificatesigningrequests csr certificates.k8s.io false CertificateSigningRequest
39 leases coordination.k8s.io true Lease
40 events ev events.k8s.io true Event
41 daemonsets ds extensions true DaemonSet
42 deployments deploy extensions true Deployment
43 ingresses ing extensions true Ingress
44 networkpolicies netpol extensions true NetworkPolicy
45 podsecuritypolicies psp extensions false PodSecurityPolicy
46 replicasets rs extensions true ReplicaSet
47 ingresses ing networking.k8s.io true Ingress
48 networkpolicies netpol networking.k8s.io true NetworkPolicy
49 runtimeclasses node.k8s.io false RuntimeClass
50 poddisruptionbudgets pdb policy true PodDisruptionBudget
51 podsecuritypolicies psp policy false PodSecurityPolicy
52 clusterrolebindings rbac.authorization.k8s.io false ClusterRoleBinding
53 clusterroles rbac.authorization.k8s.io false ClusterRole
54 rolebindings rbac.authorization.k8s.io true RoleBinding
55 roles rbac.authorization.k8s.io true Role
56 priorityclasses pc scheduling.k8s.io false PriorityClass
57 csidrivers storage.k8s.io false CSIDriver
58 csinodes storage.k8s.io false CSINode
59 storageclasses sc storage.k8s.io false StorageClass
60 volumeattachments storage.k8s.io false VolumeAttachment

Here, NAME is a name of the resource and APIGROUP is a group in which this resources are grouped. The empty string " " in APIGROUP means that those resources are grouped into CORE API group. i.e. nodes, pods are core resources.

A ClusterRole can be used to grant the same permissions as a Role, but because they are cluster-scoped, they can also be used to grant access to:

  • cluster-scoped resources (like nodes)  
  • non-resource endpoints (like “/healthz”)
  • namespaced resources (like pods) across all namespaces (needed to run kubectl get pods --all-namespaces, for example)  

The following ClusterRole can be used to grant read access to secrets in any particular namespace, or across all namespaces (depending on how it is bound):

1apiVersion: rbac.authorization.k8s.io/v1
2kind: ClusterRole
3metadata:
4 # "namespace" omitted since ClusterRoles are not namespaced
5 name: secret-reader
6rules:
7- apiGroups: [""]
8 resources: ["secrets"]
9 verbs: ["get", "watch", "list"]

Service Account:

  • Service Account Provides identity to API Server. Using service account you can Authenticate to being granted to access apiserver.
  • When you create Service Account using kubectl or describing YAML you are generating token which will be used to authenticate you to API Server.
1apiVersion: v1
2kind: ServiceAccount
3metadata:
4 name: kube-urvil
5
6OR
7
8kubectl create sa kube-urvil
  • RoleBinding  And ClusterRoleBinding are, where the set of rules which are described in a Role or ClusterRole is mapped to the Service Account. This is where authorization and authentication meets the common ground.

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, or cluster-wide with a ClusterRoleBinding.
  • A RoleBinding may reference a Role in the same namespace. The following RoleBinding grants the “pod-reader” role to the service-account “kube-urvil” within the “default” namespace. This allows “kube-urvil” to read pods in the “default” namespace.
  • roleRef is how you will actually create 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 below, this RoleBinding is using roleRef to bind the service-account “kube-urvil” to the Role created above named pod-reader.
1apiVersion: rbac.authorization.k8s.io/v1
2kind: RoleBinding
3metadata:
4 name: read-pods
5 namespace: default
6subjects:
7- kind: ServiceAccount
8 name: kube-urvil # Name is case sensitive
9 namespace: default
10roleRef:
11 kind: Role #this must be Role or ClusterRole
12 name: pod-reader
13 apiGroup: rbac.authorization.k8s.io
  • Finally, a ClusterRoleBinding may be used to grant permission at the cluster level and in all namespaces. The following ClusterRoleBinding allows any user in the group “manager” to read secrets in any namespace.
1apiVersion: rbac.authorization.k8s.io/v1
2kind: ClusterRoleBinding
3metadata:
4 name: read-secrets-global
5subjects:
6- kind: Group
7 name: manager # Name is case sensitive
8 apiGroup: rbac.authorization.k8s.io
9roleRef:
10 kind: ClusterRole
11 name: secret-reader
12 apiGroup: rbac.authorization.k8s.io

Putting All Together with a real use-case:

Let's assume that we have hired new an engineer, which is new to kubernetes and want to play around with it's API. As a cluster admin you want to give it a permission to create Pods and Services inside namespace called kube-user.

1kubectl create ns kube-user

First Step will be, describe a Role:

1cat <<EOF | kubectl apply -f -
2apiVersion: rbac.authorization.k8s.io/v1
3kind: Role
4metadata:
5 namespace: kube-user
6 name: newbie-role
7rules:
8- apiGroups: [""] # "" indicates the core API group
9 resources: ["pods","services"]
10 verbs: ["*"]
11EOF

Then create a service account for that new engineer:

1cat <<EOF | kubectl apply -f -
2apiVersion: v1
3kind: ServiceAccount
4metadata:
5 name: kube-user-new-hired
6 namespace: kube-user
7EOF

Final, Step would we to tide Role with ServiceAccount together using rolebinding:

1cat <<EOF | kubectl apply -f -
2apiVersion: rbac.authorization.k8s.io/v1
3kind: RoleBinding
4metadata:
5 name: newbie-rolebinding
6 namespace: kube-user
7subjects:
8- kind: ServiceAccount
9 name: kube-user-new-hired
10 namespace: kube-user
11roleRef:
12 kind: Role
13 name: newbie-role
14 apiGroup: rbac.authorization.k8s.io
15EOF

We, can check that all permissions are correctly applied to given service-account using kubectl as:

1kubectl auth can-i --list --as=system:serviceaccount:kube-user:kube-user-new-hired -n kube-user # --as=system:serviceaccount:<namespace>:<serviceaccountname>

This will list all the permissions that this service-account have in the given namespace.

1Resources Non-Resource URLs Resource Names Verbs
2pods [] [] [*]
3services [] [] [*]
4selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
5selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
6 [/api/*] [] [get]
7 [/api] [] [get]
8 [/apis/*] [] [get]
9 [/apis] [] [get]
10 [/healthz] [] [get]
11 [/healthz] [] [get]
12 [/openapi/*] [] [get]
13 [/openapi] [] [get]
14 [/version/] [] [get]
15 [/version/] [] [get]
16 [/version] [] [get]
17 [/version] [] [get]

That's it for now. We have created a Role and Service Account and connected both with RoleBinding.

Resources: