Implement Kubernetes RBAC with service accounts and role-based access control

Intermediate 45 min Jun 13, 2026 31 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Configure Kubernetes role-based access control (RBAC) with service accounts, roles, and role bindings to enforce secure access policies and namespace isolation in your cluster.

Prerequisites

  • Kubernetes cluster with RBAC enabled
  • kubectl configured with cluster admin access
  • Basic understanding of Kubernetes concepts

What this solves

Kubernetes RBAC (Role-Based Access Control) controls who can access what resources in your cluster. By default, Kubernetes operates on a principle of least privilege, but without proper RBAC configuration, you may grant excessive permissions or block legitimate access. This tutorial shows you how to create service accounts, define roles with specific permissions, and bind them together for secure, granular access control.

Understanding Kubernetes RBAC fundamentals

RBAC in Kubernetes consists of four main components that work together. Service accounts provide identity for pods and applications. Roles define what actions can be performed on which resources. ClusterRoles work like Roles but apply cluster-wide. RoleBindings and ClusterRoleBindings connect subjects (users, groups, service accounts) to roles.

RBAC operates on the principle of explicit allow - everything is denied by default unless explicitly permitted. Permissions are additive, meaning multiple roles can grant different permissions to the same subject. Namespace-level roles only apply within their specific namespace, while cluster roles can access resources across all namespaces.

Step-by-step configuration

Verify RBAC is enabled

Check that RBAC authorization is enabled in your Kubernetes cluster before proceeding with configuration.

kubectl api-versions | grep rbac
kubectl auth can-i create roles --as=system:serviceaccount:default:default

Create a dedicated namespace

Create a test namespace to demonstrate RBAC policies without affecting existing workloads.

kubectl create namespace rbac-demo
kubectl get namespaces rbac-demo

Create a service account

Service accounts provide an identity for processes that run in pods. Create a service account that will be used by applications needing specific permissions.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-reader
  namespace: rbac-demo
automountServiceAccountToken: true
kubectl apply -f rbac-serviceaccount.yaml
kubectl get serviceaccount -n rbac-demo

Create a namespace-level role

Define a role that grants read-only permissions to pods and services within the rbac-demo namespace. This follows the principle of least privilege by only granting necessary permissions.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: rbac-demo
  name: pod-reader
rules:
  • apiGroups: [""]
resources: ["pods", "services"] verbs: ["get", "watch", "list"]
  • apiGroups: [""]
resources: ["pods/log"] verbs: ["get"]
kubectl apply -f rbac-role.yaml
kubectl get role -n rbac-demo

Create a role binding

Bind the service account to the role, granting the app-reader service account the permissions defined in the pod-reader role.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: rbac-demo
subjects:
  • kind: ServiceAccount
name: app-reader namespace: rbac-demo roleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.io
kubectl apply -f rbac-rolebinding.yaml
kubectl get rolebinding -n rbac-demo

Create a cluster-level role

Define a ClusterRole for permissions that span multiple namespaces or cluster-wide resources like nodes. This example grants read access to nodes and persistent volumes.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: node-reader
rules:
  • apiGroups: [""]
resources: ["nodes", "persistentvolumes"] verbs: ["get", "watch", "list"]
  • apiGroups: ["metrics.k8s.io"]
resources: ["nodes", "pods"] verbs: ["get", "list"]
kubectl apply -f rbac-clusterrole.yaml
kubectl get clusterrole node-reader

Create a cluster role binding

Bind the service account to the cluster role, giving it cluster-wide read permissions for nodes and metrics.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: read-nodes
subjects:
  • kind: ServiceAccount
name: app-reader namespace: rbac-demo roleRef: kind: ClusterRole name: node-reader apiGroup: rbac.authorization.k8s.io
kubectl apply -f rbac-clusterrolebinding.yaml
kubectl get clusterrolebinding read-nodes

Create a role for write operations

Create a separate role with write permissions for deployment management. This demonstrates separation of concerns between read and write access.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: rbac-demo
  name: deployment-manager
rules:
  • apiGroups: ["apps"]
resources: ["deployments", "replicasets"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
  • apiGroups: [""]
resources: ["pods"] verbs: ["get", "list", "watch"]
kubectl apply -f rbac-deployment-role.yaml

Create a service account for deployment operations

Create a separate service account for deployment operations to demonstrate role separation.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-deployer
  namespace: rbac-demo
kubectl apply -f rbac-deployer-sa.yaml

Bind the deployer role

Create a role binding that grants the app-deployer service account deployment management permissions.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: manage-deployments
  namespace: rbac-demo
subjects:
  • kind: ServiceAccount
name: app-deployer namespace: rbac-demo roleRef: kind: Role name: deployment-manager apiGroup: rbac.authorization.k8s.io
kubectl apply -f rbac-deployer-binding.yaml

Testing RBAC policies

Test service account permissions

Use kubectl auth can-i to test what each service account can do. This helps verify your RBAC configuration works as expected.

kubectl auth can-i get pods --as=system:serviceaccount:rbac-demo:app-reader -n rbac-demo
kubectl auth can-i create deployments --as=system:serviceaccount:rbac-demo:app-reader -n rbac-demo
kubectl auth can-i create deployments --as=system:serviceaccount:rbac-demo:app-deployer -n rbac-demo

Create a test pod with service account

Deploy a pod that uses one of your service accounts to verify the RBAC configuration works in practice.

apiVersion: v1
kind: Pod
metadata:
  name: rbac-test
  namespace: rbac-demo
spec:
  serviceAccountName: app-reader
  containers:
  - name: kubectl-test
    image: bitnami/kubectl:latest
    command: ['sleep', '3600']
  restartPolicy: Never
kubectl apply -f rbac-test-pod.yaml
kubectl get pod rbac-test -n rbac-demo

Test permissions from inside the pod

Execute commands inside the test pod to verify that the service account can only perform allowed operations.

kubectl exec -it rbac-test -n rbac-demo -- kubectl get pods -n rbac-demo
kubectl exec -it rbac-test -n rbac-demo -- kubectl get nodes
kubectl exec -it rbac-test -n rbac-demo -- kubectl create deployment test --image=nginx -n rbac-demo

Implementing advanced RBAC patterns

Create resource-specific permissions

Configure RBAC to allow access to specific resources by name, not just resource types. This provides fine-grained control over individual resources.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: rbac-demo
  name: specific-config-reader
rules:
  • apiGroups: [""]
resources: ["configmaps"] resourceNames: ["app-config", "database-config"] verbs: ["get"]
  • apiGroups: [""]
resources: ["secrets"] resourceNames: ["app-secret"] verbs: ["get"]
kubectl apply -f rbac-specific-resource.yaml

Create role aggregation

Use ClusterRole aggregation to combine multiple roles automatically. This is useful for creating composite roles from smaller, reusable components.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: monitoring-reader
  labels:
    rbac.example.com/aggregate-to-monitoring: "true"
rules:
  • apiGroups: [""]
resources: ["pods", "services", "endpoints"] verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: aggregate-monitoring aggregationRule: clusterRoleSelectors: - matchLabels: rbac.example.com/aggregate-to-monitoring: "true" rules: []
kubectl apply -f rbac-aggregated-role.yaml

Verify your setup

kubectl get serviceaccounts -n rbac-demo
kubectl get roles -n rbac-demo
kubectl get rolebindings -n rbac-demo
kubectl get clusterroles | grep -E "node-reader|aggregate-monitoring"
kubectl get clusterrolebindings | grep read-nodes
kubectl auth can-i --list --as=system:serviceaccount:rbac-demo:app-reader -n rbac-demo

Troubleshooting access issues

Debug RBAC permissions

Use these commands to troubleshoot when applications can't access required resources.

kubectl auth can-i create pods --as=system:serviceaccount:rbac-demo:app-reader -n rbac-demo
kubectl describe rolebinding -n rbac-demo
kubectl describe clusterrolebinding read-nodes

Check service account tokens

Verify that service accounts have valid tokens and can authenticate to the API server.

kubectl get serviceaccount app-reader -n rbac-demo -o yaml
kubectl get secrets -n rbac-demo | grep app-reader
kubectl describe secret $(kubectl get serviceaccount app-reader -n rbac-demo -o jsonpath='{.secrets[0].name}') -n rbac-demo

Common issues

SymptomCauseFix
Pod gets "forbidden" errorsService account lacks permissionsCreate role and rolebinding with required verbs and resources
RoleBinding doesn't workWrong namespace or subject referenceVerify namespace matches and subject kind/name are correct
Can't access cluster resourcesUsing Role instead of ClusterRoleCreate ClusterRole and ClusterRoleBinding for cluster-scoped resources
Service account not foundautomountServiceAccountToken disabledSet automountServiceAccountToken: true in ServiceAccount
Permissions too broadUsing wildcards in rulesSpecify exact resources and verbs instead of "*"
Multiple bindings conflictOverlapping role definitionsRBAC permissions are additive - review all bindings for the subject

Next steps

Running this in production?

Want this handled for you? Setting this up once is straightforward. Keeping it patched, monitored, backed up and performant across environments is the harder part. See how we run infrastructure like this for European teams.

Need help?

Don't want to manage this yourself?

We handle managed devops services for businesses that depend on uptime. From initial setup to ongoing operations.