Skip to main content

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.md
  • docs/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:

  1. Generate a secure Private Key and CSR on the client side.
  2. Submit the CSR to the Kubernetes Certificate API.
  3. Have a Cluster Admin approve and sign the request.
  4. Build a Kubeconfig that uses the issued certificate.
  5. 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

  1. X.509 has no Revocation: Kubernetes cannot easily revoke a certificate once signed. This is why Short TTLs (expirationSeconds) are mandatory for production.
  2. CN = User: The API Server hard-codes the Common Name field to the identity.
  3. Embedding is Portability: Using --embed-certs=true ensures the Kubeconfig file is self-contained and doesn't rely on local file paths.
  4. mTLS is 2-Way: The client verifies the server via certificate-authority, and the server verifies the client via client-certificate.