Project Lab 07: Identity Bootstrapping & PKI Management
In a production cluster, you never share the admin.conf file. Every user must have their own identity. Kubernetes doesn't have a "User" object in its database; instead, it trusts any request signed by the Cluster Root CA. This lab demonstrates how to securely issue a new identity and package it for use.
Reference Material:
docs/06-authentication-authorisation-admissioncontrol/2-kubeconfig.mddocs/06-authentication-authorisation-admissioncontrol/4-external-access.md
1. OBJECTIVE: PROVISIONING "USER SEEMA"
The goal is to provide a new auditor, Seema, with cluster access:
- Generate a secure Private Key and CSR on the client side.
- Submit the CSR to the Kubernetes Certificate API.
- Have a Cluster Admin approve and sign the request.
- Build a Kubeconfig that uses the issued certificate.
- Prove Identity: Verify that the API server recognizes the request as coming from user "seema".
2. PHASE 1: CLIENT-SIDE CREDENTIAL GENERATION
Seema (the client) must generate her own private key. It should never be sent to the administrator.
2.1 Generate Private Key and CSR
The Common Name (CN) is the field Kubernetes uses to determine the Username.
# 1. Generate 2048-bit RSA Private Key
openssl genrsa -out seema.key 2048
# 2. Generate the CSR
# /CN=seema identifies the user.
# /O=auditors identifies the group (optional).
openssl req -new -key seema.key -out seema.csr -subj "/CN=seema/O=auditors"
3. PHASE 2: THE KUBERNETES CSR LIFECYCLE
The Administrator receives the seema.csr file and registers it with the cluster.
3.1 Create the CSR Object
The CSR file must be Base64 encoded to be embedded in the YAML.
cat seema.csr | base64 | tr -d '\n'
Manifest: seema-csr.yaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: seema-identity-request
spec:
# Paste the base64 string from the previous command here
request: <BASE64_ENCODED_CSR>
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 86400 # 24 hours (Best Practice: Short TTL)
usages:
- client auth
3.2 Approve the Identity
# 1. Apply the request
kubectl apply -f seema-csr.yaml
# 2. Inspect the request (Status will be Pending)
kubectl get csr seema-identity-request
# 3. Approve as Administrator
kubectl certificate approve seema-identity-request
4. PHASE 3: EXTRACTING THE CERTIFICATE
Once approved, the signed certificate is stored inside the Kubernetes object.
# Extract the signed crt and decode it
kubectl get csr seema-identity-request -o jsonpath='{.status.certificate}' | base64 -d > seema.crt
Audit the Certificate: Ensure the issuer is the Kubernetes Cluster CA.
openssl x509 -in seema.crt -text -noout | grep -E "Subject:|Issuer:"
5. PHASE 4: BUILDING THE KUBECONFIG
We will now build a completely separate Kubeconfig file that Seema can use.
5.1 Initialize the Config
We need the Cluster CA (ca.crt) so the client can verify the API server.
# 1. Set the Cluster info
kubectl config set-cluster production \
--server=https://<API_SERVER_IP>:6443 \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--kubeconfig=seema.kubeconfig
# 2. Set the User credentials (using the new cert and key)
kubectl config set-credentials seema \
--client-certificate=seema.crt \
--client-key=seema.key \
--embed-certs=true \
--kubeconfig=seema.kubeconfig
# 3. Set the Context
kubectl config set-context seema-prod \
--cluster=production \
--user=seema \
--namespace=default \
--kubeconfig=seema.kubeconfig
6. PHASE 5: THE IDENTITY TEST
Note: At this stage, Seema is Authenticated but Unauthorized. If she tries to run a command, she will get a 403 Forbidden error because we haven't assigned RBAC yet (this is covered in Lab 08).
6.1 Validate Identity Recognition
Use the auth can-i tool to prove the API server knows "who" is calling.
# Run command using the new kubeconfig
kubectl --kubeconfig=seema.kubeconfig auth can-i list pods
Expected Output:
no
Wait, why "no"? Because "seema" has no permissions. However, notice it didn't say "unauthorized" or "invalid token."
6.2 The "As" Trick (Admin Verification)
The administrator can verify exactly what Seema can do without her kubeconfig:
kubectl auth can-i list pods --as=seema
7. TROUBLESHOOTING & NINJA COMMANDS
7.1 "SignerName" Mismatch
If you use the wrong signerName in the CSR YAML, the request will be approved but the certificate will never be issued.
- Correct Signer:
kubernetes.io/kube-apiserver-client
7.2 Inspecting SANs
If Seema receives x509: certificate is valid for ..., not <IP>, the API Server's own certificate is missing the IP/DNS she is using.
- Reference: Check
docs/06-authentication-authorisation-admissioncontrol/3-mtls-in-kubernetes.md.
7.3 Cleaning Up Expired CSRs
# Delete all CSRs that have been issued to keep the API clean
kubectl delete csr --all
8. ARCHITECT'S KEY TAKEAWAYS
- X.509 has no Revocation: Kubernetes cannot easily revoke a certificate once signed. This is why Short TTLs (
expirationSeconds) are mandatory for production. - CN = User: The API Server hard-codes the Common Name field to the identity.
- Embedding is Portability: Using
--embed-certs=trueensures the Kubeconfig file is self-contained and doesn't rely on local file paths. - mTLS is 2-Way: The client verifies the server via
certificate-authority, and the server verifies the client viaclient-certificate.