Prerequisites:

  • Kubernetes Cluster
  • Cluster Admin Access to the Cluster

What is Access Control?

In general terms, Access control means controlling objects or systems' access. Access control can be given to any physical objects like rooms, vaults or digital objects like Databases or Web Servers. In Kubernetes, we can provide access to different users depending upon the requirements. This is done through certificate-based authentication.

Different methods exist for different types of objects. In this article, we will learn about Digital Object Access Control. To be more specific, we will dive into role-based access control in Kubernetes, which was implemented recently in version 1.20.

Need for Access Control?

We store critical data in our systems, so we should not let it get into the hands of malicious attackers. Sensitive data can be used against the organization in a blackmailing effort or could be sold off to bidders at high prices.

These unfortunate circumstances can cause irreparable damage to an organization. This is why access control is necessary for assets critical to the organization's operations and public image.

How to implement Access Control in Kubernetes?

Kubernetes Role-Based Access Control was recently introduced. In a Role-Based Access Control (RBAC), users who want to access objects in the Kubernetes Ecosystem must have certain assigned roles. These permissions can be assigned to a role depending upon the access required.

Update, Get, Watch, List, Create, Patch, Delete

It's an efficient way to provide access to certain user groups or a certain user on a need-to-see, use, edit basis.

RBAC can be implemented in different ways; one of the most common is via the certificate, specifically a X.509 certificate. If a user wants to access something on the cluster, they will be provided with a certificate that authenticates them against the cluster.  This certificate is first generated and then authenticated by the cluster admin, after which the user can access cluster resources.

We'll learn to implement X.509 certificate based authentication with edit permission to the user in this article.

How does X.509 Certificate based authentication work?

A certificate is generated for the user, and the cluster admin verifies its Certificate Signing Request (CSR). A new role and role-binding are created for the user with appropriate permissions like edit, update ,list, delete, etc.

After going through the instructions, we will be able to successfully authenticate into the Kubernetes cluster using a new user role that we'll create and then be able to perform operations that are limited within a particular namespace.

Setting up RBAC

Step 1: Create a Private Key

First, we'll generate an RSA Key of 4096 bits using the command below.

openssl genrsa -out developer.key 4096

Then, a CSR is generated for validation in the cluster with the organization and common name specified using the private key generated earlier.

openssl req -new -key developer.key -out developer.csr -subj  "/CN=developer/O=developers"

Run the command below to check CSR details [output should show the CN (Common Name) and O (Organization)].

openssl req -in developer.csr -noout -text

Note:

noout = Certificate key is not provided as Output

text = Organized and easier-to-read format

Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: CN=developer, O=developers
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (4096 bit)
                Modulus:
                    00:ad:d1:73:4a:c3:88:39:c3:a6:0e:7b:7b:0b:d1:
                    0b:f2:ce:f4:ff:c7:..:..:..............

We'll extract the CSR and decode it from base64 format to be used in the Certificate Signing Request in Kubernetes.

cat developers.csr | base64 | tr -d '\n' | tee -a decoded-csr

Step 2: Create a Certificate Signing Request

We'll now paste the value of the CSR that we decoded above into the Kubernetes CertificateSigningRequest Manifest below.

apiVersion: certificates.k8s.io/v1 
kind: CertificateSigningRequest 
metadata: 
  name: csr-request 
spec: 
  groups: 
  - system:authenticated 
  #Enter decoded CSR Value here in the request field.
  request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJRWFqQ0NBbElDQVFBd0pURU9NQXdHQTFVRUF3d0ZaR1YyWld3eEV6QVJCZ05WQkFvTUNtUmxkbVZzYjNCbApjbk13Z2dJaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQ0R3QXdnZ0lLQW9JQ0FRQ3FMSXJOQTFRdm5oNGZDZDN6CkRBV3l
  signerName: kubernetes.io/kube-apiserver-client 
  expirationSeconds: 86400 
  usages: 
  - digital signature 
  - key encipherment 
  - client auth
CSR Manifest
✍️
In recent versions of Kubernetes, server auth is not allowed. Only client auth is allowed for RBAC.

Step 3: Validate the CSR in the Cluster

Deploy the CSR object into the cluster using the mentioned command.

kubectl apply -f csr.yaml

To check if CSR was deployed:

kubectl get csr

NAME          AGE   SIGNERNAME                            REQUESTOR          REQUESTEDDURATION   CONDITION
csr-request   4s    kubernetes.io/kube-apiserver-client   kubernetes-admin   24h                 Pending
CSR Approval

After that, approve the CSR request using kubectl.

kubectl certificate approve csr-request

certificatesigningrequest.certificates.k8s.io/csr-request approved

Let's check if it got approved.

kubectl get csr

NAME        	 AGE     SIGNERNAME                                    REQUESTOR                  REQUESTEDDURATION   CONDITION
csr-request      2m47s   kubernetes.io/kube-apiserver-client           kubernetes-admin           86400s              Approved,Issued
CSR Approval Status

Once the CSR is approved by Kubernetes, extract the certificate key and save it into a .crt file (certificate file)

kubectl get csr developer-authentication -o jsonpath='{.status.certificate}' | base64 --decode >> developer.crt

Step 4: Configuring kubeconfig

An existing cluster configuration needs to exist in kubeconfig before you add access for a new user.

As this article only covers creating users in a pre-built cluster generating a CA (Certificate Authority) is out of scope which is only valid for when you create a cluster from scratch.

⚠️
If the CA doesn't match then an error like this will show up!

Unable to connect to the server: x509: certificate signed by unknown authority

Here's an example of kubeconfig for minikube:

apiVersion: v1 
clusters: 
- cluster: 
    certificate-authority-data: /Users/macbook/.minikube/ca.crt #This changes depending upon the kubernetes cluster
    server: https://127.0.0.1:52519 #This changes depending upon the kubernetes cluster
  name: cluster-1 
contexts: 
- context: 
    cluster: cluster-1 
    user: devel 
  name: cluster-1 
current-context: cluster-1 
kind: Config 
preferences: {} 
users: 
- name: devel 
  user: 
#Change this to use the generated .crt and .key file
    client-certificate: /Users/macbook/rba-keys/certs-ok/devel.crt 
    client-key: /Users/macbook/rba-keys/certs-ok/devel.key
Example kubeconfig File

If you already have an existing kubeconfig generated by minikube or any other tool, simply follow the pattern in the existing kubeconfig file to add the new entry specified in the example above.

✍️
Take a backup of the file before making modifications, as the cluster(s) will not be accessible if a mistake is made in any of the fields.
💡
kubectx is a tool that can be used to switch cluster contexts
kubens is a tool that can be used to switch namespaces inside a cluster

These two tools can be used to navigate between clusters and namespaces.

Step 5: Creating a Rolebinding

We'll create a rolebinding for our users to be able to access the resources in our cluster.

kubectl create rolebinding devel-edit-role --clusterrole=edit --user=devel --namespace=developers

✍️
The user has been provided with the inbuilt edit role, which enables access to all resources in a particular namespace. Custom roles can also be created to narrow down accessible resources, which we'll discuss in another article.

Testing the implementation

So far, we've provided the user devel access to work on the namespace developers only. If our efforts were successful, we should be able to access resources only in that particular namespace but not any other.

To test it, we use the command kubectl auth can-i. It will tell us if the resource is accessible to the user.

kubectl auth can-i get deployments -n developers

Output

yes
The output of kubectl auth can-i

It says we can access the deployments in the developer's namespace.

kubectl get deployment -n developers

NAME                    READY   STATUS    RESTARTS   AGE
nginx-8f458dc5b-jsjzs   1/1     Running   0          7s
Successfully listed pods in the developers' namespace

Let's test it in the default namespace. Note that we have not provided access to any other namespace, but you are free to modify and follow as you like.

kubectl auth can-i get deployments -n default

Output

no
The output of kubectl auth can-i

kubectl get deployments -n default

Output

error: failed to get deployment: deployments.apps is forbidden: User "devel" cannot create resource "deployments" in API group "apps" in the namespace "default"
Failed to get deployments in the default namespace

Conclusion

We learned to implement RBAC in a Kubernetes Cluster to secure it from unintended modifications and data exfiltration. Clusters should never be made accessible publicly without authentication, and organizational access should be provided sparingly on a need-to-use or know basis only.

In the next article, we'll learn more ways to implement access control in Kubernetes.

I edit and update this article for corrections and improvements periodically.
Thank you for reading. Stay tuned for another article on Access Control where we dive into using Roles, RoleBindings, ClusterRoles, ClusterRoleBindings in Kubernetes.