Lab CKA-06 — Users & Certificate Requests
Kubernetes has no user objects. A “user” is whatever name appears in a client certificate the cluster CA has signed. This lab creates one end to end: key, signing request, approval, kubeconfig and RBAC.
Concepts: Authentication vs Authorization, Certificates and RBAC.
Tested on kind v0.31 with Kubernetes v1.35.0. Not re-run on v1.37.
Verified on kind v0.31 with Kubernetes v1.35.0.
flowchart LR K["openssl genrsa<br/>private key"] --> R["openssl req<br/>CSR: CN=user, O=group"] R --> O["CertificateSigningRequest<br/>object"] O --> A["kubectl certificate approve"] A --> C["Signed certificate<br/>in .status.certificate"] C --> KC["kubeconfig<br/>user + context"] KC --> RB["Role + RoleBinding"]
1. Prerequisites & Starting State
- Working
k8s-labcluster from Lab CKAD-01. opensslon the machine where you runkubectl.
kubectl create namespace dev2. Create the Key and Signing Request
openssl genrsa -out jane.key 2048
openssl req -new -key jane.key -subj "/CN=jane/O=dev-team" -out jane.csrThe subject is the identity. CN becomes the username and each O becomes a group. RBAC bindings refer to exactly these strings.
3. Submit and Approve the Request
The request goes into the object base64-encoded on a single line:
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
EOFkubectl get csr janeNAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
jane 0s kubernetes.io/kube-apiserver-client kubernetes-admin 24h PendingApprove it and collect the certificate:
kubectl certificate approve jane
kubectl get csr jane
kubectl get csr jane -o jsonpath='{.status.certificate}' | base64 -d > jane.crt
openssl x509 -in jane.crt -noout -subject -enddateThe condition becomes Approved,Issued and the certificate shows subject=O=dev-team, CN=jane.
Three fields trip people up:
signerNamemust bekubernetes.io/kube-apiserver-clientfor a user certificate.usagesmust beclient authfor that signer.requestmust be base64 of the CSR file with no line breaks.base64 -w0does that on Linux; piping throughtr -d '\n'works on Linux and macOS alike.
kubectl certificate deny jane is the opposite of approve. A denied request cannot be approved later; delete it and submit a new one.
4. Build the kubeconfig Entry
kubectl config set-credentials jane \
--client-key=jane.key --client-certificate=jane.crt --embed-certs=true
kubectl config set-context jane \
--cluster=kind-k8s-lab --user=jane --namespace=dev
kubectl --context jane get podsError from server (Forbidden): pods is forbidden: User "jane" cannot list resource "pods" ...Forbidden is the right result. Authentication worked, because the API server knows this is jane. Authorization has not been granted yet.
5. Grant Access with RBAC
kubectl -n dev create role pod-reader --verb=get,list,watch --resource=pods
kubectl -n dev create rolebinding jane-pod-reader --role=pod-reader --user=janeVerify from both sides:
kubectl --context jane get pods # works, empty list
kubectl --context jane get secrets # Forbidden
kubectl auth can-i list pods -n dev --as jane # yes
kubectl auth can-i delete pods -n dev --as jane # no
kubectl auth can-i --list -n dev --as janekubectl auth can-i --as checks permissions without needing the user’s credentials, so it is the fastest way to verify an RBAC task in the exam.
6. Controlled Failure Scenario: The Binding That Matches Nobody
Bind the same Role to the group instead, with a typo:
kubectl -n dev delete rolebinding jane-pod-reader
kubectl -n dev create rolebinding dev-pod-reader --role=pod-reader --group=dev-teams
kubectl --context jane get podsAccess is denied again and nothing reports an error, because RBAC never validates that a subject exists. Compare what the certificate says with what the binding says:
openssl x509 -in jane.crt -noout -subject
kubectl -n dev get rolebinding dev-pod-reader -o jsonpath='{.subjects}'
kubectl auth can-i list pods -n dev --as jane --as-group dev-team
kubectl auth can-i list pods -n dev --as jane --as-group dev-teamsFix it by recreating the binding with --group=dev-team. Group-based bindings are the better design: the next user only needs a certificate with the same O.
7. Cleanup
kubectl delete namespace dev
kubectl delete csr jane
kubectl config delete-context jane
kubectl config delete-user jane
rm -f jane.key jane.csr jane.crtA client certificate cannot be revoked. Deleting the binding removes the access; the certificate itself stays valid until it expires, which is the reason to keep expirationSeconds short.
Further reading
Next Lab
Proceed to Lab CKA-07 — Control Plane & Kubelet Repair, or return to the CKA Track.