Skip to content
Published on

Kubernetes RBAC Complete Guide: Hands-On Practice for Golden Kubestronaut Exam Prep

Authors
  • Name
    Twitter

1. What Is RBAC?

Kubernetes RBAC (Role-Based Access Control) is an authorization mechanism that controls access to API resources within a cluster based on roles. It is enabled when the --authorization-mode=RBAC flag is set on the kube-apiserver.

The core principle of RBAC is the Principle of Least Privilege. Every user and service account should be granted only the minimum permissions necessary to perform their duties.

1.1 The 4 Core RBAC Resources

ResourceScopePurpose
RoleNamespaceDefines permissions for resources within a specific namespace
ClusterRoleCluster-wideDefines permissions for cluster-scoped resources or common permissions across multiple namespaces
RoleBindingNamespaceBinds a Role or ClusterRole to subjects within a specific namespace
ClusterRoleBindingCluster-wideBinds a ClusterRole to subjects across the entire cluster

2. Role and ClusterRole in Detail

2.1 Creating a Namespace Role

# dev-reader-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: development
  name: pod-reader
rules:
  - apiGroups: [''] # core API group
    resources: ['pods']
    verbs: ['get', 'watch', 'list']
  - apiGroups: ['']
    resources: ['pods/log']
    verbs: ['get']
  - apiGroups: ['apps']
    resources: ['deployments']
    verbs: ['get', 'list']

2.2 Creating a ClusterRole

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: node-viewer
rules:
  - apiGroups: ['']
    resources: ['nodes']
    verbs: ['get', 'list', 'watch']
  - apiGroups: ['metrics.k8s.io']
    resources: ['nodes']
    verbs: ['get', 'list']

2.3 Aggregated ClusterRole

The Aggregated ClusterRole pattern, frequently tested in the CKS exam:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: monitoring-endpoints
  labels:
    rbac.example.com/aggregate-to-monitoring: 'true'
rules:
  - apiGroups: ['']
    resources: ['services', 'endpoints', 'pods']
    verbs: ['get', 'list', 'watch']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: monitoring
aggregationRule:
  clusterRoleSelectors:
    - matchLabels:
        rbac.example.com/aggregate-to-monitoring: 'true'
rules: [] # Automatically populated

3. RoleBinding and ClusterRoleBinding

3.1 RoleBinding: Granting Permissions Within a Namespace

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: development
subjects:
  - kind: User
    name: jane
    apiGroup: rbac.authorization.k8s.io
  - kind: ServiceAccount
    name: ci-bot
    namespace: development
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

3.2 Using a ClusterRole with a RoleBinding (Important!)

When a ClusterRole is bound via a RoleBinding, it is only effective within that namespace. This is very useful for reusing a common set of permissions across multiple namespaces:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods-staging
  namespace: staging
subjects:
  - kind: Group
    name: dev-team
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole # It's a ClusterRole, but
  name: pod-reader # since it's a RoleBinding, it's only effective in the staging NS
  apiGroup: rbac.authorization.k8s.io

4. ServiceAccount and RBAC

4.1 ServiceAccount Tokens (1.24+)

Starting from Kubernetes 1.24, automatic Secret creation for SAs has been discontinued:

# Create a ServiceAccount
kubectl create serviceaccount monitoring-sa -n monitoring

# Create a short-lived token (1 hour)
kubectl create token monitoring-sa -n monitoring --duration=3600s

# Long-lived token (for legacy compatibility)
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: monitoring-sa-token
  namespace: monitoring
  annotations:
    kubernetes.io/service-account.name: monitoring-sa
type: kubernetes.io/service-account-token
EOF

4.2 Disabling SA Token Mount on Pods

apiVersion: v1
kind: Pod
metadata:
  name: secure-pod
spec:
  automountServiceAccountToken: false
  containers:
    - name: app
      image: nginx:1.27

5. Hands-On: Multi-Tenant RBAC Configuration

5.1 Scenario

  • frontend-team: frontend NS — Manage Deployments, Services, ConfigMaps
  • backend-team: backend NS — All workloads + read Secrets
  • platform-team: Cluster-wide — Read-only + Node/PV management

5.2 Implementation

kubectl create ns frontend
kubectl create ns backend

# 1) frontend-team
cat <<'EOF' | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: frontend
  name: frontend-developer
rules:
- apiGroups: ["", "apps"]
  resources: ["deployments", "services", "configmaps", "pods"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
  resources: ["pods/log", "pods/exec"]
  verbs: ["get", "create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: frontend
  name: frontend-team-binding
subjects:
- kind: Group
  name: frontend-team
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: frontend-developer
  apiGroup: rbac.authorization.k8s.io
EOF

# 2) backend-team
cat <<'EOF' | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: backend
  name: backend-developer
rules:
- apiGroups: ["", "apps", "batch"]
  resources: ["*"]
  verbs: ["*"]
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: backend
  name: backend-team-binding
subjects:
- kind: Group
  name: backend-team
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: backend-developer
  apiGroup: rbac.authorization.k8s.io
EOF

# 3) platform-team
cat <<'EOF' | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: platform-admin
rules:
- apiGroups: [""]
  resources: ["nodes", "persistentvolumes"]
  verbs: ["*"]
- apiGroups: ["", "apps", "batch", "networking.k8s.io"]
  resources: ["*"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: platform-team-binding
subjects:
- kind: Group
  name: platform-team
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: platform-admin
  apiGroup: rbac.authorization.k8s.io
EOF

5.3 Permission Verification

# Can frontend-team list pods in the frontend NS?
kubectl auth can-i list pods --namespace=frontend --as=jane --as-group=frontend-team
# yes

# Can frontend-team delete pods in the backend NS?
kubectl auth can-i delete pods --namespace=backend --as=jane --as-group=frontend-team
# no

# Full permission list (CKS exam tip!)
kubectl auth can-i --list --as=jane --as-group=frontend-team -n frontend

6. CKS Exam Frequently Tested RBAC Scenarios

6.1 Detecting Dangerous Permissions

# Find cluster-admin bindings
kubectl get clusterrolebindings -o json | jq -r '
  .items[] |
  select(.roleRef.name == "cluster-admin") |
  .metadata.name + " -> " +
  (.subjects[]? | .kind + "/" + .name)'

# Find Roles with wildcard (*) permissions
kubectl get roles,clusterroles -A -o json | jq -r '
  .items[] |
  select(.rules[]?.verbs[]? == "*" or .rules[]?.resources[]? == "*") |
  .metadata.namespace + "/" + .metadata.name'

6.2 Secret Access Auditing

kubectl get roles,clusterroles -A -o json | jq -r '
  .items[] |
  select(.rules[]? | .resources[]? == "secrets") |
  "\(.metadata.namespace // "cluster")/\(.metadata.name)"'

6.3 Pod Security Standards + RBAC Combination

apiVersion: v1
kind: Namespace
metadata:
  name: secure-ns
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

7. RBAC Best Practices

  1. Principle of Least Privilege: Avoid wildcards (*), explicitly specify only the required verbs
  2. Minimize ClusterRoleBindings: Use RoleBinding + ClusterRole combinations whenever possible
  3. Separate ServiceAccounts: Create dedicated SAs per Pod, avoid using the default SA
  4. Disable Token Mounting: Set automountServiceAccountToken: false by default
  5. Regular Auditing: Periodically review permissions with kubectl auth can-i --list
  6. Leverage Aggregated ClusterRoles: Modularized permission management
  7. Use Impersonation: Test permissions with the --as flag before applying

8. Common Mistakes and Solutions

MistakeProblemSolution
Confusing ClusterRole + RoleBinding vs ClusterRoleBindingScope mismatchThe Binding type determines the scope
Missing apiGroups: [""]Cannot access core resourcesCore API = empty string
Not including subresourcesCannot access pods/log, pods/execMust be explicitly specified
Unaware of SA token expiration1.24+ uses short-lived tokens by defaultSet --duration

9. Quiz

Q1. What is the main difference between Role and ClusterRole?

A Role is only effective within a specific namespace, while a ClusterRole defines permissions with cluster-wide scope. ClusterRoles can also grant permissions on non-namespaced resources like Nodes and PVs.

Q2. What happens when a ClusterRole is bound to a RoleBinding?

The permissions defined in the ClusterRole become effective only within the namespace where the RoleBinding belongs.

Q3. What changed regarding ServiceAccount tokens after Kubernetes 1.24+?

Automatic Secret creation was discontinued. You must create short-lived tokens (default 1 hour) with kubectl create token or manually create a kubernetes.io/service-account-token Secret.

Q4. Why should you set automountServiceAccountToken: false?

To prevent unnecessary SA token mounting inside Pods, blocking an attacker's access to the K8s API in case of container compromise. This is part of the Principle of Least Privilege.

Q5. What does kubectl auth can-i delete pods --as=jane -n production do?

Using the Impersonation feature, it checks whether user jane has permission to delete Pods in the production namespace.

Q6. How does Aggregated ClusterRole work?

Rules from other ClusterRoles that match the label selector in aggregationRule are automatically merged. When a new matching ClusterRole is added, it is automatically reflected.

Q7. How can you find excessive (cluster-admin) permission bindings?

Filter bindings where roleRef.name == "cluster-admin" using kubectl get clusterrolebindings -o json | jq.

Q8. What are the 3 key RBAC topics tested in the KCSA exam?

(1) Principle of Least Privilege — avoid wildcards (2) SA Security — disable token mounting, don't use the default SA (3) Regular Auditing — can-i --list, detect excessive ClusterRoleBindings