Certificates, kubeconfig and the CSR API

The cluster's certificates and how to renew them, what a kubeconfig holds, and how to give a new user a certificate through the CSR API.

45 min 2 hands-on tasksArchitecture · 25% of the exam

Key ideas in this lesson · tap one for a simple explanation

What you will be able to do

  • Find any control plane certificate, read its subject, issuer, SANs and expiry date with openssl, and renew it with kubeadm.
  • Read and build a kubeconfig with kubectl config, with the certificates embedded in the file.
  • Create a user with a private key and a CertificateSigningRequest, approve it and give the user a working kubeconfig.

A certificate is an ID card for a program or a person. Every part of a cluster shows one to prove who it is. Example: when the connects to , it shows its client certificate, and etcd checks that a CA it trusts signed it. A CA (certificate authority) issues these ID cards: whoever holds its key can sign new ones.

People reach the cluster through a : a file that says which cluster to talk to and which ID to show. This lesson covers both, plus a favorite exam task: create a new user and give them a kubeconfig that works. Certificates also expire and must be renewed. So the lesson touches two exam topics: Create and manage Kubernetes clusters using kubeadm and Manage the lifecycle of Kubernetes clusters.

WordWhat it isExample file
Private keyA secret that only the owner keeps. It proves the certificate belongs to them.jane.key
(certificate signing request)A request that says "please sign this": the owner's name plus their public key.jane.csr
CertificateThe signed ID card: a name, a public key, an expiry date and the CA's signature.jane.crt
CAThe issuer. The cluster trusts every certificate its CA signed.ca.crt, ca.key

The certificates kubeadm makes

kubeadm init creates a set of certificates and keys in /etc/kubernetes/pki. This set is called the cluster's PKI (public key infrastructure). These are the ones you will meet:

File in /etc/kubernetes/pkiWhat it isSigned by
ca.crt, ca.keyThe cluster CA. The API server accepts any client certificate it signed (--client-ca-file). The also signs approved CSRs with it.Itself
apiserver.crtThe API server's own certificate, shown to every client. Its SANs are the names and IPs it is valid for. They cover the IP, the kubernetes IP, the kubernetes.default… names and the endpoint.ca
apiserver-kubelet-client.crtThe API server's ID toward kubelets, for logs, exec and port-forward.ca
apiserver-etcd-client.crtThe API server's ID toward etcd.etcd/ca
front-proxy-ca.crt, front-proxy-client.crtLets the API server prove who it is to add-on APIs such as .front-proxy-ca
sa.key, sa.pubNot certificates: the key pair that signs and checks tokens.n/a
etcd/ca.crt, etcd/server.crt, etcd/peer.crt, etcd/healthcheck-client.crtetcd's own set: its server, member-to-member and health-check IDs.etcd/ca

Next to pki/, kubeadm writes one kubeconfig per component in /etc/kubernetes: controller-manager.conf, scheduler.conf and kubelet.conf. There is also admin.conf for you, the administrator, and super-admin.conf for emergencies. What each identity may do is the topic of RBAC.

  • Most certificates are valid for one year. The CAs are valid for ten years.
  • The 's client certificate is the exception: the kubelet renews it on its own, under /var/lib/kubelet/pki/.

Check and renew certificates

Two tools read certificates. kubeadm certs check-expiration shows when every kubeadm certificate expires. openssl x509 reads one certificate file in detail.

Check expiry, inspect a certificate, renew
# exam: ssh <control-plane>; sudo -i      lab: docker exec -it cka-control-plane bash
kubeadm certs check-expiration

# Subject, issuer, expiry and SANs of any certificate
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -subject -issuer -enddate
# subject=CN=kube-apiserver
# issuer=CN=kubernetes
# notAfter=Oct 17 09:51:49 2027 GMT
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -ext subjectAltName
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text        # everything

# Renew one certificate, or all of them (on a real cluster; see below before you do)
kubeadm certs renew apiserver
kubeadm certs renew all

Renewing rewrites the certificate files, including the ones inside the kubeconfig files. But running control plane still hold the old certificate in memory. So after renewing:

  1. 1.Restart each control plane Pod. cannot restart a . Instead, move its file out of /etc/kubernetes/manifests, wait about 20 seconds for the kubelet to stop it, then move it back.
  2. 2.If your own kubeconfig is a copy of admin.conf, copy the renewed file again.

kubeadm upgrade apply also renews every certificate. That is why a cluster upgraded at least once a year never hits expiry.

Inside a kubeconfig

A kubeconfig is a file on your machine. It tells kubectl where the cluster is and who you are. It holds three lists and a pointer:

What a kubeconfig holds

A kubeconfig file

~/​.kube/​config

clusters

where: the API server's URL and its CA

users

who: a certificate and key, or a token

contexts

one cluster + one user + a namespace

current-context

the context kubectl uses now

Example: the context jane@kind-cka means talk to cluster kind-cka, as user jane, in namespace dev.

Three lists and a pointer
apiVersion: v1
kind: Config
clusters:                 # where: API server URL and the CA that signed its certificate
  - name: kind-cka
    cluster:
      server: https://127.0.0.1:52634
      certificate-authority-data: LS0tLS1CRUdJTi...     # base64 PEM, or certificate-authority: /path/ca.crt
users:                    # who: a client certificate, a token or an exec plugin
  - name: jane
    user:
      client-certificate-data: LS0tLS1CRUdJTi...
      client-key-data: LS0tLS1CRUdJTi...
contexts:                 # a named pairing of cluster and user, with an optional default namespace
  - name: jane@kind-cka
    context:
      cluster: kind-cka
      user: jane
      namespace: dev
current-context: jane@kind-cka

To list, switch and change contexts with kubectl config, see kubectl fluency. Below you build a kubeconfig from scratch, for a new user.

A new user through the CSR API

Kubernetes has no User object. Instead, any client certificate signed by the cluster CA lets you log in. Its Common Name (CN) becomes the username, and each Organization (O) becomes a group. Example: a certificate for /CN=jane/O=developers logs in as user jane in group developers.

The CertificateSigningRequest (CSR) API gets such a certificate signed, without anyone touching ca.key:

  1. 1.You submit a CSR object for the signer kubernetes.io/kube-apiserver-client.
  2. 2.An administrator approves it. This signer never approves anything automatically.
  3. 3.The controller manager signs it with the cluster CA. The certificate appears in the CSR's status.
From key to kubeconfig

Key and request

jane.key and jane.csr, on your machine

openssl

CSR object

waits as Pending

kubectl apply

Approve

the cluster CA signs it

kubectl certificate approve

jane.crt

goes into jane's kubeconfig

expirationSeconds asks for how long the certificate stays valid, at least 600 seconds. The signer may make it shorter.

Key, CSR and approval
mkdir -p /tmp/cka && cd /tmp/cka
openssl genrsa -out jane.key 2048
openssl req -new -key jane.key -subj "/CN=jane/O=developers" -out jane.csr

cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: jane
spec:
  request: $(base64 < jane.csr | tr -d '\n')
  signerName: kubernetes.io/kube-apiserver-client
  expirationSeconds: 86400
  usages:
    - client auth
EOF

kubectl get csr jane                  # CONDITION: Pending
kubectl certificate approve jane
kubectl get csr jane                  # CONDITION: Approved,Issued
kubectl get csr jane -o jsonpath='{.status.certificate}' | base64 -d > jane.crt
openssl x509 -in jane.crt -noout -subject -issuer -enddate

Now jane has a certificate. Put it in a kubeconfig file of her own, together with the cluster's address and CA. Run this in the same folder, /tmp/cka:

A kubeconfig for jane
# A kubeconfig for jane in its own file. On a control plane node the CA is /etc/kubernetes/pki/ca.crt.
SERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
kubectl config view --minify --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 -d > ca.crt
kubectl config set-cluster kind-cka --server="$SERVER" --certificate-authority=ca.crt --embed-certs=true --kubeconfig=jane.kubeconfig
kubectl config set-credentials jane --client-certificate=jane.crt --client-key=jane.key --embed-certs=true --kubeconfig=jane.kubeconfig
kubectl config set-context jane@kind-cka --cluster=kind-cka --user=jane --kubeconfig=jane.kubeconfig
kubectl config use-context jane@kind-cka --kubeconfig=jane.kubeconfig

kubectl --kubeconfig=jane.kubeconfig auth whoami
kubectl --kubeconfig=jane.kubeconfig get pods       # Forbidden: authenticated, not yet authorized

In the official docs· open on exam day too

Hands-on task 1 of 2ar-certs-1
~6 min3% weightArchitecture

Inspect control plane certificates

Inspect this cluster's certificates on cka-control-plane. (1) Write the expiry date of the API server's serving certificate to /tmp/cka/ar-apiserver-expiry.txt, exactly as openssl prints it after notAfter= (for example Oct 17 09:51:49 2027 GMT). (2) Find the client certificate the API server presents to etcd and write the Common Name of the CA that issued it to /tmp/cka/ar-etcd-client-issuer.txt. (3) Save the complete output of kubeadm certs check-expiration to /tmp/cka/ar-cert-expiration.txt.

Cluster:kubectl config use-context kind-cka

  1. 1

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/ar-certs-1/setup | bash
  2. 2

    Solve it in your terminal

    Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under /tmp/cka/.

  3. 3

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/ar-certs-1/verify | bash
    Got FAIL? Read which check failed, fix it, run it again.
  4. 4

    Clean up (optional)

    curl -fsSL https://codewithmuh.com/labs/cka/t/ar-certs-1/cleanup | bash
Hands-on task 2 of 2ar-certs-2
~10 min7% weightArchitecture

Create a user with the CSR API and a kubeconfig

Create credentials for a new user ar-dev in group ar-team. Generate a 2048-bit RSA private key at /tmp/cka/ar-dev.key and a certificate signing request for it. Submit the request as a CertificateSigningRequest named ar-dev for signer kubernetes.io/kube-apiserver-client, valid for 24 hours, approve it, and save the issued certificate as /tmp/cka/ar-dev.crt. Then create a self-contained kubeconfig at /tmp/cka/ar-dev.kubeconfig (CA, certificate and key embedded, not referenced by path) whose current context connects to this cluster as ar-dev with default namespace ar-certs. A RoleBinding that lets ar-dev read Pods in ar-certs already exists. Do not change your own kubeconfig.

Cluster:kubectl config use-context kind-cka

  1. 1

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/ar-certs-2/setup | bash
  2. 2

    Solve it in your terminal

    Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under /tmp/cka/.

  3. 3

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/ar-certs-2/verify | bash
    Got FAIL? Read which check failed, fix it, run it again.
  4. 4

    Clean up (optional)

    curl -fsSL https://codewithmuh.com/labs/cka/t/ar-certs-2/cleanup | bash

Finished this lesson?

0 of 2 tasks passed. Your readiness counts tasks, so run them before you move on.