Detailed Overview of Role-Based Access Control and Service Accounts

Amit MauryaAmit Maurya
8 min read

In Kubernetes architecture, the user's initial request is directed to the API server when a user accesses the Kubernetes cluster. While we understand how this process operates, the key question is: how is the user authenticated and granted access to our Kubernetes cluster?

Suppose I execute the command “kubectl run nginx —image=nginx“. This command will create the pod, but what occurs before this process?

What is Authentication and Authorization?

  • Authentication: Authentication is the process by which a user is verified and granted access to the Kubernetes Cluster.

  • Authorization: Now that the user is validated, determine what roles they have to perform actions called Authorization.

Okay, now we know about Authentication and Authorization, but I have one more question: Does Kubernetes handle user creation? The answer is “NO”

Authentication:

If a valid user possesses a certificate signed by the Cluster’s Certificate Authority, they are authenticated. However, how do we create the user?

In Kubernetes, two types of users can be authenticated with the Kubernetes Cluster:

1) User Accounts: are human users who serve as Cluster Administrators or perform tasks such as creating and scaling workloads. These accounts are not managed by Kubernetes but are instead managed externally by third-party authenticators like OpenID Connect (OIDC) Providers or X509 Certificates.

2) Service Accounts: They are managed by Kubernetes API which is namespaced (which means in every namespace “default” service account is created”). The Service Account is created by the Service Account Controller by the kube-controller-manager component within the namespace. It grants permissions to the workloads with the Kubernetes API.

Authorization:

Later, we will create User and Service Accounts, now let’s understand how to give permissions to the user to perform what type of actions or say verbs (create, get, list, update, patch, delete) in the Kubernetes Cluster.

Now, the user is validated with an Authentication Strategy, the user goes to the Authorization where authorization performs authorization modules that perform allow or deny checks. By default, permissions are denied, which means the user cannot perform any actions on the Kubernetes Cluster.

Authorization has 6 modes by which you can perform authorization:

  • Always Allow: This will always allow all API requests which is a security risk.

  • Always Deny: This will deny all requests.

  • ABAC (Attribute Based Access Control) Authorization

  • RBAC (Role-Based Access Control) Authorization: To perform some actions on the Kubernetes Cluster, we must create roles that give permissions to users. By default, RBAC is enabled.

  • Webhook

  • Node Authorization

How can we verify if this User has access to this Kubernetes Object?

kubectl auth can-i create deployments -n <namespace>

This command will verify whether the user accessing the Kubernetes cluster has the necessary permission to create a deployment.

Here the “RBAC Authorization” comes into the picture to give necessary permissions to the user to create resources/objects in the Kubernetes Cluster.

RBAC (Role-Based Access Control) Authorization:

To create RBAC Authorization Kubernetes has 4 types of Objects:

1) Role: Sets permissions within a namespace.

2) ClusterRole: If we want to define cluster-wide access use ClusterRole, this is a non-namespaced resource.

3) RoleBinding: Now that we have created a Role, we need to bind the role to a particular user to assign permissions to that user or set of users.

4) ClusterRoleBinding: The same goes with also ClusterRoleBinding, this will grant access to cluster-wide.

RBAC includes an auto-reconciliation feature, which means the controller continuously monitors the current state of resources in the cluster and compares it to the desired state specified in the manifests (YAML configuration files). If there is a discrepancy between the desired and current states, the controller will align the current state with the desired state.

Auto-reconciliation ensures that any modifications to the RBAC rules are automatically implemented throughout the cluster, eliminating the need for manual intervention. This feature is essential for maintaining security and ensuring that permissions are accurately configured. The kubectl auth reconcile command is utilized to reconcile RBAC (Role-Based Access Control) resources within a Kubernetes cluster. It ensures that the desired state of RBAC resources, as specified in your YAML files or other manifests, is accurately applied to the cluster. This command facilitates the addition, updating, or correction of RBAC policies without inadvertently removing any existing rules.

Practical Demonstration:

Now, let's proceed with a practical demonstration of how to create a Service Account and a Normal User, followed by assigning the appropriate permissions to the User.

To practice, use KillerCoda Playground which gives the latest version of Kubernetes Cluster (1.31) - https://killercoda.com/playgrounds/scenario/kubernetes

1) Run kubectl auth whoami to check the current user and its group.

2) To review the current configuration of your Kubernetes user, execute (kubectl config view), which will display all the details stored in your kubeconfig files.

3) Now, let’s create the new user by generating the certificate key (.key) and signing request (CSR) by OpenSSL. Create the folder name certificate and place the .key and CSR there.

mkdir certificate && cd certificate

OpenSSL is an open-source toolkit used to implement cryptographic functions, Certificate Signing Requests (CSRs), certificate keys, and SSL/TLS protocols to secure communication.

openssl genrsa -out amit.key 2048

4) We had created the amit.key, now generate the CSR (Certificate Signing Request). CN is the Common Name that is treated as the username.

openssl req -new -key amit.key -out amit.csr -subj "/CN=amit"

Remember all certificates are stored in the/etc/kubernetes/pki folder in the Kubernetes master node.

5) Now, we have to obtain a signed certificate from a Certificate Authority (CA).

openssl x509 -req -in amit.csr -CA /etc/kubernetes/pki/ca.crt -CAkey  /etc/kubernetes/pki/ca.key -CAcreateserial -out amit.crt -days 365

Command Breakdown:

  1. openssl x509:

    • This command is used to manage X.509 certificates. In this case, it is used to sign a CSR and generate a certificate.
  2. -req:

    • This flag tells openssl that the input will be a CSR (Certificate Signing Request), which is a request for a certificate to be signed by a CA.
  3. -in amit.csr:

    • This points to the input CSR file (amit.csr), which has the public key and details about who wants the certificate.
  4. -CA /etc/kubernetes/pki/ca.crt:

    • This specifies the CA certificate file (/etc/kubernetes/pki/ca.crt) that will be used to sign the CSR. The CA’s public key and identity information is contained in this file.
  5. -CAkey /etc/kubernetes/pki/ca.key:

    • This specifies the CA private key (/etc/kubernetes/pki/ca.key) corresponding to the CA certificate. The private key is needed to sign the CSR and generate the new certificate. The private key should be kept secure, as it proves the identity of the CA.
  6. -CAcreateserial:

    • This flag instructs openssl to create a new serial number file if it doesn’t already exist. The serial number is used to uniquely identify the certificate and is included in the certificate's metadata.

    • If the serial number file (*.srl) does not exist in the current directory, OpenSSL will create it automatically.

    • The generated serial number file is typically named ca.srl.

  7. -out amit.crt:

    • This specifies the output file (amit.crt), which is the signed certificate. The signed certificate can now be used by the requester (e.g., for HTTPS, secure Kubernetes communication, etc.).
  8. -days 365:

    • This specifies the validity period of the signed certificate, in days. In this case, the certificate will be valid for 365 days (1 year) from the date it is created. After that period, the certificate will expire, and a new one will need to be issued.

What This Command Does:

  1. The command reads the CSR file (amit.csr), which contains information like the public key and details about the requester (e.g., Kubernetes component or application).

  2. It uses the provided CA certificate (/etc/kubernetes/pki/ca.crt) and CA private key (/etc/kubernetes/pki/ca.key) to sign the CSR.

  3. A serial number gets automatically created for the new certificate if there's none already, making sure each certificate is unique.

  4. The output is a signed certificate (amit.crt) that remains valid for 365 days. This certificate can now be utilized to secure communications by verifying the identity of the entity that generated the original CSR.

6) Now, let’s add the credentials in kubeconfig file, to add the credentials execute kubectl config set-credentials

kubectl config set-credentials amit --client-certificate ./amit.crt --client-key ./amit.key

7) You can now observe in the kubeconfig file that the user "amit" is included with its certificate. To list the users, execute kubectl config get-users. Before setting the context, execute the get-contexts command to view the available contexts.

kubectl config get-contexts

kubectl config set-context amit --cluster=kubernetes --user=amit

As we can see the context is created and named amit now we want to use this context, execute

kubectl config use-context amit

Now that we have created the user "amit," the question arises: can he access pods, namespaces, or any resources?

No, because he currently lacks the necessary permissions. This is where authorization becomes relevant, requiring us to create a Role and RoleBinding.

Creating Role and RoleBinding:

1) Now, let's create a role for the user "amit," which will define the permissions and resources he can access in the role.yaml file.

In this YAML file we are defining the rules for the resources that are namespace and verbs which means get, create, watch, list.

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

Remember you cannot create anything with the context amit so you have to switch the context to Kubernetes-admin to create the Role.

2) Now, we have to create RoleBinding for the User amit to assign the role with the necessary permissions.

In this YAML file, we are binding the Role pod-reader by defining the subject of kind User by referencing the Role in roleRef.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: User
  name: amit
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role 
  name: pod-reader 
  apiGroup: rbac.authorization.k8s.io

Now, apply the Role and RoleBinding to create it.

After this switch back to the context amit to check whether we can list the pods or not. As we can see “Forbidden“ message has gone, and we can get the pods in the default namespace.

Summary

At last, we learned about Authentication (Normal Users, Service Account) and Authorization (Role, ClusterRole, RoleBinding, ClusterRoleBinding). We also learned about OpenSSL a little bit where we generated the certificates for Normal Users.

Stay tuned for the next blog i.e. on '“Admission Controllers”

Follow for more upcoming Linux and DevOps blogs !!

You can connect with me on Twitter (amitmau07).

0
Subscribe to my newsletter

Read articles from Amit Maurya directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Amit Maurya
Amit Maurya

DevOps Enthusiast, Learning Linux