Access control: RBAC
Everything in Kubernetes is a request to the API server: "list Pods", "delete this Deployment", "read that Secret". RBAC (Role-Based Access Control) decides which requests are allowed. Think of it as the key cards in an office building: each card opens some doors and not others.
Who are you, and what may you do?
Every request goes through two checks at the front desk of the API server:
- Authentication proves identity. Kubernetes does not store users itself; it trusts certificates, tokens, or your company login (OIDC).
- Authorization is RBAC: rules that say "this identity may do these actions on these things".
- RBAC starts from nothing allowed. Rules only ever add permissions. There are no "deny" rules.
Subjects: users, groups, ServiceAccounts
A subject is whoever is making the request.
User
A person, like alice. Only a name inside a certificate or token; there is no User object to create.
Group
A set of users, like developers. Comes from the same login system. Bind a role to a group instead of to ten people.
ServiceAccount
An identity for programs running in Pods, like a CI tool or a controller. A real Kubernetes object, living in a namespace.
The four objects
RBAC is just two questions: what is allowed (a Role) and who gets it (a binding). Each comes in a namespace version and a cluster-wide version:
| Inside one namespace | Whole cluster | |
|---|---|---|
| What is allowed | Role | ClusterRole |
| Who gets it | RoleBinding | ClusterRoleBinding |
view, edit, admin and cluster-admin.Writing a Role
A rule is three lists: which API groups, which resources, which verbs. Click the parts:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: blog-editor
namespace: blog
rules:
- apiGroups: ["", "apps"]
resources: ["pods", "services", "configmaps", "deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: dev-edit
namespace: blog
subjects:
- kind: Group
name: developers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: blog-editor
apiGroup: rbac.authorization.k8s.io
namespace
A Role only works inside its own namespace. Use a ClusterRole for cluster-wide things like nodes.
apiGroups
Which family the resource belongs to. "" means the core group (Pods, Services, ConfigMaps, Secrets). "apps" holds Deployments and StatefulSets. The apiVersion of an object tells you its group: apps/v1 → apps.
resources
Plural, lowercase names, as in kubectl get. Sub-resources like pods/log or pods/exec must be listed separately.
verbs
The actions: get (one), list and watch (many), create, update, patch, delete. Read-only access is just get, list, watch.
subjects
Who gets the role: users, groups or ServiceAccounts. A list, so one binding can cover several.
roleRef
Which Role (or ClusterRole) is granted. It cannot be changed later; delete and recreate the binding instead.
Try it: can they do it?
This cluster has four subjects and four bindings. Pick a subject, an action and a namespace. The answer is exactly what kubectl auth can-i would say:
Try: alice deleting Pods in blog (yes) and in payments (no). bob listing Pods anywhere (yes, a ClusterRoleBinding). anyone reading secrets (no one).
ServiceAccounts for your Pods
Every Pod runs as a ServiceAccount. If you do not choose one, it gets the namespace's default ServiceAccount. Kubernetes can mount a short-lived token for it into the Pod, so code in the Pod can call the API.
apiVersion: v1
kind: ServiceAccount
metadata:
name: posts-sa
namespace: blog
---
# in the Deployment's Pod template
spec:
serviceAccountName: posts-sa
containers:
- name: posts
image: micro-posts:1.0Give the app its own ServiceAccount, and bind only the Role it needs, for example "read ConfigMaps". Never give extra rights to default; every Pod in the namespace would get them.
spec:
automountServiceAccountToken: false
containers:
- name: posts
image: micro-posts:1.0Most web apps, like posts and comments, never talk to the Kubernetes API. Then do not mount a token at all: if the app is hacked, there is no key lying around to steal.
kubectl auth can-i
$ kubectl auth can-i create deployments -n blog
yes
$ kubectl auth can-i get secrets -n blog --as=alice
no
$ kubectl auth can-i list configmaps -n blog \
--as=system:serviceaccount:blog:posts-sa
yes
$ kubectl auth can-i --list -n blog --as=alice # everything alice may do
--as lets an admin test as someone else, without logging in as them. Use it after every RBAC change.
Dangerous permissions
Some rights look harmless but quietly give away much more. Pick the safe answer:
verbs: ["*"],resources: ["*"]"to save time"Wildcards include everything, even resource types added to the cluster later. List exactly what is needed.
- Letting a team
create podsin a namespace but not read SecretsWhoever can create a Pod can mount any Secret of that namespace into it, or run it as any ServiceAccount there. "Create pods" is almost "read all Secrets".
- Binding
cluster-adminto a CI ServiceAccount "so deploys never fail"A leaked CI token would then own the entire cluster. Give CI only what it deploys, in the namespaces it deploys to.
list secrets"just to see the names"listreturns the full objects, values included, not just names.- The built-in
viewClusterRole, bound per namespace for the support teamGood choice: read-only, and
viewdeliberately excludes Secrets.
Also watch out for pods/exec (a shell in any container), escalate and bind on roles (grant yourself more), and impersonate (act as anyone).
RBAC for the blog app
| Who | Gets | How |
|---|---|---|
| posts, comments, query, moderation, event-bus | Nothing | automountServiceAccountToken: false |
| Developers (group) | Edit in blog, no Secrets | RoleBinding to a custom Role, or to edit if Secret access is acceptable |
| Support team | Read-only | RoleBinding to view |
| CI pipeline | Update Deployments in blog | Its own ServiceAccount + a small Role |
| Cluster admins (2 people) | Everything | ClusterRoleBinding to cluster-admin |
Good RBAC pairs well with network rules (chapter 28) and locked-down containers (chapter 42).
Recap
- Authentication = who you are; authorization (RBAC) = what you may do.
- Subjects are users, groups and ServiceAccounts.
- Role/ClusterRole = what is allowed; RoleBinding/ClusterRoleBinding = who gets it.
- Rules list apiGroups, resources and verbs. Nothing is allowed unless a rule says so.
- Give each app its own ServiceAccount, or no token at all.
- Least privilege: no wildcards, no cluster-admin for tools, careful with Secrets and creating Pods.
- Test with
kubectl auth can-i … --as=….
Quick check
edit in namespace blog. Can she edit Deployments in payments?Show answer
No. A RoleBinding only grants access inside its own namespace, even when it points to a ClusterRole. Only a ClusterRoleBinding reaches every namespace.
RBAC: common questions
What is the difference between a Role and a ClusterRole?
A Role grants permissions inside one namespace. A ClusterRole is defined cluster-wide and can cover cluster resources like nodes; it can be granted per namespace with a RoleBinding or everywhere with a ClusterRoleBinding.
How do I check if a user can do something?
Run kubectl auth can-i with the verb, resource and namespace, and add --as to test as another user or ServiceAccount.