Kubernetes User Authentication & Authorization
Certificate-Based User Creation with RBAC (End-to-End)

I'm a DevOps enthusiast and software engineer with 3+ years of hands-on experience building scalable CI/CD pipelines, automating infrastructure, and streamlining deployment workflows. I specialize in tools like Jenkins, Maven, Docker, and Tomcat, and I love turning complex systems into elegant, maintainable solutions. On Hashnode, I share insights, tutorials, and real-world lessons from the trenchesโwhether it's debugging flaky builds, optimizing deployment strategies, or exploring the latest in cloud-native tech. My goal is to help developers and ops teams collaborate better, ship faster, and learn continuously.4
In the previous article, we learned how RBAC works and how Kubernetes decides who can do what using Roles, RoleBindings, and ServiceAccounts.
However, RBAC answers only one part of the security story.
Before Kubernetes can authorize a request, it must first answer:
Who is the user making this request?
This article completes that missing piece by demonstrating certificate-based user authentication, followed by RBAC authorization.
By the end of this guide, you will understand:
How Kubernetes authenticates users
How certificates map to users and groups
How RBAC permissions are applied after authentication
๐น Authentication vs Authorization (Quick Context)
Kubernetes security works in two phases:
Authentication โ Who are you?
Authorization (RBAC) โ Are you allowed to do this?
This article focuses on authentication first, then connects it back to RBAC authorization.
๐น Prerequisites
Before starting, ensure you have:
Cluster admin access
A running Kubernetes cluster (Minikube or otherwise)
User machine with:
opensslkubectlbase64
๐น Stage 1 โ User Side: Generate Certificate Signing Request (CSR)
In Kubernetes, users are external identities.
They are authenticated using certificates, not Kubernetes resources.
Step 1: Create Working Directory
mkdir -p ~/.certs && cd ~/.certs
Step 2: Generate Private Key and CSR
# Create 2048-bit RSA private key
openssl genrsa -out divakar.key 2048
# Create CSR with CN=username and O=group
openssl req -new -key divakar.key -out divakar.csr -subj "/CN=divakarchakali/O=group"
CN (Common Name) โ Kubernetes username
O (Organization) โ Kubernetes group
These values must match RBAC subjects exactly.
Step 3: Encode CSR for Cluster Admin
cat divakar.csr | base64 | tr -d '\n'
Copy the output and share it securely with the cluster administrator.
๐น Stage 2 โ Admin Side: Process CSR & Issue Certificate
The cluster admin is responsible for validating and approving the CSR.
Step 1: Create CSR Manifest
Manifest: csr-requests.yaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: csr-request
spec:
groups:
- system:authenticated
request: <PASTE_BASE64_ENCODED_CSR_HERE>
signerName: kubernetes.io/kube-apiserver-client
usages:
- digital signature
- key encipherment
- client auth
Step 2: Apply & Verify CSR
kubectl apply -f csr-requests.yaml
Verify the request:
kubectl get csr csr-request -o jsonpath='{.spec.username}'
kubectl describe csr csr-request | grep -A5 "Subject:"
Ensure the subject shows:
CN=divakarchakali
Step 3: Approve CSR
kubectl certificate approve csr-request
Step 4: Extract Signed Certificate
kubectl get csr csr-request -o jsonpath='{.status.certificate}' | base64 -d > divakar.crt
Step 5: Share Certificate with User
Send the following to the user securely:
divakar.crt(signed client certificate)ca.crt(cluster CA certificate)Cluster CA certificate through JSONPath
kubectl config view -o jsonpath='{range .clusters[*]}{.name}{"\t"}{.cluster.certificate-authority-data}{"\n"}{end}'Cluster CA with
--rawkubectl config view --raw
Cluster details:
API server URL
Cluster name
Example cluster reference:
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: /path/to/ca.crt # Encoded CA
server: https://api-kops-k8s-local-airxxx-e46xxx0x0xxxxeb8.elb.us-east-2.amazonaws.com
tls-server-name: api.internal.kops.k8s.local
name: kops.k8s.local
users: []
contexts: []
current-context: ""
๐น Stage 3 โ User Side: Configure kubeconfig
Now the user configures local access using the issued certificate.
Step 1: Prepare kubeconfig Directory
mkdir -p ~/.kube/ && cd ~/.kube/
cp ~/.certs/divakar.crt ~/.certs/divakar.key ~/.kube
Step 2: Verify Certificate CN (Critical)
openssl x509 -in divakar.crt -text -noout | grep "Subject:.*CN"
Expected output:
Subject: O=group, CN=divakarchakali
Step 3: Configure kubeconfig
3.1 Set Credentials
kubectl config set-credentials divakarchakali \
--client-certificate=divakar.crt \
--client-key=divakar.key \
--embed-certs=true
3.2 Set Context
kubectl config set-context divakar-context \
--cluster=kops.k8s.local\
--user=divakarchakali \
--namespace=default
3.3 Switch Context
kubectl config use-context divakar-context
Step 4: Verify kubeconfig
kubectl config view --minify | grep -A5 users
Test access:
kubectl get nodes
๐น Expected Results
Authentication Success (Authorization Not Yet Granted)
Error from server (Forbidden): nodes is forbidden: User "divakarchakali" cannot list resource "nodes"
โ
Authentication works
โ Authorization not yet configured
This is expected.
Authentication Failure
Unable to connect to the server: x509: certificate signed by unknown authority
Check:
CA certificate path
Server URL
Certificate files
๐น Stage 4 โ Admin: Grant RBAC Permissions
Now we move from authentication to authorization.
Default roles in kubernetes:
admin: Grants read-write access to all resources within a namespace.
cluster-admin: Provides read-write access to many resources across the entire cluster.
edit: Allows users to create, update, and delete core resources like deployments, services, and configmaps.
view: Offers read-only access to most resources, excluding secrets.
Always grant access based on the principle of Least Privilege โ assign the minimal role necessary for a user to perform their tasks. For example:
Developers typically need the edit role.
Operators or team leads may require admin.
Cluster administrators should be limited to cluster-admin only when essential.
Use view for monitoring or troubleshooting without modification rights.
Cluster-Wide Access (View Only)
kubectl create clusterrolebinding divakar-view \
--clusterrole=view \
--user=divakarchakali
Namespace-Scoped Access
kubectl create rolebinding divakar-editor \
--clusterrole=edit \
--user=divakarchakali \
-n default
โ ๏ธ
subjects.namemust match the certificate CN exactly.
RBAC Verification
kubectl auth can-i list pods --namespace=default
kubectl auth can-i get nodes --as=divakarchakali
๐น Final Verification (User)
kubectl config use-context divakar-context
kubectl get pods -n default
kubectl get nodes
Access should now succeed based on granted RBAC roles.
๐น Troubleshooting
| Issue | Command | Fix |
| x509 error | openssl verify -CAfile ca.crt divakar.crt | Fix CA path |
| Forbidden error | kubectl auth can-i list pods --as=divakarchakali | Add RBAC |
| Context mismatch | kubectl config view --minify | Fix user/context |
๐น Summary
Kubernetes users are authenticated using certificates
CN maps to username, O maps to groups
Authentication happens before RBAC
RBAC decides what the user can do
kubectl auth can-iis your best debugging tool
With this, the security lifecycle is complete:
Identity
Authentication
Authorization



