Skip to content
Latchkey

kubectl "Error from server (Forbidden)" - Fix RBAC in CI

Kubernetes authenticated the request but RBAC denied it. The identity CI uses has no Role/ClusterRole granting the verb on that resource in that namespace.

What this error means

kubectl reports Error from server (Forbidden): <resource> is forbidden: User "<id>" cannot <verb> resource "<res>". Authentication succeeded. This is an authorization (RBAC) failure, not a credentials problem.

kubectl output
Error from server (Forbidden): deployments.apps is forbidden: User
"system:serviceaccount:ci:deployer" cannot create resource "deployments" in API
group "apps" in the namespace "prod"

Common causes

Missing RoleBinding for the verb/resource

The ServiceAccount has no Role/ClusterRole binding granting that verb (create/list/patch) on that resource. The message names exactly what was denied.

Right permission, wrong namespace

A namespaced RoleBinding grants access in one namespace but the action targets another. Cluster-wide access needs a ClusterRoleBinding.

How to fix it

Confirm what is missing with auth can-i

Check the exact verb/resource for the identity CI uses before changing any RBAC.

Terminal
kubectl auth can-i create deployments \
  -n prod --as=system:serviceaccount:ci:deployer

Grant a least-privilege Role and bind it

Create a Role scoped to exactly the verbs/resources the pipeline needs, then bind the ServiceAccount.

Terminal
kubectl create role deployer -n prod \
  --verb=get,list,create,patch --resource=deployments,replicasets,pods
kubectl create rolebinding ci-deployer -n prod \
  --role=deployer --serviceaccount=ci:deployer

How to prevent it

  • Define least-privilege Roles for CI ServiceAccounts and review them in version control.
  • Use kubectl auth can-i in a pre-flight step to catch gaps before the deploy.
  • Match the binding scope (Role vs ClusterRole) to where the actions run.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →