Skip to the document
Madhuopen lab
The Kubernetes Ninja PathTrack 1 — Kubernetes from the ground up

Chapter 11

RBAC & Security Basics — Who Can Do What

6 min read read1,507 wordsIntermediate6 recall cards

Before you read, guess

How 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.

Analogy: the office keycard system.
  • 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.
The profile alone opens nothing. Writing "this profile opens floor 3" into the system doesn't let anyone in — not until someone programs an actual card to use it. That's the whole Role-vs-Binding split in one line: a Role is a permission written down; a Binding is that permission handed to somebody. Kubernetes keeps these separate on purpose, so one permission can be defined once and handed to many identities.

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.

Exam trap: 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.
Try it: Create a Role called 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.

Next up: Helm — packaging up everything you've learned so far into repeatable, versioned releases instead of a pile of YAML files.

Before you go

In one sentence, what was this chapter about?

From memory, without scrolling up. Writing it is what makes it yours; the grade is only to show you what you had.

How sure?