Lesson 7.1: RBAC (Role-Based Access Control)
RBAC (Role-Based Access Control) is a method of regulating access to resources in a Kubernetes cluster based on the roles of individual users or groups. It provides fine-grained control over who can perform specific actions (e.g., create, read, update, delete) on specific resources (e.g., Pods, Services, Deployments).
Key Components of RBAC
- Subjects: Entities that need access to resources.
- Users: Individual users (e.g., john, admin).
- Groups: Collections of users (e.g., developers, admins).
- ServiceAccounts: Accounts used by applications or Pods to interact with the Kubernetes API.
- Roles:
- Define a set of permissions (e.g., get, list, create, delete) for specific resources.
- Namespaced: Applies to resources within a specific namespace.
- ClusterRoles:
- Similar to
Roles
, but applies to cluster-scoped resources (e.g., Nodes, PersistentVolumes) or across all namespaces.
- Similar to
- RoleBindings:
- Bind a
Role
to aSubject
(user, group, or ServiceAccount) within a specific namespace.
- Bind a
- ClusterRoleBindings:
- Bind a
ClusterRole
to aSubject
across the entire cluster.
- Bind a
How RBAC Works
- Define Roles/ClusterRoles: Create Roles or ClusterRoles to specify the permissions for specific resources.
- Bind Roles to Subjects: Use RoleBindings or ClusterRoleBindings to associate Roles or ClusterRoles with Subjects.
- Enforce Access Control: Kubernetes enforces the permissions defined in the Roles or ClusterRoles when a Subject tries to access a resource.
Manage TLS Certificates
How to issue a certificate for a user
A few steps are required in order to get a normal user to be able to authenticate and invoke an API. First, this user must have a certificate issued by the Kubernetes cluster, and then present that certificate to the Kubernetes API.
Create private key
[root@master managetls]# openssl genrsa -out adam.key 2048
[root@master managetls]# openssl req -new -key adam.key -out adam.csr -subj "/CN=adam"
[root@master managetls]# ls
adam.csr adam.key
[root@master managetls]# cat adam.csr
-----BEGIN CERTIFICATE REQUEST-----
MIICVDCCATw...
-----END CERTIFICATE REQUEST-----
# Has to be in base64 encoded value of the CSR file content.
[root@master managetls]# cat adam.csr | base64 | tr -d "\n"
LS0tLS1CRUd...
Create a CertificateSigningRequest
[root@master managetls]# cat csr.yml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: adam
spec:
request: LS0tLS1CRUd...
signerName: kubernetes.io/kube-apiserver-client
usages:
- client auth
[root@master managetls]# kubectl apply -f csr.yml
certificatesigningrequest.certificates.k8s.io/adam created
[root@master managetls]# kubectl get csr
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
adam 7s kubernetes.io/kube-apiserver-client kubernetes-admin <none> Pending
Why is the status pending ?
The CertificateSigningRequest (CSR) you created is in the Pending state because it needs to be approved by a Certificate Authority (CA). In Kubernetes, the CA is typically managed by the Kubernetes control plane, and the approval process involves manual or automated steps. Let’s break down the process and explain why the CSR is pending, who approves it, and how the CA works.
When you create a CSR, it is submitted to the Kubernetes API server, but it is not automatically approved. The CSR must be reviewed and approved by an entity with the appropriate permissions (e.g., a cluster administrator or an automated approval process).
Who Approves the CSR?
The approval of CSRs is typically handled by:
- Cluster Administrators: A human operator with the necessary permissions to approve CSRs. They can manually approve or deny CSRs using kubectl.
- Automated Approvers: In some clusters, an automated process (e.g., a controller) may approve CSRs based on predefined rules.
[root@master managetls]# kubectl describe csr adam
Name: adam
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"certificates.k8s.io/v1","kind":"CertificateSigningRequest","metadata":{"annotations":{},"name":"adam"},"spec":{"request":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1ZEQ0NBVHdDQVFBd0R6RU5NQXNHQTFVRUF3d0VZV1JoYlRDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRApnZ0VQQURDQ0FRb0NnZ0VCQUtaYzd5QjB0RWF2ZEFMeGRxbW4wTDdnREdkUnRndWFPMmVWZ2h4YWNEV2FCY3h2CjkvVWNHTFVkdEUvTStKaHVFazJuYzdVemtsd3ZBN2daUFBKV1pYUDJGZGYzMHNyaXo3bzQ5WmE1Q3VjejkwUHEKSjVLanI5KzZ1QTJhRXBSSUcxL05IUCtIZDdQN3VDRTkxOGt1QzkwRTNNdjFmL3d4L1BpMTlDbkRtZVdQTXoveAo5ZHpBeXhnbnFhWmdhRVVJVi9Sc01TRnFycmwrMmVlRzJvYUlPbUNYd29hckxSZ1VKMUJqcjFLVk9na01kZWZwCmZkanprdklNMHVUNzU1cnNFbnpFVWlLRlVnUzdJbXZPTGF0YnUxakZZLy9KT3RURU96cnVwZVBxZGsxcFZOMUcKcDAweklrMUhPaVNtRTg3OW9qRDFuSlQxdXk2cm5hUGtWWkVBWHFFQ0F3RUFBYUFBTUEwR0NTcUdTSWIzRFFFQgpDd1VBQTRJQkFRQk5RNW15K2M2RHF0UHdaMGhubzYyLzU1SVdvVEI0d2RGUk9nZml5bjRleU0rRmdTbkkzdXFHCjRkQnNFRTI4bXFYQVdkNzMwdXFIdWJhdHVlVHlzZlhiRHM0OVNqdUF5dmJ2bGJqUkhucGFXNy9vL0JWdVJ4ZkUKYTNDNXZrSjN3T0tOaFNtaXFhVmsvOTRPR0xBaTVucThDS3hLQmxETU9VWG5Sak5GeUgyZjNYRWxqRGlwaHpSTwpLa0g3T2JOYmJKMno3bzh0T2VEVEVMUm1Ob2V3VjZLeDVkNVJWdGVqWWZ3TTZXazhCRGJDclowQWdnaW9MUEFqCmRvSzF3OXVuV3VtQk9LZ0w1V3hvZ3Q5Vjg1aFdlS05JQmtxa3RXRzNObFFwanhVSUJjVjBZbmZsejhQaFg2b1kKcnBSditoL0FCVUNxSGlmWmhSaTdlUzdqUEdua0taMnoKLS0tLS1FTkQgQ0VSVElGSUNBVEUgUkVRVUVTVC0tLS0tCg==","signerName":"kubernetes.io/kube-apiserver-client","usages":["client auth"]}}
CreationTimestamp: Fri, 07 Mar 2025 21:14:03 +0545
Requesting User: kubernetes-admin
Signer: kubernetes.io/kube-apiserver-client
Status: Pending
Subject:
Common Name: adam
Serial Number:
Events: <none>
How to Approve the CSR
To approve the CSR, you need to use the kubectl certificate approve
command. Here’s how:
[root@master managetls]# kubectl certificate approve adam
certificatesigningrequest.certificates.k8s.io/adam approved
# The CONDITION field will change from Pending to Approved,Issued.
[root@master managetls]# kubectl get csr
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
adam 2m53s kubernetes.io/kube-apiserver-client kubernetes-admin <none> Approved,Issued
What Happens After Approval?
Once the CSR is approved:
- The Kubernetes CA signs the certificate and issues it.
- The signed certificate is added to the CSR object in the status.certificate field.
- You can extract the signed certificate and use it for authentication.
# Two methods to create adam.crt
# METHOD-1 - Automatic creation
[root@master testrbac]# kubectl get csr adam -o jsonpath='{.status.certificate}' | base64 --decode > adam.crt
# METHOD-2 - Copy from describe
[root@master managetls]# echo "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM5VENDQWQyZ0F3SUJBZ0lSQUpjakowNnJBUEFFY3dqMGp0MUF6WEV3RFFZSktvWklodmNOQVFFTEJRQXcKRlRFVE1CRUdBMVVFQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TlRBek1EY3hOVEkyTXpaYUZ3MHlOakF6TURjeApOVEkyTXpaYU1BOHhEVEFMQmdOVkJBTVRCR0ZrWVcwd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3CmdnRUtBb0lCQVFDbVhPOGdkTFJHcjNRQzhYYXBwOUMrNEF4blViWUxtanRubFlJY1duQTFtZ1hNYi9mMUhCaTEKSGJSUHpQaVliaEpOcDNPMU01SmNMd080R1R6eVZtVno5aFhYOTlMSzRzKzZPUFdXdVFybk0vZEQ2aWVTbzYvZgp1cmdObWhLVVNCdGZ6UnovaDNleis3Z2hQZGZKTGd2ZEJOekw5WC84TWZ6NHRmUXB3NW5sanpNLzhmWGN3TXNZCko2bW1ZR2hGQ0ZmMGJERWhhcTY1ZnRubmh0cUdpRHBnbDhLR3F5MFlGQ2RRWTY5U2xUb0pESFhuNlgzWTg1THkKRE5MaysrZWE3Qko4eEZJaWhWSUV1eUpyemkyclc3dFl4V1AveVRyVXhEczY3cVhqNm5aTmFWVGRScWROTXlKTgpSem9rcGhQTy9hSXc5WnlVOWJzdXE1Mmo1RldSQUY2aEFnTUJBQUdqUmpCRU1CTUdBMVVkSlFRTU1Bb0dDQ3NHCkFRVUZCd01DTUF3R0ExVWRFd0VCL3dRQ01BQXdId1lEVlIwakJCZ3dGb0FVZ3N5VjUyaEVZU1FZbGZ4NnFuNkMKQ21XQkRUSXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBRmQ5TjdoU3drV2RFK3NtK1NhVzhha3hJcVBiVE5GTQo2NTVnSG5MU3NGQkxPYXY0VHFRMjFnN0JxdVM1ZjJ1R3lXSG9YeVdZVVFIc21nOTN5dC9DQ3Y5LzBNSFJ1eEZ2CjE4NENIMFJ5Z2NhNDVCZTB6R2xGS3FySFhiQzFud0lvRnNPajBVY0lXU1lNMG5jQW1lV2JFdUFNUTZrVVB1d3cKT2JaTkJDZG5ydEhYTzJZOTJSeTV6Ymo0Snh0VTNWT3BhcFNhQkdHKzIyVFpRRHptM2lyanpDNHF5R3pzbVR2QQo3Ui9HMEp0QzN2Y3Fyb2dlS2lGb2JwTkZhREpTTUFBVzFxdHVMZXFpRGFvblE4ZDBMRXcwTVNyMldsREZGaFdsClFaWFh0TVd5ak9zZkNscHdoS0thR0FhSnYvbUpsalhmKzZkT3VxSEtORmtURmkyTFd5SmtPK1U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" | base64 -d > adam.crt
# Output
[root@master managetls]# cat adam.crt
-----BEGIN CERTIFICATE-----
MIIC9TCCAd2gAwIBAgIRAJcjJ06rAPAEcwj0jt1AzXEwDQYJKoZIhvcNAQELBQAw
FTETMBEGA1UEAxMKa3ViZXJuZXRlczAeFw0yNTAzMDcxNTI2MzZaFw0yNjAzMDcx
NTI2MzZaMA8xDTALBgNVBAMTBGFkYW0wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQCmXO8gdLRGr3QC8Xapp9C+4AxnUbYLmjtnlYIcWnA1mgXMb/f1HBi1
HbRPzPiYbhJNp3O1M5JcLwO4GTzyVmVz9hXX99LK4s+6OPWWuQrnM/dD6ieSo6/f
urgNmhKUSBtfzRz/h3ez+7ghPdfJLgvdBNzL9X/8Mfz4tfQpw5nljzM/8fXcwMsY
J6mmYGhFCFf0bDEhaq65ftnnhtqGiDpgl8KGqy0YFCdQY69SlToJDHXn6X3Y85Ly
DNLk++ea7BJ8xFIihVIEuyJrzi2rW7tYxWP/yTrUxDs67qXj6nZNaVTdRqdNMyJN
RzokphPO/aIw9ZyU9bsuq52j5FWRAF6hAgMBAAGjRjBEMBMGA1UdJQQMMAoGCCsG
AQUFBwMCMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUgsyV52hEYSQYlfx6qn6C
CmWBDTIwDQYJKoZIhvcNAQELBQADggEBAFd9N7hSwkWdE+sm+SaW8akxIqPbTNFM
655gHnLSsFBLOav4TqQ21g7BquS5f2uGyWHoXyWYUQHsmg93yt/CCv9/0MHRuxFv
184CH0Rygca45Be0zGlFKqrHXbC1nwIoFsOj0UcIWSYM0ncAmeWbEuAMQ6kUPuww
ObZNBCdnrtHXO2Y92Ry5zbj4JxtU3VOpapSaBGG+22TZQDzm3irjzC4qyGzsmTvA
7R/G0JtC3vcqrogeKiFobpNFaDJSMAAW1qtuLeqiDaonQ8d0LEw0MSr2WlDFFhWl
QZXXtMWyjOsfClpwhKKaGAaJv/mJljXf+6dOuqHKNFkTFi2LWyJkO+U=
-----END CERTIFICATE-----
Configure kubeconfig:
The user (adam) must be configured in the kubeconfig file and granted permissions via RBAC.
Add new credentials
[root@master testrbac]# kubectl config set-credentials adam --client-certificate=adam.crt --client-key=adam.key
User "adam" set.
[root@master testrbac]# kubectl config get-users | grep sanjeeb
sanjeeb
Add the context
[root@master testrbac]# kubectl config set-context sanjeeb --cluster=kind-cka-cluster2 --user=sanjeeb
Context "sanjeeb" created.
[root@master testrbac]# kubectl config get-contexts | grep sanjeeb
sanjeeb kind-cka-cluster2 sanjeeb
RBAC
Role and ClusterRole
- An RBAC Role or ClusterRole contains rules that represent a set of permissions. Permissions are purely additive (there are no "deny" rules).
- A Role always sets permissions within a particular namespace; when you create a Role, you have to specify the namespace it belongs in.
- ClusterRole, by contrast, is a non-namespaced resource. The resources have different names (Role and ClusterRole) because a Kubernetes aobject always has to be either namespaced or not namespaced; it can't be both.
- ClusterRoles have several uses. You can use a ClusterRole to:
- define permissions on namespaced resources and be granted access within individual namespace(s)
- define permissions on namespaced resources and be granted access across all namespaces
- define permissions on cluster-scoped resources
- If you want to define a role within a namespace, use a Role; if you want to define a role cluster-wide, use a ClusterRole.
In this section we will allow the user sanjeeb
to access resources (e.g., Pods) in the Kubernetes cluster, you need to:
- Define a Role (or ClusterRole) that specifies the permissions.
- Bind the Role to the User using a RoleBinding (or ClusterRoleBinding).
Here are some commonly used resources in Roles and ClusterRoles:
API | Group Resources |
---|---|
Core ("") | pods, services, configmaps, secrets, nodes, persistentvolumes |
apps | deployments, statefulsets, daemonsets, replicasets |
rbac.authorization.k8s.io | roles, rolebindings, clusterroles, clusterrolebindings |
networking.k8s.io | networkpolicies, ingresses |
storage.k8s.io | storageclasses, volumeattachments |
batch | jobs, cronjobs |
autoscaling | horizontalpodautoscalers |
Role
A Role defines a set of permissions (rules) within a specific namespace. It specifies what actions (verbs) can be performed on which resources (e.g., pods, services) in that namespace.
Creating a Role that allows get
, list
, and watch
on Pods
in the default namespace
.
[root@master rbac]# cat simple-role.yaml
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"]
[root@master rbac]# kubectl apply -f simple-role.yaml
role.rbac.authorization.k8s.io/pod-reader created
ClusterRole
- "namespace" omitted since ClusterRoles are not namespaced
[root@master rbac]# cat simple-clusterrole.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "watch", "list"]
[root@master rbac]# kubectl apply -f simple-clusterrole.yml
clusterrole.rbac.authorization.k8s.io/secret-reader created
Key Differences in Binding
| Feature | Role | ClusterRole | | --- | --- | | Scope | Namespaced | Cluster-wide | | Resources | Namespaced resources only | Namespaced and cluster-wide resources | | Binding | RoleBinding (namespaced) | RoleBinding (namespaced) or ClusterRoleBinding (cluster-wide) | | Use Case | Fine-grained access within a namespace | Broad access across the cluster |
RoleBinding with Role
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. A RoleBinding grants permissions within a specific namespace
[root@master rbac]# cat simple-rolebinding-with-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
# This role binding allows "jane" to read pods in the "default" namespace.
# You need to already have a Role named "pod-reader" in that namespace.
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
# You can specify more than one "subject"
- kind: User
name: jane # "name" is case sensitive
apiGroup: rbac.authorization.k8s.io
roleRef:
# "roleRef" specifies the binding to a Role / ClusterRole
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
[root@master rbac]# kubectl apply -f simple-rolebinding-with-role.yaml
rolebinding.rbac.authorization.k8s.io/read-pods created
[root@master rbac]# kubectl auth can-i get pods --as=jane -n=default
yes
[root@master rbac]# kubectl auth can-i watch pods --as=jane -n=default
yes
[root@master rbac]# kubectl auth can-i list pods --as=jane -n=default
yes
[root@master rbac]# kubectl auth can-i update pods --as=jane -n=default
no
[root@master rbac]# kubectl auth can-i delete pods --as=jane -n=default
no
RoleBinding with ClusterRole
A RoleBinding may reference any Role in the same namespace. Alternatively, a RoleBinding can reference a ClusterRole and bind that ClusterRole to the namespace of the RoleBinding. If you want to bind a ClusterRole to all the namespaces in your cluster, you use a ClusterRoleBinding.
[root@master rbac]# cat simple-rolebinding-with-clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
# This role binding allows "dave" to read secrets in the "development" namespace.
# You need to already have a ClusterRole named "secret-reader".
kind: RoleBinding
metadata:
name: read-secrets
#
# The namespace of the RoleBinding determines where the permissions are granted.
# This only grants permissions within the "development" namespace.
namespace: development
subjects:
- kind: User
name: dave # Name is case sensitive
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
[root@master rbac]# kubectl apply -f simple-rolebinding-with-clusterrole.yaml
rolebinding.rbac.authorization.k8s.io/read-secrets created
Verification
[root@master rbac]#
[root@master rbac]# kubectl auth can-i get secrets --as=dave -n=development
yes
[root@master rbac]# kubectl auth can-i watch secrets --as=dave -n=development
yes
[root@master rbac]# kubectl auth can-i list secrets --as=dave -n=development
yes
[root@master rbac]# kubectl auth can-i create secrets --as=dave -n=development
no
[root@master rbac]# kubectl auth can-i update secrets --as=dave -n=development
no
[root@master rbac]# kubectl auth can-i delete secrets --as=dave -n=development
no
# Vertification using user jane
[root@master rbac]# kubectl auth can-i get secrets --as=jane -n=development
no
#Adding user jane to the rolebinding with clusterrole
[root@master rbac]# cat simple-rolebinding-with-clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
# This role binding allows "dave" to read secrets in the "development" namespace.
# You need to already have a ClusterRole named "secret-reader".
kind: RoleBinding
metadata:
name: read-secrets
#
# The namespace of the RoleBinding determines where the permissions are granted.
# This only grants permissions within the "development" namespace.
namespace: development
subjects:
- kind: User
name: dave # Name is case sensitive
apiGroup: rbac.authorization.k8s.io
- kind: User
name: jane
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
[root@master rbac]# kubectl apply -f simple-rolebinding-with-clusterrole.yaml
rolebinding.rbac.authorization.k8s.io/read-secrets configured
# Verification as user jane
[root@master rbac]# kubectl auth can-i get secrets --as=jane -n=development
yes
[root@master rbac]# kubectl auth can-i watch secrets --as=jane -n=development
yes
[root@master rbac]# kubectl auth can-i list secrets --as=jane -n=development
yes
[root@master rbac]# kubectl auth can-i create secrets --as=jane -n=development
no
For instance, even though the following RoleBinding refers to a ClusterRole, "dave" & "jane" will only be able to read Secrets in the "development" namespace, because the RoleBinding's namespace (in its metadata) is "development".
# Verification using namespace default which is added 'development'
[root@master rbac]# kubectl auth can-i get secrets --as=jane -n=development
yes
[root@master rbac]# kubectl auth can-i get secrets --as=dave -n=development
yes
# Verification using namespace default which is not added 'default'
[root@master rbac]# kubectl auth can-i get secrets --as=dave -n=default
no
[root@master rbac]# kubectl auth can-i get secrets --as=jane -n=default
no
ClusterRoleBinding with ClusterRole
In the provided configuration, Sarah (the user sarah) has been granted access to get, watch, and list secrets in all namespaces across the cluster. This is because the ClusterRoleBinding (read-secrets-global) binds the ClusterRole (secret-reader) to Sarah cluster-wide.
[root@master rbac]# cat simple-clusterrolebinding.yml
apiVersion: rbac.authorization.k8s.io/v1
# This cluster role binding allows anyone in the "manager" group to read secrets in any namespace.
kind: ClusterRoleBinding
metadata:
name: read-secrets-global
subjects:
- kind: Group
name: manager # Name is case sensitive
apiGroup: rbac.authorization.k8s.io
- kind: User
name: sarah
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
[root@master rbac]# kubectl apply -f simple-clusterrolebinding.yml
clusterrolebinding.rbac.authorization.k8s.io/read-secrets-global created
[root@master rbac]# kubectl auth can-i get secrets --as=sarah -n=default
yes
[root@master rbac]# kubectl auth can-i get secrets --as=sarah -n=development
yes
[root@master rbac]# kubectl auth can-i get secrets --as=sarah --namespace=kube-system
yes