Configure Kubernetes RBAC with service accounts and role bindings for secure cluster access control

Intermediate 25 min May 29, 2026 130 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up role-based access control in Kubernetes using service accounts, roles, and role bindings to implement least-privilege security principles and granular permission management for applications and users.

Prerequisites

  • Running Kubernetes cluster with kubectl access
  • Cluster admin permissions
  • Basic understanding of Kubernetes concepts

What this solves

Kubernetes RBAC (Role-Based Access Control) provides fine-grained access control for cluster resources by defining who can perform what actions on which resources. Without proper RBAC configuration, applications and users might have excessive permissions, creating security risks and violating the principle of least privilege.

Understanding Kubernetes RBAC fundamentals

RBAC in Kubernetes consists of four main components that work together to control access. Service accounts represent identities for pods and applications running in the cluster. Roles define sets of permissions for resources within a namespace, while ClusterRoles define permissions across the entire cluster.

Role bindings connect roles to subjects (users, groups, or service accounts) within a namespace, while ClusterRole bindings work at the cluster level. This separation allows you to create reusable permission sets and apply them selectively to different identities.

Note: RBAC is enabled by default in most Kubernetes distributions. You can verify this by checking if the --authorization-mode parameter includes RBAC in your API server configuration.

Step-by-step configuration

Verify RBAC is enabled

First, confirm that RBAC authorization is active in your cluster.

kubectl cluster-info dump | grep authorization-mode
kubectl auth can-i list pods --as=system:serviceaccount:default:default

Create a dedicated namespace

Set up a separate namespace for testing RBAC configurations without affecting existing workloads.

kubectl create namespace rbac-demo
kubectl get namespaces

Create a service account

Service accounts provide identities for applications running in pods. Create one for our demo application.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-reader
  namespace: rbac-demo
  labels:
    purpose: rbac-demonstration
automountServiceAccountToken: true
kubectl apply -f rbac-service-account.yaml
kubectl get serviceaccounts -n rbac-demo

Create a role with specific permissions

Define a role that grants read-only access to pods and services within the namespace.

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

Create a role binding

Bind the role to the service account to grant the defined permissions.

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-role-binding.yaml
kubectl describe rolebinding read-pods -n rbac-demo

Create a cluster role for cross-namespace access

For permissions that span multiple namespaces, create a ClusterRole instead of a namespace-scoped Role.

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

Create a cluster role binding

Bind the ClusterRole to a service account to grant cluster-wide permissions.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: read-namespaces
subjects:
  • kind: ServiceAccount
name: app-reader namespace: rbac-demo roleRef: kind: ClusterRole name: namespace-reader apiGroup: rbac.authorization.k8s.io
kubectl apply -f rbac-cluster-role-binding.yaml
kubectl describe clusterrolebinding read-namespaces

Create a test pod with the service account

Deploy a pod that uses the service account to test the RBAC configuration.

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

Configure advanced role permissions

Create a more complex role that demonstrates resource filtering and specific action permissions.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: deployment-manager
  namespace: rbac-demo
rules:
  • apiGroups: ["apps"]
resources: ["deployments"] verbs: ["get", "list", "watch", "create", "update", "patch"]
  • apiGroups: ["apps"]
resources: ["deployments/scale"] verbs: ["update", "patch"]
  • apiGroups: [""]
resources: ["events"] verbs: ["get", "list", "watch"]
  • apiGroups: [""]
resources: ["secrets"] resourceNames: ["app-secret", "db-secret"] verbs: ["get"]
kubectl apply -f advanced-role.yaml

Verify your setup

Test the RBAC configuration by checking what actions the service account can perform.

# Test permissions from within the pod
kubectl exec -it rbac-test-pod -n rbac-demo -- kubectl get pods
kubectl exec -it rbac-test-pod -n rbac-demo -- kubectl get namespaces

Test permissions using kubectl auth can-i

kubectl auth can-i list 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 delete pods --as=system:serviceaccount:rbac-demo:app-reader -n rbac-demo

Check what resources the service account can access

kubectl auth can-i --list --as=system:serviceaccount:rbac-demo:app-reader -n rbac-demo

You can also verify the service account token and permissions are correctly mounted.

# Check mounted service account token
kubectl exec rbac-test-pod -n rbac-demo -- ls -la /var/run/secrets/kubernetes.io/serviceaccount/

View the token content (base64 decoded)

kubectl exec rbac-test-pod -n rbac-demo -- cat /var/run/secrets/kubernetes.io/serviceaccount/token

Check namespace

kubectl exec rbac-test-pod -n rbac-demo -- cat /var/run/secrets/kubernetes.io/serviceaccount/namespace

Managing user access with RBAC

RBAC also controls human user access to the cluster. Create role bindings for users and groups from your authentication provider.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: developer-access
  namespace: rbac-demo
subjects:
  • kind: User
name: jane.doe@example.com apiGroup: rbac.authorization.k8s.io
  • kind: Group
name: developers apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: deployment-manager apiGroup: rbac.authorization.k8s.io
kubectl apply -f user-role-binding.yaml
Security note: Always follow the principle of least privilege. Grant only the minimum permissions required for each service account or user to perform their intended functions.

Implementing network policies for additional security

Combine RBAC with network policies for comprehensive security. While RBAC controls API access, network policies control pod-to-pod communication.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: rbac-demo-netpol
  namespace: rbac-demo
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: monitoring
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          name: database
    ports:
    - protocol: TCP
      port: 5432

For comprehensive network security configuration, you can reference our Kubernetes network policies guide for detailed network isolation strategies.

Common issues

SymptomCauseFix
Forbidden: access deniedMissing role or role bindingCreate appropriate role and binding with required permissions
Service account not foundService account not created in correct namespaceVerify namespace and recreate service account
Role binding has no effectIncorrect subject reference or roleRefCheck subject kind, name, and namespace match exactly
Cannot access cluster resourcesUsing Role instead of ClusterRoleCreate ClusterRole and ClusterRoleBinding for cluster-scoped resources
Pod cannot mount service accountService account token automounting disabledSet automountServiceAccountToken: true in service account
Excessive permissions grantedUsing wildcard permissions or admin rolesCreate specific roles with minimal required permissions

Next steps

Running this in production?

Need this managed? 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.