DEV Community

Cover image for Kubernetes RBAC — Control Who Can Do What in Your Cluster
DevOps Rise
DevOps Rise

Posted on • Edited on

Kubernetes RBAC — Control Who Can Do What in Your Cluster

Without RBAC properly configured:

  • A developer can accidentally delete production pods
  • A compromised app can read ALL secrets in the cluster
  • CI/CD pipelines have unlimited cluster access

RBAC uses 4 objects:

  • Role — namespace-scoped permissions
  • ClusterRole — cluster-wide permissions
  • RoleBinding — attach Role to a user/serviceaccount
  • ClusterRoleBinding — attach ClusterRole cluster-wide

Check Permissions First

# What can YOU do?
kubectl auth can-i get pods
kubectl auth can-i delete deployments
kubectl auth can-i get secrets -n production

# What can a specific user do?
kubectl auth can-i get pods --as=john.doe -n dev
kubectl auth can-i delete pods --as=john.doe -n dev  # no
kubectl auth can-i get secrets --as=john.doe -n dev  # no
Enter fullscreen mode Exit fullscreen mode

Create a Role (Namespace-Scoped)

# developer-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer-role
  namespace: dev
rules:
  - apiGroups: [""]
    resources: ["pods", "pods/log"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["apps"]
    resources: ["deployments", "replicasets"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["configmaps", "services"]
    verbs: ["get", "list"]
  # Explicitly NO access to secrets!
Enter fullscreen mode Exit fullscreen mode
kubectl apply -f developer-role.yaml
kubectl describe role developer-role -n dev
Enter fullscreen mode Exit fullscreen mode

Bind Role to User

# rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: developer-binding
  namespace: dev
subjects:
  - kind: User
    name: john.doe
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: developer-role
  apiGroup: rbac.authorization.k8s.io
Enter fullscreen mode Exit fullscreen mode
kubectl apply -f rolebinding.yaml

# Test permissions
kubectl auth can-i get pods --as=john.doe -n dev    # yes ✅
kubectl auth can-i delete pods --as=john.doe -n dev  # no ✅
kubectl auth can-i get secrets --as=john.doe -n dev  # no ✅
Enter fullscreen mode Exit fullscreen mode

ClusterRole — Cluster-Wide Permissions

# cluster-reader.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-reader
rules:
  - apiGroups: ["", "apps", "batch"]
    resources: ["*"]
    verbs: ["get", "list", "watch"]
  # Still NO secrets access!
Enter fullscreen mode Exit fullscreen mode

Built-in ClusterRoles you can use:

# View available built-in roles
kubectl get clusterroles | grep -v system

# Common ones:
# cluster-admin  - full access (be very careful!)
# admin          - full access in namespace
# edit           - read/write most resources
# view           - read-only most resources
Enter fullscreen mode Exit fullscreen mode

ServiceAccounts for Applications

Applications in pods should use ServiceAccounts — never hardcoded credentials:

# Create ServiceAccount
kubectl create serviceaccount myapp-sa -n default

# Create Role with MINIMUM permissions
Enter fullscreen mode Exit fullscreen mode
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: myapp-role
  namespace: default
rules:
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["get"]
    resourceNames: ["myapp-config"]  # Only THIS configmap!
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["get"]
    resourceNames: ["myapp-secret"]  # Only THIS secret!
Enter fullscreen mode Exit fullscreen mode
# Bind ServiceAccount to Role
kubectl create rolebinding myapp-binding \
  --role=myapp-role \
  --serviceaccount=default:myapp-sa

# Use in Deployment spec:
# serviceAccountName: myapp-sa
Enter fullscreen mode Exit fullscreen mode

RBAC for CI/CD Pipelines

# Create namespace and ServiceAccount for CI/CD
kubectl create namespace ci-cd
kubectl create serviceaccount github-actions -n ci-cd
Enter fullscreen mode Exit fullscreen mode
# deployer role - just enough to update deployments
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: deployer
rules:
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list", "update", "patch"]
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list", "watch"]
Enter fullscreen mode Exit fullscreen mode
kubectl apply -f deployer-role.yaml

kubectl create clusterrolebinding github-actions-binding \
  --clusterrole=deployer \
  --serviceaccount=ci-cd:github-actions

# CI/CD can deploy but CANNOT:
# - Read secrets
# - Delete resources
# - Access other namespaces
Enter fullscreen mode Exit fullscreen mode

Audit RBAC — Who Has What Access

# List all roles in namespace
kubectl get roles -n dev
kubectl get rolebindings -n dev

# List cluster-wide
kubectl get clusterroles | grep -v system
kubectl get clusterrolebindings | grep -v system

# What can a serviceaccount do?
kubectl auth can-i --list \
  --as=system:serviceaccount:default:myapp-sa

# Describe binding to see subjects
kubectl describe rolebinding developer-binding -n dev
Enter fullscreen mode Exit fullscreen mode

RBAC Best Practices

Practice Why
Least privilege always Limit blast radius
Roles over ClusterRoles Namespace isolation
ServiceAccounts for apps No hardcoded credentials
Never use cluster-admin for apps Too dangerous
resourceNames for specific access Extra restriction
Audit RBAC quarterly Remove unused permissions

Practice Kubernetes Interview Questions

535+ real DevOps interview questions — Kubernetes, Docker, AWS, Terraform and more.

Completely free at devopsrise.vercel.app

Mock interview mode with timer available!

Top comments (0)