Kubernetes Authentication — A deep dive

Raja Venkataraman
Star Systems Labs
Published in
6 min readOct 1, 2019
Photo by Florian Berger on Unsplash

This is the first of a multi-part series that dives into how Kubernetes authenticates users and how you can allow your users to login to Kubernetes. This part shows you how to authenticate to Kubernetes using X509 certificates all done manually. View the other upcoming posts for other ways of authenticating including automating the X509 certificates, basic auth, token auth and OAuth based authentication. Stay tuned!

Kubernetes provides a variety of mechanisms to authenticate(which is the Process of verifying who you are) the user. Authorization (which is the process of verifying what you have access to) is done separately and is quite straightforward to do using ClusterRoleBindings and RoleBindings. We will cover Authorization just to indicate and prove that the user has been able to do what they need to do, but the blog series is mostly about Authentication and the various methods to do it.

Kubernetes does not manage Users but expects an outside service to manage them. Same with groups. The only thing that looks like a user in k8s is a Serviceaccount. Serviceaccounts are a special user account that an application uses to talk to the operating system. In the case of kubernetes, Serviceaccounts are used to talk to the API server of a cluster.

Now that all the jargons are out of the way, let’s see how Kubernetes authenticates you when you do something with its Swiss army knife a.k.a kubectl.

Authenticating through X509 Client Certificates

For most people who install Kubernetes and get a KUBECONFIG file, the user authentication is done through X509 client certificates. If you look into the KUBECONFIG file (Which by default lives in ~/.kube/config) and find entries like client-certificate-data and client-key-data (See screenshot below).

You are authenticating yourself using certificates. Kubernetes when setting itself up, creates a Certificate Authority (CA) that can be used to sign incoming requests from your users. The process of getting a client certificate contains the following steps:

  1. Create a private key (pem file)
  2. Create a Certificate Signing Request (CSR)
  3. Have a CA Administrator sign your CSR
  4. Once signed, use the Certificate (crt file) and Private key (pem) to create a kubeconfig file.
  5. Get a Kubernetes administrator to give you access
  6. Profit!

Now, lets see this step by step. For the sake of the example, assume that Keerthi is the Kubernetes administrator (and CA Administrator) and Raja is the developer who needs access to the cluster.

Create the private key

Assuming Raja has a linux machine which has openssl installed by default, he creates a private key like

openssl genrsa -out raja.key 2048

This generates a 2048 bit private key with the name raja.key

Create a Certificate Signing Request (CSR)

Once the key is generated using the above step, the next one is to generate the CSR, which indicates to the CA who you are and what you would like to access. Kubernetes uses the Common name(CN) portion of the Certificate as the user who is accessing the api server and the Organization (O) portion of the certificate as the group to which the user might belong to.

openssl req -new -key raja.key -out raja.csr

The above will ask a series of questions (which you can pass as an option to the openssl req as well), but for the purposes of this, lets manually assign them. For now, Im assuming the name of the user is “raja” and the group that he belongs to is “developers”

emerald:tmp raja$ openssl req -new -key raja.key -out raja.csr
You are about to be asked to enter information that will be incorporated into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:IN
State or Province Name (full name) []:Tamilnadu
Locality Name (eg, city) []:Chennai
Organization Name (eg, company) []:developers
Organizational Unit Name (eg, section) []:engineering
Common Name (eg, fully qualified host name) []:raja
Email Address []:raja@starsystems.in
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:

I have highlighted the inputs in bold, but feel free to change it as per your environment. The only things that matter are the “O” (for groupname) and “CN” (for username)

Once the above command is run, you will have a CSR file available to you.

Note: If you wanted to verify that the CSR generated is correct, pls run

openssl req -in raja.csr -noout -text

and look at the Subject field in the output to see if it matches what you provided

Have a CA Administrator sign your CSR

Once you send the csr file to your Certificate Authority(CA) administrator, he can then generate the certificate key using the CA certificate and keys. The CA admin will know the locations of these files.

For this example, since my dev cluster is on minikube, the locations of these files will be at ~/.minikube/ca.crt (for certificate) and ~/.minikube/ca.key (for the key).

To generate the user’s certificate, the administrator can run

openssl x509 -req -in raja.csr -CA ~/.minikube/ca.crt -CAkey ~/.minikube/ca.key -CAcreateserial -out raja.crt -days 500 -sha256

The above will create a certificate called raja.crt which is valid for 500 days from the date of issue.

Create the kubeconfig file for the user

Once the developer gets the crt and the key file, you can create a kubeconfig file that can be used to authenticate to the api server.

If you already have a kubeconfig file, you can replace certain sections of it, or create it from scratch

To create the base file, you would need two pieces of information from your CA administrator

  • Server address
  • Certificate authority file (extension is typically .crt)

Assuming that your new kubeconfig file is located at /tmp/raja_kube.conf, you can create the basic details from the above with

KUBECONFIG=/tmp/raja_kube.conf kubectl config set-cluster devcluster --server=<server-address-from-admin> --certificate-authority=<location-of-ca-crt> --embed-certs

The above will create a file in /tmp/raja_kube.conf with a cluster named as devcluster with the server information and the CA certificate.

The next step is to setup the user credentials in the KUBECONFIG. To do that, you need the crt and key file that was created in the earlier steps.

KUBECONFIG=/tmp/raja_kube.conf kubectl config set-credentials raja --client-certificate=/tmp/raja.crt --client-key=/tmp/raja.key --embed-certs

Now that we have both the User info and the cluster info, the only remaining is to setup a context and use that context for ourselves. We can do that by

KUBECONFIG=/tmp/test.conf kubectl config set-context devcontext --user=raja --cluster=devcluster

The previous command connects the user that we created earlier with the cluster that we setup before that.

The final bit of the puzzle is to let kubectl know that you want to use this context. So to do that

export KUBECONFIG=/tmp/test.conf
kubectl config use-context devcontext

Get a Kubernetes administrator to give you access

To get access to Kubernetes, the cluster administrator needs to decide on the following;

a) What namespace(s) do you need access to

b) What level of permissions do you need (Read/write), What objects do you need to see/read/write

Based on the above two questions, he will create a ClusterRoleBinding (that binds a ClusterRole to your user/group) or a RoleBinding(That binds a role to your user/group on a namespace). The difference between the two is that ClusterRole is across namespaces and Role binding limits you to a specific namespace.

For e.g. you can do something like

kubectl create rolebinding raja_roles --role=edit --user=raja

or

kubectl create rolebinding dev_roles --role=edit --group=developers

Using either of the above will give you access to the ‘edit’ role.

The same can be done for a ClusterRole by replacing the rolebinding with a clusterrolebinding above. For e.g.

kubectl create clusterrolebinding raja_cluster_role --clusterrole=admin --user=raja

Please make sure that users/groups are only given roles that they need. The lesser the better, unless they deserve it is the motto for security.

You should now have be able to access the kubernetes cluster by running kubectl commands depending on the role/clusterrole that you got. I hope this helped you get an understanding of how to create users/groups that can get access to Kubernetes.

In the next series, we will look at a more automated way of doing this rather than doing all of this manually. Kubernetes provides first class citizens of kind CertificateSigningRequest that minimize some of the hassle mentioned. I wanted to do this first as this is under the covers and if you understood this, the next part of the series will be a lot easier.

Happy k8s-ing!!!

--

--