Chapter 11
RBAC & Security Basics — Who Can Do What
Before you read, guessHow do human users and ServiceAccounts differ in their authentication within Kubernetes?
Take ten seconds and guess — even a wrong guess makes the answer stick. Tap to see where the chapter lands, or just read on.
Human users are usually authenticated outside Kubernetes (cloud IAM, for example); ServiceAccounts are native Kubernetes identities for Pods and apps, like a CI bot.
Back in Post 2, you met the kube-apiserver as the front door everything talks through. But a front door with no lock isn't security, it's just a hallway. Today you're installing the lock: who's allowed through this door, and once they're in, what are they actually allowed to touch?
The question RBAC answers
Every request that hits the kube-apiserver goes through two checks, in order. First: authentication — are you a real, recognized identity, or a stranger? Second, only if the first passes: authorization — we know who you are, but are you allowed to do this specific thing?
Kubernetes supports a few ways to run that second check. The one you'll configure, and the one the CKA exam tests, is RBAC — Role-Based Access Control.
RBAC answers exactly one question: can this identity perform this verb on this resource in this namespace? Identity is the requester. Verb is the action — get, list, create, delete, update. Resource is the thing acted on — pods, deployments, secrets, nodes. Namespace is the folder inside the cluster the request applies to.
All three parts must match, or the answer is no. Being allowed to list pods in dev says nothing about whether you can delete deployments in prod. RBAC is deliberately this narrow.
Two kinds of identity walking through the front door
Authentication has to answer "who are you," and there are two kinds of "who" in a cluster.
Human users — you, your teammates — usually aren't managed inside Kubernetes at all. Kubernetes has no built-in user database; it trusts an external source instead, often your cloud provider's identity system. Once you're on GCP later in this series, your Google identity and IAM permissions will feed straight into cluster access — more on that in a future post.
ServiceAccounts are the other kind, native to Kubernetes itself. A ServiceAccount is an identity for a Pod or an application, not a person — a CI/CD pipeline checking deployment status, say, or an app listing its own pods for a health dashboard. Every namespace gets a default ServiceAccount automatically; real setups create purpose-specific ones, like the CI bot below.
The four objects — and the pairing that trips everyone up
RBAC is built from exactly four object types, in two matched pairs. Get the pairing straight and the rest is easy.
Role — permission rules (which verbs on which resources) scoped to one namespace. A Role defined in dev only means something in dev; it has zero reach into prod.
ClusterRole — the same idea, not tied to one namespace. Use it when the rules should apply cluster-wide, or when the resource itself isn't namespaced at all — nodes and PersistentVolumes live outside any namespace, so only a ClusterRole can grant access to them.
RoleBinding — the object that actually hands a Role (or a ClusterRole) to a real identity — a user, a group, or a ServiceAccount — inside one namespace. ClusterRoleBinding does the same thing cluster-wide, with no namespace boundary.
Here's the single most important idea in this whole post: a Role or ClusterRole, by itself, grants nobody anything. It's just a definition sitting in etcd (Kubernetes' backing datastore) until a Binding attaches it to a real identity. This is the #1 RBAC mistake: writing a perfectly correct Role, then wondering why nothing works — because no Binding ever handed it to anyone.
- Role = a keycard PROFILE. "This profile opens the floor-3 supply closets." Floor 3 is your namespace. Supply closets are your resources.
- ClusterRole = a MASTER profile. It works building-wide, or it's required for shared infrastructure like the fire escape — things that don't belong to any one floor.
- RoleBinding = programming one person's keycard to use a Role's profile — floor 3 only.
- ClusterRoleBinding = programming a keycard to use a ClusterRole's profile — building-wide.
Least privilege isn't a suggestion
The single biggest real-world RBAC mistake is reaching for cluster-admin — the built-in ClusterRole that can do anything, anywhere — because it's the fastest way to make an error message go away. Resist this, every time.
Least privilege means granting exactly the verbs and resources an identity needs, nothing more. Don't ask "what grant makes the error stop?" Ask "what's the smallest grant that makes this work?"
The CI bot above only needs to read pod status, so it should never be able to delete a Secret. Tokens leak — that's a fact of running real systems, not a hypothetical. When one does, least privilege is the difference between "an attacker can see some pods" and "an attacker owns your cluster."
Hands-on: building a scoped identity from scratch
Let's build the CI bot — a ServiceAccount that can read pods and nothing else. First, the identity itself:
$ kubectl create serviceaccount ci-bot
serviceaccount/ci-bot created
Now the permission slip — a Role scoped to default, allowing only reads on pods:
$ kubectl create role pod-reader \
--verb=get,list,watch \
--resource=pods
role.rbac.authorization.k8s.io/pod-reader created
Notice what's missing: no create, no delete, no update. This bot can look, not touch. Now the binding — the step that hands that slip to ci-bot:
$ kubectl create rolebinding ci-bot-binding \
--role=pod-reader \
--serviceaccount=default:ci-bot
rolebinding.rbac.authorization.k8s.io/ci-bot-binding created
That default:ci-bot text is namespace:serviceaccount-name — memorize this format, it shows up constantly. Let's inspect what we built:
$ kubectl get rolebindings
NAME ROLE AGE
ci-bot-binding Role/pod-reader 1m
$ kubectl describe role pod-reader
Name: pod-reader
Namespace: default
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get list watch]
Never trust the YAML — verify it
You could stare at that output and reason your way to "yes, this should work." Don't. Kubernetes gives you a command that skips the guessing and asks the API server directly, impersonating the exact identity in question:
$ kubectl auth can-i list pods --as=system:serviceaccount:default:ci-bot
yes
$ kubectl auth can-i delete deployments --as=system:serviceaccount:default:ci-bot
no
The answer matches exactly what you built: it can list pods (what the Role granted) and cannot delete deployments (what it was never granted). Note the impersonation string's format — system:serviceaccount:<namespace>:<name> — worth memorizing on its own.
kubectl auth can-i is the fastest way to verify RBAC on the CKA exam and in real clusters — full stop. Under time pressure, the instinct is to apply your Role and RoleBinding YAML and trust it looks right. Don't. A typo in a resource name, a missing verb, a RoleBinding pointing at the wrong ServiceAccount or namespace — all of these apply cleanly with zero errors and still grant the wrong permissions. Always follow up with kubectl auth can-i <verb> <resource> --as=<identity> and confirm the real answer.pod-manager with --verb=get,list,watch,delete on pods, bind it to a new ServiceAccount called ops-bot, and use can-i delete pods --as=system:serviceaccount:default:ops-bot to confirm yes — then confirm ci-bot still says no to the same check.Where ClusterRole and ClusterRoleBinding come in
Everything above stayed inside one namespace on purpose — that's the shape of most real permissions. Reach for a ClusterRole and ClusterRoleBinding in two cases: the resource is cluster-scoped (nodes, PersistentVolumes), or an identity genuinely needs the same access everywhere, like a monitoring tool reading pod metrics in every namespace. The commands mirror what you just ran — kubectl create clusterrole and kubectl create clusterrolebinding — just without a namespace. Use them deliberately: the master keycard that opens every floor should be rare.
Key Takeaways
- Every API server request is authenticated (who are you?) then authorized (are you allowed to do this?) — RBAC is the authorization layer, answering "which verbs on which resources in which namespace."
- Human users are usually authenticated outside Kubernetes (cloud IAM, for example); ServiceAccounts are native Kubernetes identities for Pods and apps, like a CI bot.
- A Role or ClusterRole is a permission written down — like a keycard profile. It grants nothing alone. A RoleBinding or ClusterRoleBinding hands that permission to a specific identity — like programming an actual keycard.
- Role/RoleBinding are namespace-scoped; ClusterRole/ClusterRoleBinding are cluster-wide, or required for cluster-scoped resources like nodes.
- Practice least privilege as a default mindset — grant exactly the verbs and resources needed, and never reach for cluster-admin just to silence an error.
- Always verify RBAC with
kubectl auth can-i <verb> <resource> --as=<identity>— don't trust YAML you haven't tested against the real API server.