Home/Engineer/Docker / Containers/Kubernetes RBAC: Diagnosing …
Docker / ContainersAdvancedlinuxkubernetesrbacsecurity

Kubernetes RBAC: Diagnosing 'Forbidden' Errors and Granting Least-Privilege Access with Roles and ServiceAccounts

How to minimize cluster permissions with Role, ClusterRole, bindings, and ServiceAccount. Covers kubectl auth can-i debugging and least-privilege examples for CI deployments.

Contents
  1. What RBAC Is — Who, What, and Where
  2. Three Kinds of Subject
  3. Creating a Role — Namespace Permissions
  4. RoleBinding — Connecting to a Subject
  5. ClusterRole and Reuse
  6. Attaching a ServiceAccount to a Pod
  7. Checking Permissions — kubectl auth can-i
  8. Least-Privilege Example — CI Deployment SA
  9. Common Problems

What RBAC Is — Who, What, and Where

Kubernetes RBAC (Role-Based Access Control) is a permission model that defines which subject can perform which verb on which resource. When a cluster is shared by multiple people, teams, and CI pipelines, it is the core mechanism that enforces least privilege.

RBAC works through a combination of four resources.

ResourceScopeRole
RoleNamespaceA bundle of permissions (policy)
ClusterRoleCluster-wideA bundle of permissions (global / nodes / PVs, etc.)
RoleBindingNamespaceConnects a subject ↔ Role
ClusterRoleBindingCluster-wideConnects a subject ↔ ClusterRole

The key rule: Role/ClusterRole only define "what can be done". Binding decides who actually receives those permissions.

RBAC is purely additive — there is addition, but no subtraction. There are no deny rules that say "this is forbidden"; only what is explicitly allowed is possible. Permissions from multiple bindings accumulate as a union.


Three Kinds of Subject

Bindings grant permissions to three kinds of target.

  • User: A human user (external auth such as certificates or OIDC. Kubernetes has no User object)
  • Group: A user group
  • ServiceAccount: The identity of a workload running inside a Pod. Used when CI deployments, operators, or apps call the API.

Creating a Role — Namespace Permissions

This Role can only list Pods and read logs in the dev namespace.

YAML
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: dev
  name: pod-reader
rules:
- apiGroups: [""] # "" = core API
  resources: ["pods", "pods/log"]
  verbs: ["get", "list", "watch"]

Choose verbs from get list watch create update patch delete deletecollection. You can also specify subresources such as pods/log and pods/exec separately in resources.


RoleBinding — Connecting to a Subject

Grant the Role above to a specific ServiceAccount.

YAML
apiVersion: v1
kind: ServiceAccount
metadata:
  name: ci-deployer
  namespace: dev
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ci-can-read-pods
  namespace: dev
subjects:
- kind: ServiceAccount
  name: ci-deployer
  namespace: dev
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io
Bash
kubectl apply -f rbac.yaml

roleRef cannot be modified once created. To change the Role it references, you must delete the RoleBinding and recreate it.


ClusterRole and Reuse

Use a ClusterRole for cluster-wide resources (nodes, PersistentVolumes, namespaces, and so on), or when you want common permissions that can be reused across multiple namespaces.

The key pattern: binding a ClusterRole with a RoleBinding applies that ClusterRole's permissions only in that namespace.

YAML
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: deploy-in-dev
  namespace: dev
subjects:
- kind: ServiceAccount
  name: ci-deployer
  namespace: dev
roleRef:
 kind: ClusterRole # ...
 name: edit #
  apiGroup: rbac.authorization.k8s.io

view / edit / admin / cluster-admin are ClusterRoles that Kubernetes provides by default. Most real-world needs are solved by binding these to a specific namespace with a RoleBinding.


Attaching a ServiceAccount to a Pod

For a workload to call the API server, specify an SA on the Pod. The token is mounted automatically.

YAML
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployer
  namespace: dev
spec:
  template:
    spec:
      serviceAccountName: ci-deployer
 # API call Pod :
      automountServiceAccountToken: false
      containers:
      - name: app
        image: myapp:1.0

For ordinary app Pods that do not call the API, turning off token mounting with automountServiceAccountToken: false is safer. Even if the container is compromised, an API access token is not exposed.


Checking Permissions — kubectl auth can-i

This is the core command for RBAC debugging. Ask directly whether a given subject can perform a given action.

Bash
# dev pod ?
kubectl auth can-i create pods -n dev

# ServiceAccount check (--as)
kubectl auth can-i list pods -n dev \
  --as=system:serviceaccount:dev:ci-deployer

# SA
kubectl auth can-i --list -n dev \
  --as=system:serviceaccount:dev:ci-deployer

The ServiceAccount username format is always system:serviceaccount:<>:<>.


Least-Privilege Example — CI Deployment SA

Giving cluster-admin when CI only needs to manage Deployments in dev is a common mistake. Define only the permissions that are actually needed.```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: dev name: deployment-manager rules:

  • apiGroups: ["apps"] resources: ["deployments", "replicasets"] verbs: ["get", "list", "watch", "create", "update", "patch"]
  • apiGroups: [""] resources: ["pods", "services"] verbs: ["get", "list", "watch"]
CODE

- Omitting delete permission (`delete`) prevents accidents where CI accidentally deletes resources.
- There is no access across namespaces, so `prod` is unaffected.

---

## Common Problems

- **`Forbidden` errors**: The message lists the required apiGroup/resource/verb as-is. Add those to the Role's `rules`.
- **Mixing up apiGroup**: Pod, Service, and ConfigMap are core (`""`); Deployment is `apps`; Ingress is `networking.k8s.io`. Check with `kubectl api-resources`.
- **Bound but still no permission**: Usually a typo in the `roleRef` name or a ServiceAccount namespace mismatch. Check the permissions actually granted with `kubectl auth can-i --list --as=...`.
- **Overly broad ClusterRoleBinding**: Binding `cluster-admin` to an SA with a ClusterRoleBinding means full cluster takeover. Reconsider whether you really need it.

RBAC looks complicated at first because there are four resources, but it boils down to one sentence: **"a permission bundle (Role) + a connection (Binding)"**. Keep `kubectl auth can-i` nearby and ask it as you go — tightening down to least privilege gets much easier.
#kubernetes#rbac#security#serviceaccount
Editorial note

AI tools may assist drafting. Check the evidence in each guide for whether commands were run and which environment was used. Confirm the current docs for your version before applying instructions, and email us about errors. email us

Topic-related official docs (auto-linked · not per-claim sources)Kubernetes documentation ↗Docker documentation ↗

Questions & answers

Ask a question about this guide. We'll review and reply.