RBAC Builder + Explainer
Build Kubernetes Role and RoleBinding YAML, or paste any existing RBAC and get a plain-English summary with live security warnings. Runs entirely in your browser.
Recipe
Role
Rule #1
| resource | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
create — you can't restrict create-by-name.Rule #2
| resource | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
create — you can't restrict create-by-name.Rule #3
| resource | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
create — you can't restrict create-by-name.Rule #4
| resource | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
create — you can't restrict create-by-name.Rule #5
| resource | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
create — you can't restrict create-by-name.Rule #6
| resource | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ✓ | ✓ | |||||||||||
create — you can't restrict create-by-name.Binding
Security review
highRead all secrets. This rule allows reading every Secret in scope — including API keys, database passwords, TLS private keys, and ServiceAccount tokens. Possessing a ServiceAccount token is functionally equivalent to acting as that account, so read-all-secrets in a namespace is read-all-permissions for that namespace. Use `resourceNames:` to scope to specific Secret names if possible, or split your secrets across namespaces so this role doesn't need cluster-wide reach.(Rule #1)
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: viewer namespace: default rules: - apiGroups: [""] resources: ["*"] verbs: ["get", "list", "watch"] - apiGroups: ["apps"] resources: ["*"] verbs: ["get", "list", "watch"] - apiGroups: ["batch"] resources: ["*"] verbs: ["get", "list", "watch"] - apiGroups: ["networking.k8s.io"] resources: ["*"] verbs: ["get", "list", "watch"] - apiGroups: ["autoscaling"] resources: ["*"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["pods/log"] verbs: ["get", "list"]
Apply with kubectlheredoc — no file write
kubectl apply -f - <<'EOF' apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: viewer namespace: default rules: - apiGroups: [""] resources: ["*"] verbs: ["get", "list", "watch"] - apiGroups: ["apps"] resources: ["*"] verbs: ["get", "list", "watch"] - apiGroups: ["batch"] resources: ["*"] verbs: ["get", "list", "watch"] - apiGroups: ["networking.k8s.io"] resources: ["*"] verbs: ["get", "list", "watch"] - apiGroups: ["autoscaling"] resources: ["*"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["pods/log"] verbs: ["get", "list"] EOF
Then confirm it landed:
kubectl describe role/viewer -n default
How RBAC works in Kubernetes
Kubernetes RBAC has four object kinds. Role and ClusterRole describe a set of permissions — verbs (actions) on resources, optionally scoped by name. RoleBinding and ClusterRoleBinding attach those permissions to subjects (Users, Groups, or ServiceAccounts). A role by itself grants nothing; only the binding wires permissions to identities.
Each rule in a role has up to five fields:
apiGroups,
resources,
verbs,
resourceNames,
and (for ClusterRole) nonResourceURLs. apiGroups identifies which Kubernetes API the resource lives in (the core group is the empty string ""; named groups are things like apps, batch, rbac.authorization.k8s.io). resources picks the resource types within that group, with subresources expressed as parent/sub (pods/exec, pods/log). verbs picks the actions allowed.
A role grants nothing on its own. Until a RoleBinding or ClusterRoleBinding ties it to a subject, the rules might as well not exist. When debugging "Forbidden" errors, check the binding before you check the rule.
ServiceAccounts and pods
Every pod runs as a ServiceAccount. If you don't specify one, it runs as default in its namespace. In modern Kubernetes (1.6+), the default ServiceAccount has no permissions — pods that need API access must use a custom SA wired up with bindings.
The SA's API token is auto-mounted at /var/run/secrets/kubernetes.io/serviceaccount/token. For pods that don't talk to the API, set automountServiceAccountToken: false at the pod or SA level so a compromised pod can't replay the token. Bound SA tokens (Kubernetes 1.22+) expire automatically; legacy long-lived tokens don't, and the docs strongly recommend the bound variant for any new workload.
Common RBAC patterns
The recipe selector at the top of the tool covers the patterns SREs reach for most often:
- Read-only viewer for support engineers and on-call.
- Secret manager for sealed-secrets, external-secrets, cert-manager-style operators.
- Deployment operator for namespace-scoped controllers that manage workloads.
- Pod exec for "let SRE debug" without granting write access.
- CI/CD deployer for pipeline runners (GitHub Actions, ArgoCD, Jenkins) applying manifests in one namespace.
- Cluster-wide read-only for monitoring tools and audit dashboards.
- Metrics reader for HPA and metrics-server consumers.
- CRD operator template for any controller-runtime-based operator owning a custom resource.
RBAC anti-patterns and how to avoid them
Granting cluster-admin "just for now"
It always becomes permanent. Take the extra ten minutes to build a named, scoped role even when the work is one-off. Auditing six months later, "this SA has cluster-admin because it once needed to bootstrap something" is the worst possible answer.
Wildcard secrets read
get list watch on secrets in any namespace lets the holder extract API keys, database passwords, TLS private keys, and ServiceAccount tokens. Possessing a ServiceAccount token is functionally equivalent to acting as that SA. Use resourceNames: to scope reads to specific secrets when possible, or split sensitive secrets across namespaces so this role doesn't need cluster-wide reach.
Pod create without scrutiny
The subject who can create pods can mount any volume (including hostPath), run as privileged, share host networking, or reference any ServiceAccount in the namespace — including operator identities with elevated access. Pair pod-create with PodSecurity admission and restrict the ServiceAccounts callable from the bound subjects' namespaces.
Conflating a Role with a ClusterRole
A ClusterRole bound via RoleBinding is namespace-scoped for that subject — but the ClusterRole itself remains cluster-scoped and reusable. Easy to surprise yourself: "I bound the cluster-reader ClusterRole, why does my SA only see one namespace?" Because it was bound via RoleBinding. If you wanted cluster-wide, use ClusterRoleBinding.
The 100-rule role
When a single Role accumulates 30+ rules, nobody reviews changes carefully — every PR adds "one more verb on one more resource" and the role drifts toward cluster-admin. Split by function: one role per coherent responsibility, bound separately. Smaller roles are cheaper to audit and easier to reason about.
Debugging "Forbidden" errors
The single most useful command: kubectl auth can-i. It pretends to be a subject and asks the authorizer "would this be allowed?" — without actually performing the action.
# What can the SA do?
kubectl auth can-i --list --as=system:serviceaccount:default:my-sa
# Specific check
kubectl auth can-i list pods --as=system:serviceaccount:default:my-sa
# Find every binding that mentions a subject
kubectl get rolebindings,clusterrolebindings -A \
-o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,ROLE:.roleRef.name \
| grep my-sa
The pod's actual SA is in kubectl describe pod <name> — check it before assuming "default." If the SA is wrong, the rest of the RBAC investigation is misdirected.
RBAC controls who can do what. NetworkPolicy controls what can talk to what. They're complementary cluster-hardening controls — both default-permissive, both allow-list-additive, both bite if you assume otherwise.
FAQ
What's the difference between Role and ClusterRole?
Role is namespace-scoped — its rules apply within a single namespace. ClusterRole is either cluster-scoped (granted across the whole cluster via ClusterRoleBinding) or used as a reusable template (referenced from a RoleBinding to grant the same permissions repeatedly across namespaces). The role itself doesn't grant anything; only the binding does.
Why is my pod getting `Forbidden: User cannot list resource X`?
The ServiceAccount your pod runs as doesn't have permission for that resource. Find the SA with `kubectl describe pod`, then run `kubectl auth can-i list X --as=system:serviceaccount:NS:SA-NAME` to confirm. Add a Role rule (or use an existing recipe above) granting `list` on that resource and a binding tying it to the SA.
How do I see what permissions a ServiceAccount has?
On Kubernetes 1.18+, run `kubectl auth can-i --list --as=system:serviceaccount:NAMESPACE:NAME`. It prints the full effective permission set across every Role and ClusterRole bound to that SA. For a single-action check use `kubectl auth can-i VERB RESOURCE --as=...`.
Should I use ClusterRoles for namespace-scoped permissions?
Yes if the role is reusable across namespaces — write the ClusterRole once, bind it via RoleBindings in each consuming namespace. No if the role is genuinely scoped to one namespace and one purpose; in that case write a plain Role so the scope is obvious from the manifest. The mixed pattern (ClusterRole referenced from RoleBinding) is fine but worth flagging — this tool surfaces it as an info-level warning.
What does the `*` wildcard match?
Every current resource, verb, or apiGroup at the time the request is evaluated. The authorizer doesn't try to predict future API surface, but in practice `*` does cover new resources Kubernetes adds, because they're checked against the same authorizer at request time. Be deliberate about wildcards on writes — they make future K8s upgrades silently widen your permissions.
What's `resourceNames` for?
Restricts a rule to specific named instances of a resource. e.g., allow updating only the configmap named `app-config`. The big catch: it doesn't work with `create` — the resource doesn't exist yet, so there's no name to match against. Use it for get/update/patch/delete on long-lived resources you want narrowly scoped.