Companion guide for Kubernetes RBAC: Foundations to Essentials (50 slides). Updated 12 November 2026. Examples follow Kubernetes v1.37 API documentation.
Execution status: Commands and YAML have been checked against the official Kubernetes documentation and reviewed for internal consistency. They have not been executed against your specific cluster. Run these labs in a disposable Kubernetes environment, never unreviewed in production.
Prerequisites and safety
- A working Kubernetes cluster (self-managed Kubernetes is fine; no EKS, AKS, or GKE required).
- An administrator kubeconfig that can create Namespaces, Roles, RoleBindings, ClusterRoles, ClusterRoleBindings, and CertificateSigningRequests.
kubectl,openssl,base64, and a POSIX shell such as Bash.- For the human-certificate lab, the Kubernetes control plane must have a working signer for
kubernetes.io/kube-apiserver-client. Approval does not force a signer to issue a certificate. kubectl auth can-i --as=...impersonation requires appropriate administrative impersonation permission.- Do not commit, email, screen-record, or share a private key or bearer token.
- Do not send learners a copy of an administrator kubeconfig. Set up separate, restricted learner credentials when needed.
Verify cluster access
kubectl config current-context
kubectl cluster-info
kubectl version --client
kubectl api-resources --api-group=rbac.authorization.k8s.io
kubectl api-resources --namespaced=false
Lab 0 – Create a safe namespace
kubectl create namespace rbac-lab
kubectl -n rbac-lab get pods
Lab 1 – Human user access with Role and RoleBinding
Goal: The named user mia may read Pods in rbac-lab, but may not read Secrets or read Pods in default.
This lab uses a User identity string with administrator impersonation. Kubernetes has no User API object, so there is no kubectl create user step.
Create a Role
kubectl -n rbac-lab create role pod-reader \
--verb=get,list,watch \
--resource=pods
kubectl -n rbac-lab describe role pod-reader
Bind the user
kubectl -n rbac-lab create rolebinding mia-read \
--role=pod-reader \
--user=mia
kubectl -n rbac-lab describe rolebinding mia-read
Verify three behaviors
# Expected: yes
kubectl auth can-i list pods -n rbac-lab --as=mia
# Expected: no
kubectl auth can-i get secrets -n rbac-lab --as=mia
# Expected: no
kubectl auth can-i list pods -n default --as=mia
The expected results assume a clean training cluster without extra grants for the test identity, and an administrator authorized to impersonate users.
Equivalent declarative manifest
Save as rbac-mia.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: rbac-lab
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: mia-read
namespace: rbac-lab
subjects:
- kind: User
name: mia
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
kubectl diff -f rbac-mia.yaml
kubectl apply -f rbac-mia.yaml
Lab 2 – Real human certificate and group-based access
Goal: Issue a short-duration client certificate for username alice, with group team-dev; before binding the group, Pod access fails; after binding, Pod access succeeds.
Important distinction: alice.csr is a PKCS#10 file created by OpenSSL. A Kubernetes CertificateSigningRequest is an API object containing the base64-encoded request.
1. Generate the private key and certificate request
Run on a trusted workstation. Use a private lab directory.
umask 077
openssl genrsa -out alice.key 3072
openssl req -new -key alice.key -out alice.csr \
-subj "/CN=alice/O=team-dev"
openssl req -in alice.csr -noout -subject
Expected identity: CN=alice maps to username alice and O=team-dev maps to group team-dev when using this Kubernetes X.509 authentication mechanism.
2. Create the Kubernetes CSR object
Run with credentials allowed to create CertificateSigningRequests.
CSR_B64=$(base64 < alice.csr | tr -d '\n')
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: alice-rbac-lab
spec:
request: ${CSR_B64}
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 86400
usages: ["client auth"]
EOF
This requests one day of validity. The final duration is determined by the issuer’s configuration.
3. Review, approve, and wait for actual issuance
An administrator must verify the requested subject and signer before approval.
kubectl get csr alice-rbac-lab
kubectl get csr alice-rbac-lab -o yaml
kubectl certificate approve alice-rbac-lab
kubectl get csr alice-rbac-lab -o yaml
Do not proceed just because it is Approved. Check .status.certificate is populated. The cluster signer might not be configured. A signer must issue the certificate after approval.
kubectl get csr alice-rbac-lab \
-o jsonpath='{.status.certificate}' | base64 -d > alice.crt
openssl x509 -in alice.crt -noout -subject -dates
On systems where base64 -d is unavailable, use the equivalent decode option (some BSD tools support -D).
Approving CertificateSigningRequests requires specific permissions beyond simple CSR listing: update on certificatesigningrequests/approval, and approve on the requested signers signer; grant these only to approved certificate authorities/administrators. Refer to the official CSR authorization documentation.
4. Add a user context, without switching the active context
These commands add an alice user context to the current workstation’s kubeconfig, using its existing trusted cluster entry. Never distribute that kubeconfig if it also contains administrator credentials.
CLUSTER=$(kubectl config view --minify \
-o jsonpath='{.contexts[0].context.cluster}')
kubectl config set-credentials alice \
--client-certificate=alice.crt \
--client-key=alice.key \
--embed-certs=true
kubectl config set-context alice-rbac-lab \
--cluster="$CLUSTER" \
--user=alice \
--namespace=rbac-lab
kubectl --context=alice-rbac-lab auth whoami
kubectl --context=alice-rbac-lab -n rbac-lab get pods
Initially, the last command should produce a Forbidden result because group team-dev is not bound yet. If the identity is not recognized, verify the certificate’s issuer, validity, and subject before changing RBAC.
5. Bind the group and verify the permission
kubectl -n rbac-lab create rolebinding team-dev-read \
--role=pod-reader \
--group=team-dev
# Expected: success (a zero-row result is still success)
kubectl --context=alice-rbac-lab -n rbac-lab get pods
# Expected: Forbidden
kubectl --context=alice-rbac-lab -n rbac-lab get secrets
Lab 3 – ServiceAccount identity for an application
Goal: An application ServiceAccount may read ConfigMaps in rbac-lab but not Secrets.
1. Create a ServiceAccount and one ConfigMap
kubectl -n rbac-lab create serviceaccount audit-bot
kubectl -n rbac-lab create configmap demo-config \
--from-literal=mode=training
kubectl -n rbac-lab get serviceaccounts
The authenticated Kubernetes username for this account is system:serviceaccount:rbac-lab:audit-bot.
2. Define permissions and bind them
kubectl -n rbac-lab create role configmap-reader \
--verb=get,list \
--resource=configmaps
kubectl -n rbac-lab create rolebinding audit-config-read \
--role=configmap-reader \
--serviceaccount=rbac-lab:audit-bot
3. Create a Pod using that ServiceAccount
Save as sa-demo-pod.yaml:
apiVersion: v1
kind: Pod
metadata:
name: sa-demo
namespace: rbac-lab
spec:
serviceAccountName: audit-bot
containers:
- name: app
image: busybox:1.36
command: ["sleep", "3600"]
kubectl apply -f sa-demo-pod.yaml
kubectl -n rbac-lab get pod sa-demo
kubectl -n rbac-lab get pod sa-demo -o jsonpath='{.spec.serviceAccountName}'
The Pod image is public but requires outbound registry access to pull. RBAC verification below does not depend on installing kubectl inside the Pod.
4. Verify with admin impersonation
# Expected: yes
kubectl auth can-i list configmaps -n rbac-lab \
--as=system:serviceaccount:rbac-lab:audit-bot
# Expected: no
kubectl auth can-i get secrets -n rbac-lab \
--as=system:serviceaccount:rbac-lab:audit-bot
5. Tokens and Pod hardening
# Prints a sensitive short-lived token: never use on a public projector
kubectl -n rbac-lab create token audit-bot --duration=10m
Modern Kubernetes Pods generally use projected, bounded ServiceAccount tokens. If a Pod does not need Kubernetes API access, opt out of automatic token mounting:
spec:
automountServiceAccountToken: false
Lab 4 – ClusterRole, ClusterRoleBinding, and namespaced reuse
1. Cluster-wide read of Nodes
kubectl create clusterrole lab-node-reader \
--verb=get,list,watch \
--resource=nodes
kubectl create clusterrolebinding lab-ops-node-read \
--clusterrole=lab-node-reader \
--group=ops-readers
# Expected: yes, on a clean cluster with admin impersonation permission
kubectl auth can-i list nodes \
--as=pat --as-group=ops-readers
2. Reuse a ClusterRole within just one namespace
kubectl -n rbac-lab create rolebinding qa-view \
--clusterrole=view --group=qa-team
# Expected: yes
kubectl auth can-i list pods -n rbac-lab \
--as=lea --as-group=qa-team
# Expected: no
kubectl auth can-i list pods -n default \
--as=lea --as-group=qa-team
A RoleBinding can reference a ClusterRole, but access is still restricted to that namespace. A ClusterRoleBinding may refer only to a ClusterRole.
Reference: common RBAC rules
A. Read Pod logs (different from permission to read Pods)
rules:
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
B. Get only a particular ConfigMap
rules:
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["demo-config"]
verbs: ["get"]
resourceNames does not constrain top-level create or deletecollection; list and watch restricted by resourceNames require a matching metadata.name field selector.
C. Read a custom resource (example; requires a matching CRD)
rules:
- apiGroups: ["example.com"]
resources: ["widgets"]
verbs: ["get", "list"]
D. Read a non-resource API path (ClusterRole only)
rules:
- nonResourceURLs: ["/healthz"]
verbs: ["get"]
Command summary
| Purpose | Command |
|---|---|
| Show active identity | kubectl auth whoami |
| List API resources | kubectl api-resources -o wide |
| List namespace Roles / bindings | kubectl get roles,rolebindings -n rbac-lab |
| List cluster-scoped roles / bindings | kubectl get clusterroles,clusterrolebindings |
| Describe a Role | kubectl describe role pod-reader -n rbac-lab |
| Test read permission | kubectl auth can-i list pods -n rbac-lab |
| Test as another user | kubectl auth can-i list pods -n rbac-lab --as=mia |
| See the CSR request | kubectl get csr alice-rbac-lab -o yaml |
| Approve a reviewed CSR | kubectl certificate approve alice-rbac-lab |
| Request a short-lived SA token | kubectl -n rbac-lab create token audit-bot --duration=10m |
Troubleshooting
- 401 Unauthorized: invalid, missing, or expired credentials; verify certificate trust, token, or kubeconfig selection.
- 403 Forbidden: commonly insufficient authorization, but admission policy can also reject a request. Check the entire error.
--asis rejected: your invoking identity may lack impersonation permission.- Unexpected
yes: inspect all applicable bindings, default access, and additional authorizers. ApprovedCSR without certificate: a matching signer might not be configured or willing/able to sign.- Group test fails: verify CN/O in certificate and
kubectl --context=alice-rbac-lab auth whoami. - Pod is Pending / ImagePullBackOff: inspect cluster scheduling and image pull separately from RBAC.
- A RoleBinding cannot find a Role: verify name, namespace,
roleRef.kind, and API group. roleRefcannot be changed: delete and recreate the binding as appropriate, after reviewing downstream access changes.
Cleanup
Run as the administrator after finishing all labs and confirming the resource names belong only to these labs.
kubectl delete namespace rbac-lab
kubectl delete clusterrolebinding lab-ops-node-read
kubectl delete clusterrole lab-node-reader
kubectl delete csr alice-rbac-lab
# Optional cleanup for the local lab kubeconfig (be mindful of its contents)
kubectl config delete-context alice-rbac-lab
kubectl config delete-user alice
# Remove local training-only credentials when no longer needed:
rm -f alice.key alice.csr alice.crt
Instructor quiz – with answers
- How can we allow a group to list Pods only in
rbac-lab? A Role with a RoleBinding to Group; orviewClusterRole with a RoleBinding inrbac-lab. - Can we create a human user with
kubectl create user? No. A normal user identity comes from an authenticator such as client cert or OIDC. - Can
ClusterRoleBindingpoint toRole? No; only toClusterRole. - What does certificate
CNmean? What doesOmean? Username and group for Kubernetes X.509 authentication. - Does creating a ServiceAccount grant permissions? No, bind a Role or ClusterRole as needed.
- What is the difference between
getandlist? One named object vs collection of objects. - Does approval guarantee that a CSR has an issued certificate? No, a configured signer must issue it.
- Why should
editbe considered high privilege? It grants access to Secrets and the ability to run Pods using namespace ServiceAccounts.
Official references
- Kubernetes releases: https://kubernetes.io/releases/
- RBAC authorization: https://kubernetes.io/docs/reference/access-authn-authz/rbac/
- Authentication: https://kubernetes.io/docs/reference/access-authn-authz/authentication/
- Authorization: https://kubernetes.io/docs/reference/access-authn-authz/authorization/
- CertificateSigningRequest API: https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/
- Client certificate step-by-step: https://kubernetes.io/docs/tasks/tls/certificate-issue-client-csr/
- ServiceAccounts: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
kubectl auth can-i: https://kubernetes.io/docs/reference/kubectl/generated/kubectl_auth/kubectl_auth_can-i/- Original tutorial flow: https://www.devopsschool.com/blog/understanding-authentication-authorization-in-kubernetes/