Role vs ClusterRole
Key Differences in Kubernetes
A Role defines permissions within a single namespace — it can only grant access to resources in the namespace where it is created. A ClusterRole defines permissions cluster-wide and can grant access to cluster-scoped resources (nodes, namespaces), non-resource endpoints, or be reused across multiple namespaces via RoleBindings.
Side-by-Side Comparison
| Dimension | Role | ClusterRole |
|---|---|---|
| Scope | Single namespace only | Cluster-wide or reusable across namespaces |
| Namespaced Resources | Can grant access to Pods, Services, ConfigMaps, etc. in one namespace | Can grant access to namespaced resources in all namespaces (via ClusterRoleBinding) |
| Cluster-Scoped Resources | Cannot grant access to nodes, namespaces, PersistentVolumes, etc. | Can grant access to cluster-scoped resources |
| Binding Type | Bound via RoleBinding (namespace-scoped) | Bound via ClusterRoleBinding (cluster-wide) or RoleBinding (namespace-scoped) |
| Reusability | Only usable in its own namespace | Can be referenced by RoleBindings in any namespace |
| Non-Resource URLs | Cannot grant access to API endpoints like /healthz | Can grant access to non-resource URLs |
Detailed Breakdown
Role — Namespace-Scoped Permissions
A Role can only reference resources within its namespace:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: development
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
This Role allows reading Pods and their logs, but only in the development namespace. It cannot be used in any other namespace.
To grant this Role to a user, you create a RoleBinding:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: development
subjects:
- kind: User
name: jane
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
ClusterRole — Cluster-Wide Permissions
A ClusterRole can grant access to everything a Role can, plus cluster-scoped resources:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-reader
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list"]
- nonResourceURLs: ["/healthz", "/healthz/*"]
verbs: ["get"]
This grants read access to nodes (cluster-scoped), PersistentVolumes (cluster-scoped), and the /healthz endpoint (non-resource URL). None of these can be expressed in a Role.
ClusterRoleBinding — Cluster-Wide Grant
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-nodes-global
subjects:
- kind: Group
name: developers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: node-reader
apiGroup: rbac.authorization.k8s.io
This grants the node-reader ClusterRole to all users in the developers group, across the entire cluster.
The Reusable ClusterRole Pattern
One of the most powerful RBAC patterns is defining a ClusterRole once and binding it per-namespace with RoleBindings. This avoids duplicating Role definitions:
# Define once as a ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: deployment-manager
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
# Bind in team-a namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: team-a-deployment-manager
namespace: team-a
subjects:
- kind: Group
name: team-a-devs
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: deployment-manager
apiGroup: rbac.authorization.k8s.io
# Bind in team-b namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: team-b-deployment-manager
namespace: team-b
subjects:
- kind: Group
name: team-b-devs
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: deployment-manager
apiGroup: rbac.authorization.k8s.io
Even though deployment-manager is a ClusterRole, binding it with a RoleBinding restricts the permissions to that specific namespace. Team A can manage Deployments in team-a but not in team-b, and vice versa.
Built-in ClusterRoles
Kubernetes ships with several default ClusterRoles:
kubectl get clusterroles | grep -E "^(admin|edit|view|cluster-admin)"
- cluster-admin — full access to everything (superuser)
- admin — full access within a namespace (when bound with RoleBinding)
- edit — read/write access to most namespace resources (no RBAC modification)
- view — read-only access to most namespace resources (no Secrets)
These are designed to be bound per-namespace. For example, granting admin to a team lead in their namespace:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: team-lead-admin
namespace: production
subjects:
- kind: User
name: alice
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
Service Account Permissions
RBAC applies to ServiceAccounts the same way. If a Pod needs to list other Pods (e.g., for leader election), you create a Role and bind it to the ServiceAccount:
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app
namespace: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-lister
namespace: production
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-app-pod-lister
namespace: production
subjects:
- kind: ServiceAccount
name: my-app
namespace: production
roleRef:
kind: Role
name: pod-lister
apiGroup: rbac.authorization.k8s.io
Principle of Least Privilege
The security best practice is:
- Start with Roles (namespace-scoped) unless you specifically need cluster-scoped access
- Use ClusterRoles with RoleBindings for reusable permission sets
- Only use ClusterRoleBindings for truly cluster-wide needs (monitoring, node management)
- Never grant
cluster-adminto application ServiceAccounts - Use
resourceNamesto restrict access to specific resources when possible
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["app-secret"] # Only this specific Secret
verbs: ["get"]
Use Role when...
- •You need to grant access to resources in a single namespace only
- •You want to enforce strict namespace-level isolation
- •Team-specific permissions that should not leak across namespaces
- •Following the principle of least privilege for namespace-scoped work
Use ClusterRole when...
- •You need to grant access to cluster-scoped resources (nodes, PVs, namespaces)
- •You want to define a reusable set of permissions applied per-namespace via RoleBindings
- •You're granting read access across all namespaces (e.g., monitoring tools)
- •You need to grant access to non-resource URLs like /healthz or /metrics
- •You're defining admin, edit, or view roles used across the organization
Model Interview Answer
“A Role is namespace-scoped — it grants permissions to resources like Pods, Services, and ConfigMaps within a single namespace and is bound to subjects via a RoleBinding. A ClusterRole is cluster-scoped — it can grant access to cluster-wide resources like nodes and PersistentVolumes, non-resource endpoints like /healthz, and namespaced resources across all namespaces. A useful pattern is defining a ClusterRole once and binding it in specific namespaces with RoleBindings. For example, you create a ClusterRole called 'pod-reader' and then create a RoleBinding in each team's namespace to grant that role, avoiding duplication.”