Learning Kubernetes - Episode 33 - Introduction and Explanation of RBAC and RoleBinding

Learning Kubernetes - Episode 33 - Introduction and Explanation of RBAC and RoleBinding

In this episode, we'll discuss Kubernetes RBAC (Role-Based Access Control) and RoleBinding for authorization. We'll learn about Roles, ClusterRoles, RoleBindings, ClusterRoleBindings, and best practices for implementing fine-grained access control.

Arman Dwi Pangestu
Arman Dwi PangestuApril 8, 2026
0 views
9 min read

Introduction

Note

If you want to read the previous episode, you can click the Episode 32 thumbnail below

Episode 32Episode 32

In the previous episode, we learned about ServiceAccount which provides identity for Pods. In episode 33, we'll discuss RBAC (Role-Based Access Control) and RoleBinding, which control what authenticated users and ServiceAccounts can do in the cluster.

Note: Here I'll be using a Kubernetes Cluster installed through K3s.

Authentication answers "who are you?" (ServiceAccount), while authorization answers "what can you do?" (RBAC). RBAC enables fine-grained access control, allowing you to grant specific permissions to users and applications based on the principle of least privilege.

What Is RBAC?

RBAC (Role-Based Access Control) is Kubernetes' authorization mechanism that regulates access to cluster resources based on roles assigned to users or ServiceAccounts.

Think of RBAC like building security - your badge (ServiceAccount) identifies you, but RBAC determines which floors you can access, which doors you can open, and what actions you can perform in each room.

Key RBAC components:

  • Role - Defines permissions within a namespace
  • ClusterRole - Defines permissions cluster-wide
  • RoleBinding - Grants Role permissions to subjects in a namespace
  • ClusterRoleBinding - Grants ClusterRole permissions cluster-wide
  • Subjects - Users, Groups, or ServiceAccounts receiving permissions
  • Resources - Kubernetes objects (pods, services, etc.)
  • Verbs - Actions that can be performed (get, list, create, etc.)

RBAC Components

Role

Role defines permissions within a specific namespace.

Kubernetespod-reader-role.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
    name: pod-reader
    namespace: default
rules:
    - apiGroups: [""]
      resources: ["pods"]
      verbs: ["get", "list", "watch"]

Characteristics:

  • Namespace-scoped
  • Defines what can be done
  • Doesn't grant permissions by itself
  • Needs RoleBinding to take effect

ClusterRole

ClusterRole defines permissions cluster-wide or for cluster-scoped resources.

Kubernetesnode-reader-clusterrole.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
    name: node-reader
rules:
    - apiGroups: [""]
      resources: ["nodes"]
      verbs: ["get", "list", "watch"]

Characteristics:

  • Cluster-wide scope
  • Can access cluster-scoped resources (nodes, namespaces)
  • Can be bound in specific namespace via RoleBinding
  • Can be bound cluster-wide via ClusterRoleBinding

RoleBinding

RoleBinding grants Role permissions to subjects within a namespace.

Kubernetesread-pods-binding.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
    name: read-pods
    namespace: default
subjects:
    - kind: ServiceAccount
      name: my-app-sa
      namespace: default
roleRef:
    kind: Role
    name: pod-reader
    apiGroup: rbac.authorization.k8s.io

Characteristics:

  • Namespace-scoped
  • Binds Role or ClusterRole to subjects
  • Subjects must be in same namespace (for ServiceAccounts)
  • Can reference ClusterRole for namespace-scoped access

ClusterRoleBinding

ClusterRoleBinding grants ClusterRole permissions cluster-wide.

Kubernetesread-nodes-binding.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
    name: read-nodes
subjects:
    - kind: ServiceAccount
      name: monitoring-sa
      namespace: monitoring
roleRef:
    kind: ClusterRole
    name: node-reader
    apiGroup: rbac.authorization.k8s.io

Characteristics:

  • Cluster-wide scope
  • Binds ClusterRole to subjects
  • Grants access across all namespaces
  • Use carefully - powerful permissions

RBAC Rules

API Groups

Kubernetes resources belong to API groups:

Kubernetesyml
rules:
    # Core API group (empty string)
    - apiGroups: [""]
      resources: ["pods", "services", "configmaps"]
      
    # apps API group
    - apiGroups: ["apps"]
      resources: ["deployments", "statefulsets"]
      
    # rbac.authorization.k8s.io API group
    - apiGroups: ["rbac.authorization.k8s.io"]
      resources: ["roles", "rolebindings"]

Resources

Kubernetes objects that can be accessed:

Kubernetesyml
resources:
    - "pods"
    - "services"
    - "deployments"
    - "configmaps"
    - "secrets"
    - "persistentvolumeclaims"

Resource Names

Restrict access to specific resource instances:

Kubernetesyml
rules:
    - apiGroups: [""]
      resources: ["configmaps"]
      resourceNames: ["app-config", "app-secrets"]
      verbs: ["get", "update"]

Verbs

Actions that can be performed:

Kubernetesyml
verbs:
    - "get"        # Read single resource
    - "list"       # List resources
    - "watch"      # Watch for changes
    - "create"     # Create new resource
    - "update"     # Update existing resource
    - "patch"      # Partially update resource
    - "delete"     # Delete resource
    - "deletecollection"  # Delete multiple resources

Subresources

Access to resource subresources:

Kubernetesyml
rules:
    - apiGroups: [""]
      resources: ["pods/log"]
      verbs: ["get"]
    - apiGroups: [""]
      resources: ["pods/exec"]
      verbs: ["create"]

Creating RBAC Resources

Example 1: Read-Only Access to Pods

Kubernetesreadonly-pods.yml
# Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
    name: pod-reader
    namespace: production
rules:
    - apiGroups: [""]
      resources: ["pods"]
      verbs: ["get", "list", "watch"]
---
# RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
    name: read-pods
    namespace: production
subjects:
    - kind: ServiceAccount
      name: app-reader
      namespace: production
roleRef:
    kind: Role
    name: pod-reader
    apiGroup: rbac.authorization.k8s.io

Example 2: Full Access to Deployments

Kubernetesdeployment-admin.yml
# Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
    name: deployment-admin
    namespace: development
rules:
    - apiGroups: ["apps"]
      resources: ["deployments"]
      verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
# RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
    name: deployment-admin-binding
    namespace: development
subjects:
    - kind: ServiceAccount
      name: deployer-sa
      namespace: development
roleRef:
    kind: Role
    name: deployment-admin
    apiGroup: rbac.authorization.k8s.io

Example 3: Cluster-Wide Read Access

Kubernetescluster-reader.yml
# ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
    name: cluster-reader
rules:
    - apiGroups: [""]
      resources: ["pods", "services", "nodes"]
      verbs: ["get", "list", "watch"]
    - apiGroups: ["apps"]
      resources: ["deployments", "statefulsets"]
      verbs: ["get", "list", "watch"]
---
# ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
    name: cluster-reader-binding
subjects:
    - kind: ServiceAccount
      name: monitoring-sa
      namespace: monitoring
roleRef:
    kind: ClusterRole
    name: cluster-reader
    apiGroup: rbac.authorization.k8s.io

Example 4: Multiple Resources and Verbs

Kubernetesapp-manager.yml
# Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
    name: app-manager
    namespace: production
rules:
    # Manage Deployments
    - apiGroups: ["apps"]
      resources: ["deployments", "replicasets"]
      verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
    # Manage Services
    - apiGroups: [""]
      resources: ["services"]
      verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
    # Read ConfigMaps and Secrets
    - apiGroups: [""]
      resources: ["configmaps", "secrets"]
      verbs: ["get", "list"]
    # View Pods and logs
    - apiGroups: [""]
      resources: ["pods", "pods/log"]
      verbs: ["get", "list", "watch"]
---
# RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
    name: app-manager-binding
    namespace: production
subjects:
    - kind: ServiceAccount
      name: app-manager-sa
      namespace: production
roleRef:
    kind: Role
    name: app-manager
    apiGroup: rbac.authorization.k8s.io

Built-in ClusterRoles

Kubernetes provides default ClusterRoles:

view

Read-only access to most resources:

Kubernetesbash
kubectl get clusterrole view -o yaml

Permissions:

  • Read pods, services, deployments, etc.
  • Cannot read secrets
  • Cannot modify resources

edit

Read-write access to most resources:

Kubernetesbash
kubectl get clusterrole edit -o yaml

Permissions:

  • All view permissions
  • Create, update, delete resources
  • Cannot modify roles or rolebindings

admin

Full access within namespace:

Kubernetesbash
kubectl get clusterrole admin -o yaml

Permissions:

  • All edit permissions
  • Manage roles and rolebindings
  • Cannot modify namespace itself

cluster-admin

Full cluster access:

Kubernetesbash
kubectl get clusterrole cluster-admin -o yaml

Permissions:

  • Unrestricted access to all resources
  • Can perform any action
  • Use with extreme caution

Using Built-in Roles

Kubernetesuse-builtin-role.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
    name: developer-view
    namespace: development
subjects:
    - kind: ServiceAccount
      name: developer-sa
      namespace: development
roleRef:
    kind: ClusterRole
    name: view  # Built-in ClusterRole
    apiGroup: rbac.authorization.k8s.io

Aggregated ClusterRoles

Combine multiple ClusterRoles:

Kubernetesaggregated-role.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
    name: monitoring-role
aggregationRule:
    clusterRoleSelectors:
        - matchLabels:
              rbac.example.com/aggregate-to-monitoring: "true"
rules: []  # Rules automatically filled by aggregation
---
# Component role 1
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
    name: monitoring-pods
    labels:
        rbac.example.com/aggregate-to-monitoring: "true"
rules:
    - apiGroups: [""]
      resources: ["pods"]
      verbs: ["get", "list", "watch"]
---
# Component role 2
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
    name: monitoring-nodes
    labels:
        rbac.example.com/aggregate-to-monitoring: "true"
rules:
    - apiGroups: [""]
      resources: ["nodes"]
      verbs: ["get", "list", "watch"]

Testing RBAC

Check Permissions

Kubernetesbash
# Check if you can perform action
kubectl auth can-i create deployments
 
# Check for specific user/ServiceAccount
kubectl auth can-i get pods --as=system:serviceaccount:default:my-app-sa
 
# Check in specific namespace
kubectl auth can-i delete services --namespace=production
 
# List all permissions
kubectl auth can-i --list
kubectl auth can-i --list --as=system:serviceaccount:default:my-app-sa

Impersonate User

Kubernetesbash
# Run command as ServiceAccount
kubectl get pods --as=system:serviceaccount:default:my-app-sa
 
# Run command as user
kubectl get pods --as=john@example.com

Practical Examples

Example 1: CI/CD Pipeline ServiceAccount

Kubernetescicd-rbac.yml
# ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
    name: cicd-deployer
    namespace: default
---
# Role - Deploy applications
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
    name: deployer-role
    namespace: production
rules:
    # Manage Deployments
    - apiGroups: ["apps"]
      resources: ["deployments"]
      verbs: ["get", "list", "create", "update", "patch"]
    # Manage Services
    - apiGroups: [""]
      resources: ["services"]
      verbs: ["get", "list", "create", "update", "patch"]
    # Manage ConfigMaps
    - apiGroups: [""]
      resources: ["configmaps"]
      verbs: ["get", "list", "create", "update", "patch"]
    # Read Pods (for status checking)
    - apiGroups: [""]
      resources: ["pods"]
      verbs: ["get", "list", "watch"]
---
# RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
    name: cicd-deployer-binding
    namespace: production
subjects:
    - kind: ServiceAccount
      name: cicd-deployer
      namespace: default
roleRef:
    kind: Role
    name: deployer-role
    apiGroup: rbac.authorization.k8s.io

Example 2: Developer Access

Kubernetesdeveloper-rbac.yml
# ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
    name: developer
    namespace: development
---
# Role - Development environment access
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
    name: developer-role
    namespace: development
rules:
    # Full access to Deployments
    - apiGroups: ["apps"]
      resources: ["deployments", "replicasets"]
      verbs: ["*"]
    # Full access to Services
    - apiGroups: [""]
      resources: ["services"]
      verbs: ["*"]
    # Full access to ConfigMaps
    - apiGroups: [""]
      resources: ["configmaps"]
      verbs: ["*"]
    # Read-only Secrets
    - apiGroups: [""]
      resources: ["secrets"]
      verbs: ["get", "list"]
    # Pod management
    - apiGroups: [""]
      resources: ["pods", "pods/log", "pods/exec"]
      verbs: ["get", "list", "watch", "create", "delete"]
---
# RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
    name: developer-binding
    namespace: development
subjects:
    - kind: ServiceAccount
      name: developer
      namespace: development
roleRef:
    kind: Role
    name: developer-role
    apiGroup: rbac.authorization.k8s.io

Example 3: Monitoring System

Kubernetesmonitoring-rbac.yml
# ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
    name: prometheus
    namespace: monitoring
---
# ClusterRole - Read metrics cluster-wide
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
    name: prometheus-role
rules:
    # Read nodes
    - apiGroups: [""]
      resources: ["nodes", "nodes/metrics", "nodes/stats"]
      verbs: ["get", "list", "watch"]
    # Read pods
    - apiGroups: [""]
      resources: ["pods"]
      verbs: ["get", "list", "watch"]
    # Read services
    - apiGroups: [""]
      resources: ["services", "endpoints"]
      verbs: ["get", "list", "watch"]
    # Read metrics
    - apiGroups: ["metrics.k8s.io"]
      resources: ["nodes", "pods"]
      verbs: ["get", "list"]
---
# ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
    name: prometheus-binding
subjects:
    - kind: ServiceAccount
      name: prometheus
      namespace: monitoring
roleRef:
    kind: ClusterRole
    name: prometheus-role
    apiGroup: rbac.authorization.k8s.io

Example 4: Namespace Admin

Kubernetesnamespace-admin-rbac.yml
# ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
    name: namespace-admin
    namespace: production
---
# RoleBinding - Use built-in admin role
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
    name: namespace-admin-binding
    namespace: production
subjects:
    - kind: ServiceAccount
      name: namespace-admin
      namespace: production
roleRef:
    kind: ClusterRole
    name: admin  # Built-in ClusterRole
    apiGroup: rbac.authorization.k8s.io

Common Mistakes and Pitfalls

Mistake 1: Granting cluster-admin

Problem: Giving cluster-admin to everyone.

Kubernetesyml
# Bad: Too permissive
roleRef:
    kind: ClusterRole
    name: cluster-admin

Solution: Grant minimum necessary permissions:

Kubernetesyml
# Good: Specific permissions
roleRef:
    kind: ClusterRole
    name: view

Mistake 2: Using ClusterRoleBinding for Namespace Access

Problem: Granting cluster-wide access when namespace access sufficient.

Kubernetesyml
# Bad: Cluster-wide access
kind: ClusterRoleBinding

Solution: Use RoleBinding for namespace-scoped access:

Kubernetesyml
# Good: Namespace-scoped
kind: RoleBinding
metadata:
    namespace: production

Mistake 3: Wildcard Permissions

Problem: Using wildcards (*) for everything.

Kubernetesyml
# Bad: Too broad
rules:
    - apiGroups: ["*"]
      resources: ["*"]
      verbs: ["*"]

Solution: Be specific:

Kubernetesyml
# Good: Specific permissions
rules:
    - apiGroups: [""]
      resources: ["pods"]
      verbs: ["get", "list"]

Mistake 4: Not Testing Permissions

Problem: Deploying RBAC without testing.

Solution: Always test:

Kubernetesbash
kubectl auth can-i get pods --as=system:serviceaccount:default:my-app-sa

Mistake 5: Forgetting API Groups

Problem: Wrong or missing API group.

Kubernetesyml
# Bad: Missing API group for deployments
rules:
    - apiGroups: [""]  # Wrong! Deployments are in "apps"
      resources: ["deployments"]

Solution: Use correct API group:

Kubernetesyml
# Good: Correct API group
rules:
    - apiGroups: ["apps"]
      resources: ["deployments"]

Best Practices

Principle of Least Privilege

Grant only necessary permissions:

Kubernetesyml
# Minimal permissions
rules:
    - apiGroups: [""]
      resources: ["pods"]
      verbs: ["get", "list"]  # Only what's needed

Use Namespace-Scoped Roles

Prefer Role over ClusterRole:

Kubernetesyml
# Good: Namespace-scoped
kind: Role
metadata:
    namespace: production

Leverage Built-in Roles

Use view, edit, admin when appropriate:

Kubernetesyml
roleRef:
    kind: ClusterRole
    name: view  # Built-in role

Document RBAC Policies

Kubernetesyml
metadata:
    name: app-manager
    annotations:
        description: "Manages applications in production namespace"
        permissions: "deployments, services, configmaps"

Regular Audits

Review RBAC regularly:

Kubernetesbash
# List all RoleBindings
kubectl get rolebindings --all-namespaces
 
# List all ClusterRoleBindings
kubectl get clusterrolebindings
 
# Check specific permissions
kubectl auth can-i --list --as=system:serviceaccount:default:my-app-sa

Separate Roles by Function

Kubernetesyml
# Reader role
kind: Role
name: pod-reader
 
# Writer role
kind: Role
name: pod-writer
 
# Admin role
kind: Role
name: pod-admin

Viewing RBAC Resources

Get Roles

Kubernetesbash
kubectl get roles
kubectl get roles --all-namespaces
kubectl get clusterroles

Get RoleBindings

Kubernetesbash
kubectl get rolebindings
kubectl get rolebindings --all-namespaces
kubectl get clusterrolebindings

Describe RBAC Resources

Kubernetesbash
kubectl describe role pod-reader
kubectl describe rolebinding read-pods
kubectl describe clusterrole view
kubectl describe clusterrolebinding cluster-admin

View RBAC YAML

Kubernetesbash
kubectl get role pod-reader -o yaml
kubectl get rolebinding read-pods -o yaml

Deleting RBAC Resources

Kubernetesbash
# Delete Role
kubectl delete role pod-reader
 
# Delete RoleBinding
kubectl delete rolebinding read-pods
 
# Delete ClusterRole
kubectl delete clusterrole custom-role
 
# Delete ClusterRoleBinding
kubectl delete clusterrolebinding custom-binding

Conclusion

In episode 33, we've explored RBAC and RoleBinding in Kubernetes in depth. We've learned how to implement fine-grained access control using Roles, ClusterRoles, RoleBindings, and ClusterRoleBindings.

Key takeaways:

  • RBAC controls what authenticated subjects can do
  • Role defines namespace-scoped permissions
  • ClusterRole defines cluster-wide permissions
  • RoleBinding grants Role to subjects in namespace
  • ClusterRoleBinding grants ClusterRole cluster-wide
  • Rules specify apiGroups, resources, and verbs
  • Verbs include get, list, watch, create, update, delete
  • Built-in roles: view, edit, admin, cluster-admin
  • Use principle of least privilege
  • Prefer Role over ClusterRole when possible
  • Test permissions with kubectl auth can-i
  • Document RBAC policies
  • Regular audits of permissions
  • Avoid cluster-admin unless necessary
  • Separate roles by function

RBAC is fundamental to Kubernetes security. By understanding and properly implementing RBAC, you can ensure secure, controlled access to cluster resources, protecting your applications and data from unauthorized access.

Are you getting a clearer understanding of RBAC and RoleBinding in Kubernetes? Keep your learning momentum going and look forward to the next episode!

Catatan

If you want to continue to the next episode, you can click the Episode 34 thumbnail below

Episode 34Episode 34

Related Posts