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:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  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:

kubectl api-resources
    
    NAME                              SHORTNAMES   APIGROUP                       NAMESPACED   KIND
    bindings                                                                      true         Binding
    componentstatuses                 cs                                          false        ComponentStatus
    configmaps                        cm                                          true         ConfigMap
    endpoints                         ep                                          true         Endpoints
    events                            ev                                          true         Event
    limitranges                       limits                                      true         LimitRange
    namespaces                        ns                                          false        Namespace
    nodes                             no                                          false        Node
    persistentvolumeclaims            pvc                                         true         PersistentVolumeClaim
    persistentvolumes                 pv                                          false        PersistentVolume
    pods                              po                                          true         Pod
    podtemplates                                                                  true         PodTemplate
    replicationcontrollers            rc                                          true         ReplicationController
    resourcequotas                    quota                                       true         ResourceQuota
    secrets                                                                       true         Secret
    serviceaccounts                   sa                                          true         ServiceAccount
    services                          svc                                         true         Service
    mutatingwebhookconfigurations                  admissionregistration.k8s.io   false        MutatingWebhookConfiguration
    validatingwebhookconfigurations                admissionregistration.k8s.io   false        ValidatingWebhookConfiguration
    customresourcedefinitions         crd,crds     apiextensions.k8s.io           false        CustomResourceDefinition
    apiservices                                    apiregistration.k8s.io         false        APIService
    controllerrevisions                            apps                           true         ControllerRevision
    daemonsets                        ds           apps                           true         DaemonSet
    deployments                       deploy       apps                           true         Deployment
    replicasets                       rs           apps                           true         ReplicaSet
    statefulsets                      sts          apps                           true         StatefulSet
    tokenreviews                                   authentication.k8s.io          false        TokenReview
    localsubjectaccessreviews                      authorization.k8s.io           true         LocalSubjectAccessReview
    selfsubjectaccessreviews                       authorization.k8s.io           false        SelfSubjectAccessReview
    selfsubjectrulesreviews                        authorization.k8s.io           false        SelfSubjectRulesReview
    subjectaccessreviews                           authorization.k8s.io           false        SubjectAccessReview
    horizontalpodautoscalers          hpa          autoscaling                    true         HorizontalPodAutoscaler
    cronjobs                          cj           batch                          true         CronJob
    jobs                                           batch                          true         Job
    certificatesigningrequests        csr          certificates.k8s.io            false        CertificateSigningRequest
    leases                                         coordination.k8s.io            true         Lease
    events                            ev           events.k8s.io                  true         Event
    daemonsets                        ds           extensions                     true         DaemonSet
    deployments                       deploy       extensions                     true         Deployment
    ingresses                         ing          extensions                     true         Ingress
    networkpolicies                   netpol       extensions                     true         NetworkPolicy
    podsecuritypolicies               psp          extensions                     false        PodSecurityPolicy
    replicasets                       rs           extensions                     true         ReplicaSet
    ingresses                         ing          networking.k8s.io              true         Ingress
    networkpolicies                   netpol       networking.k8s.io              true         NetworkPolicy
    runtimeclasses                                 node.k8s.io                    false        RuntimeClass
    poddisruptionbudgets              pdb          policy                         true         PodDisruptionBudget
    podsecuritypolicies               psp          policy                         false        PodSecurityPolicy
    clusterrolebindings                            rbac.authorization.k8s.io      false        ClusterRoleBinding
    clusterroles                                   rbac.authorization.k8s.io      false        ClusterRole
    rolebindings                                   rbac.authorization.k8s.io      true         RoleBinding
    roles                                          rbac.authorization.k8s.io      true         Role
    priorityclasses                   pc           scheduling.k8s.io              false        PriorityClass
    csidrivers                                     storage.k8s.io                 false        CSIDriver
    csinodes                                       storage.k8s.io                 false        CSINode
    storageclasses                    sc           storage.k8s.io                 false        StorageClass
    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):

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # "namespace" omitted since ClusterRoles are not namespaced
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  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.
apiVersion: v1
kind: ServiceAccount
metadata:
  name: kube-urvil
  
OR

kubectl 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.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: ServiceAccount
  name: kube-urvil # Name is case sensitive
  namespace: default
roleRef:
  kind: Role #this must be Role or ClusterRole
  name: pod-reader
  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.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: read-secrets-global
subjects:
- kind: Group
  name: manager # Name is case sensitive
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  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.

kubectl create ns kube-user

First Step will be, describe a Role:

cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: kube-user
  name: newbie-role
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods","services"]
  verbs: ["*"]
EOF

Then create a service account for that new engineer:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: kube-user-new-hired
  namespace: kube-user
EOF

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

cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: newbie-rolebinding
  namespace: kube-user
subjects:
- kind: ServiceAccount
  name: kube-user-new-hired
  namespace: kube-user
roleRef:
  kind: Role
  name: newbie-role
  apiGroup: rbac.authorization.k8s.io
EOF

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

kubectl 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.

Resources                                       Non-Resource URLs   Resource Names   Verbs
pods                                            []                  []               [*]
services                                        []                  []               [*]
selfsubjectaccessreviews.authorization.k8s.io   []                  []               [create]
selfsubjectrulesreviews.authorization.k8s.io    []                  []               [create]
                                                [/api/*]            []               [get]
                                                [/api]              []               [get]
                                                [/apis/*]           []               [get]
                                                [/apis]             []               [get]
                                                [/healthz]          []               [get]
                                                [/healthz]          []               [get]
                                                [/openapi/*]        []               [get]
                                                [/openapi]          []               [get]
                                                [/version/]         []               [get]
                                                [/version/]         []               [get]
                                                [/version]          []               [get]
                                                [/version]          []               [get]

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

Resources: