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
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).
Role & RoleBinding
Define a role
Create a Role that allows get
, list
, and watch
on Pods
in the default namespace
.
[root@master testrbac]# cat pod-reader-role.yml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: default name: pod-reader rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "watch", "list"] [root@master testrbac]# kubectl apply -f pod-reader-role.yml role.rbac.authorization.k8s.io/pod-reader unchanged [root@master testrbac]# kubectl get roles | grep pod-reader pod-reader 2025-03-07T16:24:59Z [root@master testrbac]# kubectl describe role pod-reader Name: pod-reader Labels: <none> Annotations: <none> PolicyRule: Resources Non-Resource URLs Resource Names Verbs --------- ----------------- -------------- ----- pods [] [] [get watch list]
Bind the Role to the User
Create a RoleBinding
that binds the pod-reader
Role to the user sanjeeb
.
[root@master testrbac]# cat sanjeeb-pod-reader-binding.yml apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: sanjeeb-pod-reader namespace: default subjects: - kind: User name: sanjeeb apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.io [root@master testrbac]# kubectl apply -f sanjeeb-pod-reader-binding.yml rolebinding.rbac.authorization.k8s.io/sanjeeb-pod-reader created [root@master testrbac]# kubectl get rolebinding | grep sanjeeb-pod-reader sanjeeb-pod-reader Role/pod-reader 20s [root@master testrbac]# kubectl describe rolebinding sanjeeb-pod-reader Name: sanjeeb-pod-reader Labels: <none> Annotations: <none> Role: Kind: Role Name: pod-reader Subjects: Kind Name Namespace ---- ---- --------- User sanjeeb
Verify
Now, verify that sanjeeb
has the necessary permissions to access Pods in the default
namespace.
- Switch to the sanjeeb Context
- Check Permissions
[root@master testrbac]# kubectl config use-context sanjeeb Switched to context "sanjeeb". [root@master testrbac]# kubectl auth can-i get pods yes [root@master testrbac]# kubectl auth can-i list pods yes [root@master testrbac]# kubectl auth can-i watch pods yes
ClusterRole & ClusterRoleBinding
We use ClusterRoles
and ClusterRoleBindings
to grant a user permissions to access cluster-wide resources (e.g., Nodes, PersistentVolumes).
Define a ClusterRole
A ClusterRole defines permissions for cluster-scoped resources (e.g., Nodes, PersistentVolumes) or across all namespaces.
# Switch to your kubernetes-admin cluster [root@master testrbac]# kubectl config use-context kind-cka-cluster2 [root@master testrbac]# cat node-reader-clusterrole.yml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: node-reader rules: - apiGroups: [""] resources: ["nodes"] verbs: ["get", "watch", "list"] [root@master testrbac]# kubectl apply -f node-reader-clusterrole.yml clusterrole.rbac.authorization.k8s.io/node-reader created [root@master testrbac]# kubectl get clusterroles | grep node-reader node-reader 2025-03-08T05:41:48Z [root@master testrbac]# kubectl describe clusterrole node-reader Name: node-reader Labels: <none> Annotations: <none> PolicyRule: Resources Non-Resource URLs Resource Names Verbs --------- ----------------- -------------- ----- nodes [] [] [get watch list]
Bind the ClusterRole to the User
[root@master testrbac]# cat sanjeeb-node-reader-binding.yml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: sanjeeb-node-reader subjects: - kind: User name: sanjeeb apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: node-reader apiGroup: rbac.authorization.k8s.io [root@master testrbac]# kubectl apply -f sanjeeb-node-reader-binding.yml clusterrolebinding.rbac.authorization.k8s.io/sanjeeb-node-reader created [root@master testrbac]# kubectl get clusterrolebinding | grep sanjeeb-node-reader sanjeeb-node-reader ClusterRole/node-reader 25s [root@master testrbac]# kubectl describe clusterrolebinding sanjeeb-node-reader Name: sanjeeb-node-reader Labels: <none> Annotations: <none> Role: Kind: ClusterRole Name: node-reader Subjects: Kind Name Namespace ---- ---- --------- User sanjeeb
Verify Permissions
Now, verify that sanjeeb has the necessary permissions to access Nodes across the cluster.
[root@master testrbac]# kubectl config use-context sanjeeb Switched to context "sanjeeb". [root@master testrbac]# kubectl auth can-i get nodes Warning: resource 'nodes' is not namespace scoped yes [root@master testrbac]# kubectl auth can-i list nodes Warning: resource 'nodes' is not namespace scoped yes [root@master testrbac]# kubectl auth can-i watch nodes Warning: resource 'nodes' is not namespace scoped yes [root@master testrbac]# kubectl auth can-i get nodes -n default --all-namespaces yes
- The warning is simply informing you that the resource (nodes) is not namespace-scoped, so the command applies to the entire cluster. It does not indicate an error or problem with your permissions.