How Do You Create an RBAC Role and Bind It to a User?
You create a Role by defining rules that specify API groups, resources, and allowed verbs in a YAML manifest. You then create a RoleBinding that associates the Role with a subject (user, group, or ServiceAccount). Both can be created declaratively with YAML or imperatively with kubectl.
Detailed Answer
Creating RBAC permissions in Kubernetes is a two-step process: define the permissions (Role or ClusterRole) and assign them (RoleBinding or ClusterRoleBinding). Here is a complete walkthrough.
Step 1: Identify Required Permissions
Before writing YAML, determine exactly what API actions are needed. Use kubectl api-resources to find the correct API groups and resource names:
# Find the API group for Deployments
kubectl api-resources | grep deployments
# deployments deploy apps/v1 true Deployment
# Find all resources in the core API group
kubectl api-resources --api-group=""
# Find all resources in the apps group
kubectl api-resources --api-group=apps
Key API groups and their common resources:
| API Group | Resources |
|---|---|
| "" (core) | pods, services, configmaps, secrets, persistentvolumeclaims |
| apps | deployments, statefulsets, daemonsets, replicasets |
| batch | jobs, cronjobs |
| networking.k8s.io | networkpolicies, ingresses |
| rbac.authorization.k8s.io | roles, clusterroles, rolebindings, clusterrolebindings |
Step 2: Create the Role (Declarative)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: development
name: app-developer
rules:
# Core resources
- apiGroups: [""]
resources: ["pods", "pods/log", "pods/portforward"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["services", "configmaps"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
# Deployments
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
# Events (read-only for debugging)
- apiGroups: [""]
resources: ["events"]
verbs: ["get", "list", "watch"]
Apply it:
kubectl apply -f role.yaml
Step 2 (Alternative): Create the Role Imperatively
kubectl create role app-developer \
--verb=get,list,watch,create,delete \
--resource=pods,pods/log,pods/portforward \
-n development
# Note: imperative creation supports only one rule at a time.
# For multiple rules, use YAML or run the command multiple times
# and edit the resulting role.
Step 3: Create the RoleBinding (Declarative)
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
namespace: development
name: alice-app-developer
subjects:
- kind: User
name: alice
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: app-developer
apiGroup: rbac.authorization.k8s.io
Apply it:
kubectl apply -f rolebinding.yaml
Step 3 (Alternative): Create the RoleBinding Imperatively
kubectl create rolebinding alice-app-developer \
--role=app-developer \
--user=alice \
-n development
For a ServiceAccount:
kubectl create rolebinding deployer-binding \
--role=app-developer \
--serviceaccount=development:deployer-sa \
-n development
For a group:
kubectl create rolebinding team-binding \
--clusterrole=edit \
--group=dev-team \
-n development
Step 4: Verify the Permissions
# Check a specific permission
kubectl auth can-i create pods --as=alice -n development
# yes
kubectl auth can-i delete deployments --as=alice -n development
# no (we only granted get/list/watch/create/update/patch)
# List all permissions
kubectl auth can-i --list --as=alice -n development
Complete End-to-End Example
Here is a real-world scenario: creating a CI/CD ServiceAccount that can deploy applications to a staging namespace.
# 1. ServiceAccount for the CI pipeline
apiVersion: v1
kind: ServiceAccount
metadata:
name: ci-deployer
namespace: staging
---
# 2. Role with deployment permissions
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: staging
name: ci-deploy-role
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "create", "update", "patch"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "create", "update", "patch"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
---
# 3. Bind the Role to the ServiceAccount
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
namespace: staging
name: ci-deployer-binding
subjects:
- kind: ServiceAccount
name: ci-deployer
namespace: staging
roleRef:
kind: Role
name: ci-deploy-role
apiGroup: rbac.authorization.k8s.io
# Apply all resources
kubectl apply -f ci-rbac.yaml
# Verify
kubectl auth can-i create deployments \
--as=system:serviceaccount:staging:ci-deployer \
-n staging
# yes
kubectl auth can-i delete namespaces \
--as=system:serviceaccount:staging:ci-deployer
# no (good — least privilege)
Understanding apiGroups
The apiGroups field is often confusing. Here is the rule:
- Core resources (pods, services, configmaps, secrets, etc.) use an empty string:
[""] - Everything else uses the group from the API path. For
apps/v1, the group is"apps". Forbatch/v1, the group is"batch".
# Quick reference: find the group for any resource
kubectl api-resources -o wide | grep -i deployment
# NAME SHORTNAMES APIVERSION NAMESPACED KIND VERBS
# deployments deploy apps/v1 true Deployment [create delete ...]
The APIVERSION column shows apps/v1, so the apiGroup is apps.
Common Mistakes
- Forgetting the empty string for core resources — writing
apiGroups: ["core"]orapiGroups: ["v1"]instead ofapiGroups: [""]. - Missing subresources —
pods/logandpods/execare separate resources that need their own rules. - Not testing after creation — always run
kubectl auth can-ito verify.
Why Interviewers Ask This
This is a hands-on question that tests whether you can actually set up RBAC in a cluster. Interviewers expect you to walk through the process confidently, including the YAML structure and imperative commands.
Common Follow-Up Questions
Key Takeaways
- Role rules require three fields: apiGroups, resources, and verbs.
- The core API group (pods, services, etc.) is represented as an empty string.
- kubectl create role and kubectl create rolebinding provide quick imperative creation.
- Always verify the result with kubectl auth can-i.