Generate OpenSSL Keys and Certificate for Use with Kubernetes

We’ll create user called “dave” to use within a Kubernetes cluster, I’m using Minikube in this case.

Create Private Key

Create the private key:

openssl genrsa -out dave.key 2048

Create and Sign the CSR

Now create the Certificate Signing Request (CSR):

openssl req -new -key dave.key -out dave.csr -subj "/CN=dave/O=admin"

Now on this the subject is important. Here you are defining their username (CN), “dave” in this case, and then the group (O) in this case is “admin”.

We now need to sign the requests (CSRs) with the Kubernetes Certificate Authority (CA). Note i’m using Minikube in this example.

We now need to create a CSR.yaml file we can use to create the signing request to the Kubernetes CA.

We first need to get the CSR in Base64, so we can add it to the CSR.yaml, so we do this with the following, we are also removing any newline characters with “tr”.

cat alice.csr | base64 | tr -d "\n"

Now we can create the CSR.yaml as follows and paste in the CSR (Base64) encoded we just created:

apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: alice
spec:
  request: <YOUR CSR BASE64 HERE>
  signerName: kubernetes.io/kube-apiserver-client
  expirationSeconds: 86400
  usages:
    - client auth

So once done, run kubectl to create theCSR.

kubectl apply -f csr.yaml

To check it has worked, we can run the following to see the CSR within Kubernetes.

kubectl get certificatesigningrequest

For example:

NAME    AGE   SIGNERNAME                            REQUESTOR       REQUESTEDDURATION   CONDITION
dave 54s   kubernetes.io/kube-apiserver-client   minikube-user   24h                 Pending

Notice however it is saying “Pending”, so we now need to approve these CSRs.

kubectl certificate approve dave

And repeat the above command, we can see this is now “approved”.

NAME    AGE   SIGNERNAME                            REQUESTOR       REQUESTEDDURATION   CONDITION
dave 54s   kubernetes.io/kube-apiserver-client   minikube-user   24h                 Approved,Issued

Get Signed Certificate

To take a look at it, we can then run:

kubectl get certificatesigningrequest dave -o yaml

Within this output, you’ll find a section called “Certificate” which is what we want to obtain to be able to have the signed certificate.

kubectl get csr dave -o jsonpath='{.status.certificate}' | base64 -d > dave.crt

To take a look inside of the certificate, we can use:

openssl x509 -noout -text -in dave.crt

We’d get an output like the following within which we can see the “Subject” as “O = admin, CN = bob” as per what we did earlier on.

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            8f:4b:1a:a1:6d:77:66:59:8f:7a:a8:d6:3f:c9:51:38
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = minikubeCA
        Validity
            Not Before: Jun 10 08:25:37 2026 GMT
            Not After : Jun 11 08:25:37 2026 GMT
        Subject: O = admin, CN = bob
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:a0:44:ea:98:c9:e4:f0:dd:84:db:00:fc:44:86:
                    aa:c0:55:2f:b4:48:1b:fa:fa:f5:b3:45:e6:97:98:
                    2e:05:b6:f7:40:cc:a2:1a:8b:86:0a:d3:84:22:b9:
                    8f:b1:8d:5d:3b:99:8f:16:9f:23:0a:7d:ff:84:51:

Context

Create

kubectl config set-context bob--cluster minikube --user dave

This will create a user and a context or that user within Kubernetes.

kubectl config set-credentials dave --client-key $(realpath dave.key) --client-certificate $(realpath dave.crt) --embed-certs=true

If we now run: kubectl config view, we’ll see that we have a new context, and further down the file we see the new user created, with the certificate and key data as “omitted” because it is stored directly within Kubernetes, rather than referring to files on disk. If you leave off the “–embed-certs=true” from the end, you’ll see that it instead points to the files on disk.

...
contexts:
- context:
    cluster: minikube
    user: alice
  name: alice
- context:
    cluster: minikube
    extensions:
...
users:
- name: dave
  user:
    client-certificate-data: DATA+OMITTED
    client-key-data: DATA+OMITTED
- name: minikube
  user:
    client-certificate: /home/user/.minikube/profiles/minikube/client.crt
    client-key: /home/user/.minikube/profiles/minikube/client.key

Test Context

Now try to swap context with:

kubectl config use-context dave

And check with the following which should just show “dave” as the current context.

kubectl config current-context

If you then run:

kubectl config view

And within the output look for the specific “current-context”, which will say “dave”. All commands now run will be done so under the “dave” context.

Conclusion

We’ve explored creating a user and keys to allow a user to access Kubernetes and swap context to actually use that user within Kubernetes.

What you will find however is that although the user has access to Kubernetes, we’ve not yet provided any rolebindings or clusterolebindings to provide them with any privileges!

Leave a comment