Logo

Kubernetes API authentication using TLS Certificates

In a Kubernetes cluster, the kube-apiserver is the main component of the Control Plane, all the actions that occur within the cluster go through this component. The kube-scheduler, kube-controller, kube-proxy, kubelet among other components talk to the kube-apiserver as clients. These components authenticate against the API through TLS certificates and thus establish encrypted communications.

What about the users? There are many people who need to access the cluster for administration purposes, those accesses and communications must be duly authenticated and encrypted as well.

Kubernetes allows different authentication mechanisms for user accounts: Basic HTTP using user and password or tokens, TLS certificates, and protocols like LDAP and Kerberos. A good practice is to avoid using Basic and implement TLS certificates instead, although, depending on the size of the organization, it may be more convenient to use LDAP, Kerberos or other systems.

These mechanisms can be implemented for users, but there are also service accounts. It is important to know the difference between these two, since Kubernetes handles them differently. On one hand there are users who are humans accessing the cluster for administration purposes; and on the other hand, service accounts for processes, services or applications that need to access the cluster as well.

 

Users Authentication

Users can be authenticated using TLS certificates in a similar way to the previously mentioned components of Kubernetes.

To start, create the certificate for the user account:


1. Create the private key:

$ openssl genrsa -out admin.key 2048


2. Generate the CSR specifying a CN that allows to identify the user. If it’s an administrator user, add "system:masters" to the Organization field, it indicates administration privileges in the cluster (organizations defined in the subject are used as groups).

$ openssl req -new -key admin.key -subj “CN=admin/O=system:masters” \ -out admin.csr

 

3. Sign the CSR using the Kubernetes cluster's CA or a service account’s key pair:

$ openssl x509 -req -in admin.csr -CA ca.crt -CAkey ca.key -out admin.crt


Once the certificates have been generated, there are two ways in which the user can authenticate against the Kubernetes API. One is passing the certificate through parameters in each request, as follows:

$ curl https://<kube-apiserver>:<port>/api \
--cacert ca.crt \
--cert admin.crt \
--key admin.key

 

A more practical way is using a KubeConfig file like the following one:

apiVersion: v1

kind: Config

clusters:

- name: k8s-cluster

  cluster:

    certificate-authority: ca.crt

    server: &lt;kube-apiserver>:<port>

contexts:

- name: admin-k8s-cluster

   context:

     cluster: k8s-cluster

     user: admin

users:

- name: admin

  user:

    client-certificate: admin.crt

    client-key: admin.key

Place that file in the user’s $HOME/.kube/config so as not to need to specify the path to this configuration in each kubectl command. Note that in this configuration file it is possible to specify multiple clusters as well as multiple users (with their respective certificates) to access each one of them.

The context defines what user access what cluster, in the previous file it is indicated that the user admin is used to access the cluster k8s-cluster. In case there are multiple contexts defined, the command kubectl config use-context <context-name> can be used to specify the current context.

 

Service Accounts Authentication

The case of service accounts is different since Kubernetes can manage them natively. The following command creates a service account in the current namespace and an associated secret:

$ kubectl create serviceaccount jenkins


The associated secret name can be obtained by running:

$ kubectl get serviceaccounts jenkins -o yaml

 

The created secret holds the public CA of the API server and a signed JSON Web Token (JWT).

$ kubectl get secret jenkins-token-wcl6d -o yaml

 

The above command will generate an output similar to the following:

apiVersion: v1

data:

  ca.crt: {APISERVER'S CA BASE64 ENCODED}

  namespace: ZGVmYXVsdA==

  token: {BEARER TOKEN BASE64 ENCODED}

kind: Secret

metadata:

  # ...

type: kubernetes.io/service-account-token

 

The signed JWT can be used as a bearer token to authenticate as the given service account. Normally service accounts are used into pods (by specifying the serviceAccountName field in the pod spec) for in-cluster access to the API server but they can be used from outside the cluster as well.

Important to note: because service account tokens are stored in secrets, any user with read access to those secrets can authenticate as the service account. Be cautious when granting permissions to service accounts and read capabilities for secrets.

The next article will talk about API authorization.

Do you want to learn more?

We will give a training about pentesting and securing docker swarm & kubernetes environments at Black Hat USA, HITB and Ekoparty!

Get your ticket!

__________

References

Sheila A. Berta
Head of Research at Dreamlab Technologies

Kubernetes API authentication using TLS Certificates

All blog posts