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!