Kubernetes RBAC Viewer

Paste your Roles, ClusterRoles and their bindings, and get the answer per subject: what can this service account actually do, which binding gave it that, and does any of it lead to cluster-admin or to reading credentials.

Paste below, or drop a file anywhere on this panel

Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.

The answer appears here

Paste on the left and press Resolve. Nothing leaves this tab.

Examples

Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.

cluster-admin in all but name

Wildcards on groups, resources and verbs, which is every permission there is

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: admin
rules:
  - apiGroups: ["*"]
    resources: ["*"]
    verbs: ["*"]

A scoped Role

Read-only access to one resource, which is what most application accounts need

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: reader
  namespace: app
rules:
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["get", "list"]

Common mistakes

These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.

  1. Granting a wildcard verb to save time

    verbs: ["*"] includes delete, deletecollection and impersonate. Impersonate in particular lets the holder act as any user, which is privilege escalation with extra steps.

    Instead:List the verbs. get, list and watch cover most read use.

  2. Using a ClusterRoleBinding where a RoleBinding was meant

    A ClusterRoleBinding grants the role in EVERY namespace. The distinction is one word and the blast radius is the whole cluster.

    Instead:RoleBinding for namespace scope, and check which one you wrote.

  3. Forgetting that secrets are readable by list

    get on a named Secret is narrow; list on Secrets returns every Secret's contents in the response. They are very different grants.

    Instead:Avoid list on Secrets. Use get with resourceNames where possible.

What it does

Reading one Role tells you very little. RBAC only becomes legible once the bindings are resolved and you can ask the question by subject.

Bindings resolved, not roles read

A ClusterRole grants nothing until something binds it, and a RoleBinding can reference a ClusterRole to scope its rules to one namespace. Paste the roles and the bindings together and you get the answer per subject: what can this service account actually do, and which binding gave it that.

The permissions that do not look dangerous

Nobody writes verbs: ["*"] by accident. They grant create on pods, which lets the holder mount any Secret in the namespace and run as a more privileged service account. Or create on Deployments, which is the same thing one step removed. Those paths are the ones worth finding.

Routes to cluster-admin, named

impersonate on groups reaches system:masters. escalate removes the check that stops you granting what you do not hold. bind attaches cluster-admin to anyone. serviceaccounts/token mints credentials for a more privileged account. Each is reported with the binding that granted it.

It does not invent findings

A rule narrowed with resourceNames is a materially smaller grant and is not reported as reading every Secret. A role nothing binds raises no security finding at all, because it grants nobody anything: it is reported as unbound instead, which is usually a missing binding or dead config.

How Kubernetes RBAC actually resolves

Four object types, and the thing that makes RBAC confusing is that permissions live in one pair and identity lives in the other. A role is a list of rules with nobody attached. A binding attaches subjects to a role. Nothing grants anything until both exist.

Four objects, two axes

Role and RoleBinding are namespaced. ClusterRole and ClusterRoleBinding are cluster-wide. The combination that catches people is the third one: a RoleBinding may reference a ClusterRole, which applies that ClusterRole's rules but only inside the binding's namespace. That is the intended way to reuse a role definition across namespaces without granting it everywhere.

RoleBinding        -> Role           rules apply in that namespace
RoleBinding        -> ClusterRole    rules apply in that namespace only
ClusterRoleBinding -> ClusterRole    rules apply everywhere
ClusterRoleBinding -> Role           not allowed

Permissions are purely additive

There is no deny rule in Kubernetes RBAC. A subject's permissions are the union of every binding that names them, and nothing subtracts. This is the opposite of AWS IAM, and it means you cannot fix an over-broad grant by adding a narrower one: the broad one has to be removed or replaced.

Subresources are separate resources

pods/exec, pods/log, pods/portforward and serviceaccounts/token are resources in their own right, not verbs on their parent. Granting get on pods does not grant pods/log, and: much more importantly: a rule written as resources: ["pods"] with verbs: ["*"] does not include exec. This cuts both ways: it is why least-privilege roles need subresources listed explicitly, and why a wildcard on resources is so much broader than it looks.

resources: ["pods"]        verbs: ["*"]   -> no exec
resources: ["pods/exec"]   verbs: ["create"] -> exec
resources: ["*"]           verbs: ["*"]   -> everything, including exec

The escalation prevention, and the two verbs that remove it

The API server normally refuses to let you create a role granting permissions you do not hold yourself, which stops a limited account writing itself an admin role. The escalate verb turns that check off. The bind verb lets the holder attach an existing role: cluster-admin included: to any subject. Either one converts a limited account into an unlimited one in a single call, and both exist mainly so that controllers can manage RBAC on your behalf.

Why an empty apiGroup means core

The core API group: Pods, Services, Secrets, ConfigMaps, ServiceAccounts: has an empty string as its name. A rule listing resources without apiGroups: [""] silently matches nothing, which produces a role that looks correct in review and grants nothing at runtime. It is the most common reason a hand-written role appears not to work.

- apiGroups: [""]                          core: pods, secrets, services
  resources: ["secrets"]
  verbs: ["get"]

- apiGroups: ["apps"]                      deployments, statefulsets
- apiGroups: ["rbac.authorization.k8s.io"] roles, bindings

More kubernetes tools

Kubernetes YAML Generator Answer a few questions, get a manifest Kubernetes YAML Validator Is this YAML valid, and where is it wrong? Kubernetes Rollout & Probe Timing Restart loops, capacity dips and stuck drains Kubernetes Service Checker Will this Service have any endpoints? Kubernetes Network Policy Viewer What can reach what, and what just broke Kubernetes Manifest Diff What actually changed Kubernetes Resource Calculator What these manifests actually reserve Kubernetes Deployment Generator See the capacity dip before you deploy Kubernetes Service Generator port, targetPort, and which one you meant Kubernetes StatefulSet Generator Stable names, and volumes that outlive you Kubernetes QoS Class Calculator And where you sit in the eviction order Kubernetes Node Capacity Planner Allocatable is not capacity Kubernetes Max Pods per Node Calculator The ENI limit, not the 110 default Kubernetes Label Selector Tester Which key failed, not just that one did Kubernetes Taint & Toleration Tester Tolerations permit, they do not attract Kubernetes Resource Name Validator RFC 1123 subdomain, label, or 1035 Kubernetes Label & Annotation Validator Why your image tag is not a legal label Kubernetes CrashLoopBackOff Guide The status is a timer, not a cause Kubernetes TLS Certificate Decoder When it expires, and what it covers Kubernetes ServiceAccount Token Decoder Bound or legacy, and when it dies Kubernetes imagePullSecret Generator The registry URL nobody gets right Kubernetes cert-manager Certificates Issuer scope, and the rate limit that costs a week Kubernetes Flux HelmRelease Generator With the source it cannot work without Kubernetes Helm Chart Generator Chart.yaml, values, and working templates Kubernetes Argo CD Application Generator The defaults that are off, turned on Kubernetes Ingress Generator pathType, and the TLS secret that fails quietly Kubernetes HPA Generator Why it says unknown and never scales Kubernetes SecurityContext Generator Pod level, container level, and which wins Kubernetes Probe Generator How long it gets to start before liveness kills it Kubernetes PVC Generator Access modes your storage can actually do Kubernetes ResourceQuota Generator And the LimitRange that stops it breaking deploys Kubernetes CronJob Generator The fields that decide whether it runs Kubernetes NetworkPolicy Generator With the DNS rule already in it Kubernetes RBAC Generator And what it actually grants Kubernetes PodDisruptionBudget Generator Can this budget ever be satisfied? Kubernetes API Deprecation Checker What breaks on the next upgrade Kubernetes Kubeconfig Viewer Read it without handing it to anyone Kubernetes Quantity Parser What 512Mi, 100m and 1e3 actually mean Kubernetes Multi-Document YAML Splitter One file per object, in apply order Kubernetes .env to ConfigMap & Secret Split the credentials out on the way Kubernetes Secret Decoder See what is actually in there Kubernetes Ingress to Gateway API Which annotations silently stop working Kubernetes Manifest Visualizer What points at what, and what points at nothing Kubernetes Patch Tester Which --type, and what it deletes Kubernetes kubectl JSONPath Tester kubectl's dialect, not generic JSONPath Kubernetes Node Affinity Tester Required excludes, preferred only scores Kubernetes Helm Values Diff A missing key is a third value Kubernetes Pod and Service CIDR Fixed at cluster creation Kubernetes Secret Encoder base64 is not encryption Kubernetes API Version Checker Will this apply on that cluster Kubernetes Go Template Tester Go truthiness is not JavaScript's Kubernetes Cluster Cost Estimator At your rates, not a price table Kubernetes Kustomize Build Transformers run in kustomize's order Kubernetes Helm Chart Validator version is SemVer, appVersion is not

Elsewhere on the site