One thing I discovered today is that before Kubernetes can decide what you're allowed to do, it first needs to know who you are.
That means there are two separate steps:
- Authentication – Proving your identity using a client certificate.
- Authorization – Deciding what you're allowed to do using RBAC.
In this lab, I created my own Kubernetes user named adeoye, authenticated the user with a certificate, and then used RBAC to control what that user could access.
Step 1 – Generate a Private Key
openssl genrsa -out adeoye.key 2048
This generates a 2048-bit RSA private key.
Think of this as your digital identity. It should never be shared.
Step 2 – Generate a Certificate Signing Request (CSR)
openssl req -new -key adeoye.key -out adeoye.csr -subj "/CN=adeoye"
A Certificate Signing Request asks Kubernetes to issue a client certificate.
The important part is:
/CN=adeoye
The Common Name (CN) becomes the Kubernetes username.
Step 3 – Base64 Encode the CSR
cat adeoye.csr | base64 | tr -d '\n'
Kubernetes expects the CSR to be embedded inside a YAML manifest as Base64-encoded text. The tr -d '\n' removes line breaks so it becomes a single continuous string.
Step 4 – Submit the CSR
After inserting the encoded CSR into csr.yaml, I submitted it.
kubectl apply -f csr.yaml
Initially, the request was in the Pending state so I had to approve the request.
Step 5 – Approve the Certificate
kubectl certificate approve adeoye
Approving the request tells Kubernetes to trust the user and issue a signed client certificate.
Step 6 – Extract the Signed Certificate
kubectl get csr adeoye -o jsonpath='{.status.certificate}' | base64 -d > adeoye.crt
Now I had:
adeoye.keyadeoye.crt
The key proves my identity, while the certificate proves Kubernetes trusts that identity.
Step 7 – Configure kubectl
kubectl config set-credentials adeoye \
--client-key=adeoye.key \
--client-certificate=adeoye.crt
Then I created a context.
kubectl config set-context adeoye \
--cluster=kind-cka-cluster3 \
--user=adeoye
A mistake I made: I initially typed
lind-cka-cluster3instead ofkind-cka-cluster3, which caused API errors until I corrected the cluster name.
Finally, I switched to my new user.
kubectl config use-context adeoye
At this point I was authenticated, but I still didn't have permissions to perform actions.
RBAC Time!
Authentication tells Kubernetes who I am.
RBAC tells Kubernetes what I'm allowed to do.
Creating the Role
role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs:
- get
- watch
- list
This Role only allows reading Pods.
Apply it:
kubectl apply -f role.yaml
Creating the RoleBinding
binding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
- kind: User
name: adeoye
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
This binds the adeoye user to the pod-reader Role.
kubectl apply -f binding.yaml
Testing the Permissions
Verify permission:
kubectl auth can-i get pods
Output:
yes
List Pods:
kubectl get pods
Output:
No resources found in default namespace.
That means the command succeeded, but there were simply no Pods.
Next, I tried listing Deployments.
kubectl get deploy
Output:
Error from server (Forbidden): deployments.apps is forbidden
Why Could I Read Pods but Not Deployments?
The answer is in the Role.
It only grants access to:
resources:
- pods
It does not include Deployments.
Deployments belong to the apps API group, while Pods belong to the core API group.
Since my RoleBinding connects adeoye to the pod-reader Role, Kubernetes only allows the permissions defined there.
No Deployment permissions were granted, so Kubernetes correctly denied access.
This is the Principle of Least Privilege in action.
What I Learned
- Kubernetes first authenticates users using client certificates.
- The certificate's Common Name becomes the Kubernetes username.
- A Role defines permissions.
- A RoleBinding assigns those permissions to users.
- Authentication and authorization are separate processes.
- RBAC only grants explicitly defined permissions.
- Pods and Deployments are different resources, so access to one doesn't imply access to the other.
Final Thoughts
Today's lab tied together authentication and authorization. Creating my own client certificate, configuring a new kubectl context, and then restricting that user with RBAC made the concepts much easier to understand.
Security in Kubernetes isn't about giving users full access,but about giving them exactly the permissions they need, nothing more.
Top comments (0)