Skip to content

RBAC and Security in Kubernetes: Roles, Bindings & Best Practices

DodaTech 5 min read

In this tutorial, you'll learn about RBAC and Security in Kubernetes: Roles, Bindings & Best Practices. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

Kubernetes Role-Based Access Control (RBAC) governs who can access the cluster API and what actions they can perform, using Roles, ClusterRoles, and bindings to enforce least-privilege security across users and service accounts.

What You'll Learn

This tutorial covers RBAC resources including Roles and ClusterRoles, RoleBindings and ClusterRoleBindings, service account permissions, pod security context, audit logging configuration, and production security hardening practices.

Why It Matters

Misconfigured RBAC is the leading cause of Kubernetes security breaches. Overly permissive roles let attackers pivot from a compromised pod to control the entire cluster. Proper RBAC limits Blast Radius and is required for Compliance frameworks like SOC 2 and PCI DSS.

Real-World Use

Spotify operates over 300 Kubernetes clusters with fine-grained RBAC that restricts each team to their own namespaces while allowing Containerization platform engineers full cluster access. Capital One uses RBAC with custom audit logging to detect and alert on unauthorized API calls within minutes.

graph TD
  A[User / ServiceAccount] --> B[Authentication]
  B --> C{RBAC Authorization}
  C --> D[RoleBinding]
  C --> E[ClusterRoleBinding]
  D --> F[Role namespace-scoped]
  E --> G[ClusterRole cluster-scoped]
  F --> H[Allow / Deny API actions]
  G --> H

Expected output: diagram showing how users and service accounts authenticate, then RBAC authorization checks RoleBindings and ClusterRoleBindings to determine allowed API actions.

Roles and ClusterRoles

Roles grant permissions within a namespace. ClusterRoles grant permissions cluster-wide.

# Namespace-scoped Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: development
  name: pod-manager
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log", "pods/exec"]
  verbs: ["get", "list", "watch", "create", "update", "delete"]
- apiGroups: ["apps"]
  resources: ["deployments", "statefulsets"]
  verbs: ["get", "list", "watch", "create", "update"]
---
# Cluster-scoped ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-admin
rules:
- apiGroups: [""]
  resources: ["nodes", "namespaces", "persistentvolumes"]
  verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: ["rbac.authorization.k8s.io"]
  resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
  verbs: ["*"]
# Create the Role and ClusterRole
kubectl apply -f rbac-roles.yaml

# List Roles in a namespace
kubectl get roles -n development

# List ClusterRoles
kubectl get clusterroles | grep -E "pod-manager|cluster-admin"

Expected output: roles and clusterroles are created with the specified permissions. The custom roles appear alongside the four default clusterroles (cluster-admin, admin, edit, view).

RoleBindings and ClusterRoleBindings

Bindings assign roles to subjects (users, groups, or service accounts).

# Bind a Role to a user in a namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: development
  name: pod-manager-binding
subjects:
- kind: User
  name: alice@example.com
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-manager
  apiGroup: rbac.authorization.k8s.io
---
# Bind a ClusterRole to all authenticated users
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: view-only-binding
subjects:
- kind: Group
  name: system:authenticated
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: view
  apiGroup: rbac.authorization.k8s.io
# Test RBAC permissions
kubectl auth can-i create pods --namespace development --as alice@example.com

# Check who can delete nodes
kubectl auth can-i delete nodes --as bob@example.com

# Verify binding
kubectl get rolebinding pod-manager-binding -n development -o yaml

Expected output: kubectl auth can-i returns "yes" for permitted actions and "no" for denied actions. The rolebinding YAML shows the subjects and roleRef.

Service Account Permissions

Service accounts grant pod-level permissions for API access.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: pipeline-sa
  namespace: ci
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: ci
  name: pipeline-role
rules:
- apiGroups: ["", "apps", "batch"]
  resources: ["pods", "deployments", "jobs"]
  verbs: ["get", "list", "watch", "create", "update", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: ci
  name: pipeline-binding
subjects:
- kind: ServiceAccount
  name: pipeline-sa
  namespace: ci
roleRef:
  kind: Role
  name: pipeline-role
  apiGroup: rbac.authorization.k8s.io
apiVersion: v1
kind: Pod
metadata:
  name: ci-agent
spec:
  serviceAccountName: pipeline-sa
  automountServiceAccountToken: true
  containers:
  - name: agent
    image: bitnami/kubectl:latest
    command: ["kubectl", "get", "pods"]
# Create the service account and binding
kubectl apply -f sa-pipeline.yaml

# Verify the pod can list pods
kubectl logs ci-agent

Expected output: the pod successfully lists pods in the ci namespace. Without the RoleBinding, the same command would return a Forbidden error.

Pod Security Context

Restrict what pods can do at the container and pod level.

apiVersion: v1
kind: Pod
metadata:
  name: secure-pod
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: myapp:1.0
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop:
        - ALL
        add:
        - NET_BIND_SERVICE
      runAsUser: 1000
      runAsGroup: 3000
# Check pod security context
kubectl exec secure-pod -- id

# Verify read-only root
kubectl exec secure-pod -- touch /test

Expected output: the id command shows uid=1000 gid=3000. The touch command fails with "Read-only file system."

Practice Questions

  1. What is the difference between a Role and a ClusterRole? A Role grants permissions within a single namespace. A ClusterRole grants permissions cluster-wide, including non-namespaced resources like nodes and namespaces.

  2. How do you restrict a service account to specific API operations? Create a Role with only the required verbs (get, list, watch) on specific resources, then bind it to the service account with a RoleBinding.

  3. What does automountServiceAccountToken: false do? It prevents the pod from automatically mounting the service account token, reducing the attack surface if the pod does not need API access.

Frequently Asked Questions

What is the default RBAC behavior when no roles are bound?

By default, Kubernetes denies all API requests. There is no implicit allow. If no RoleBinding or ClusterRoleBinding grants a user or service account permission for an action, the API server returns a 403 Forbidden error. The cluster-admin ClusterRoleBinding for the kube-system service accounts ensures core components can operate.

How do I audit RBAC permissions across the cluster?

Use kubectl auth can-i --list to view permissions for the current user. For cluster-wide auditing, use tools like rbac-lookup, rbac-manager, or kubectl who-can. Third-party tools like kube-bench and kube-hunter scan for overly permissive roles and suggest remediation.

Can I use groups from an external identity provider with RBAC?

Yes. Configure OIDC integration with the API server using --oidc-* flags. When a user authenticates via OIDC, their group memberships are extracted from the token. You can then create RoleBindings that reference those group names as subjects, enabling centralized group management through your identity provider.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro