Introduction to Kubernetes RBAC: Why Authorization Matters
Role-Based Access Control (RBAC) is Kubernetes' primary authorization mechanism that determines who can access which resources and perform what actions in your cluster. While authentication answers the question "Who are you?" (proving identity through certificates, tokens, or OIDC), authorization answers the equally critical question "What are you allowed to do?" (defining permissions based on roles). Without proper RBAC configuration, you face severe security risks including unauthorized access to sensitive resources like Secrets containing database passwords and API keys, privilege escalation where users grant themselves cluster-admin permissions, lateral movement where compromised pods access resources they shouldn't reach, compliance violations failing SOC 2, HIPAA, PCI-DSS, or GDPR audits, and insider threats from malicious or negligent employees with excessive permissions.
RBAC is absolutely critical for several operational and security requirements in production Kubernetes environments. First, security and least privilege RBAC enables implementing the principle of least privilege where users and service accounts receive only the minimum permissions necessary to perform their legitimate functions, nothing more. This dramatically limits the blast radius if credentials are compromised or if application bugs are exploited. Second, in multi-tenant, isolated Kubernetes clusters where multiple teams, projects, or customers run workloads side-by-side, RBAC provides hard security boundaries that prevent Team A from viewing, modifying, or deleting Team B's deployments, secrets, or data, enabling safe multi-tenant operation on shared infrastructure. Third, compliance and audit regulatory frameworks like SOC 2, HIPAA for healthcare, PCI-DSS for payment processing, and GDPR for EU data require demonstrable access controls with audit trails showing who accessed what resources and when, capabilities that RBAC provides through audit logging of API server requests. Fourth, operational safety RBAC prevents accidental destructive actions like a developer accidentally deleting production databases thinking they were in staging, or CI/CD pipelines with overly broad permissions accidentally wiping out entire namespaces during deployment automation gone wrong.
However, Kubernetes RBAC is notoriously complex and difficult to implement correctly. The permission model involves four different resource types (Role, ClusterRole, RoleBinding, ClusterRoleBinding) with subtle differences in scope and behavior. Understanding how permissions aggregate, how verb wildcards work, which API groups resources belong to, and the interaction between namespace-scoped and cluster-scoped permissions requires deep knowledge that most teams lack initially. Common mistakes include granting overly broad permissions using wildcards for convenience (apiGroups: ["*"], resources: ["*"], verbs: ["*"]), creating privilege escalation vulnerabilities by granting users permissions to modify RBAC resources themselves, binding too many users or service accounts to the dangerous cluster-admin ClusterRole giving unlimited cluster access, and creating RBAC configurations so complex that nobody fully understands who can actually do what, making security audits impossible.
This comprehensive technical guide teaches you everything about Kubernetes RBAC from foundational concepts to advanced production patterns, covering: the four core RBAC resource types and how they interact, the RBAC authorization formula (Who + Can Do What + On Which Resources = Permission), creating namespace-scoped Roles for tenant isolation, creating cluster-scoped ClusterRoles for cluster-wide permissions, RoleBindings and ClusterRoleBindings with subjects (Users, Groups, ServiceAccounts), real-world RBAC examples for common scenarios (read-only users, developers, DevOps engineers, CI/CD pipelines, monitoring systems), understanding Kubernetes API groups and how they map to resources, advanced RBAC patterns like aggregated ClusterRoles and fine-grained resource name restrictions, testing and auditing RBAC permissions to prevent misconfigurations, troubleshooting "Forbidden" errors systematically, security best practices to avoid common vulnerabilities, and how Atmosly automates RBAC management with pre-configured production-ready role templates (super_admin, read_only, devops), automatic subject binding ensuring permissions actually work, and validation preventing common RBAC mistakes that leave resources accessible to unauthorized users or break legitimate access.
By completing this guide, you'll master Kubernetes RBAC, be able to design and implement secure least-privilege access controls for your entire organization, troubleshoot permission issues efficiently, audit your cluster's authorization posture, and avoid the security vulnerabilities that plague poorly-configured Kubernetes clusters in the wild.
RBAC Core Concepts: The Four Resource Types
Understanding the RBAC Resource Quartet
Kubernetes RBAC consists of exactly four resource types that work together to define permissions. Understanding each type, when to use it, and how they combine is fundamental to mastering authorization.
1. Role: Namespace-Scoped Permissions
A Role defines a set of permissions within a single specific namespace. Roles can only grant access to namespaced resources (Pods, Services, Deployments, ConfigMaps, Secrets, etc.) and only within the namespace where the Role is created. Roles are the foundation of multi-tenant security in Kubernetes each team gets a namespace and Roles define what they can do within that namespace boundary.
When to use Role:
- Granting permissions to resources within a specific namespace (production, staging, team-a, etc.)
- Multi-tenant clusters where teams should not see or affect each other's resources
- Following principle of least privilege limiting permissions to smallest necessary scope
- Application-specific permissions (this app can read these ConfigMaps in this namespace)
2. ClusterRole: Cluster-Wide Permission Template
A ClusterRole defines permissions that can be used cluster-wide. Unlike Roles, ClusterRoles can grant access to: cluster-scoped resources that don't belong to any namespace (Nodes, PersistentVolumes, Namespaces themselves, ClusterRoles, ClusterRoleBindings), namespaced resources across all namespaces (when bound via ClusterRoleBinding), and non-resource URLs (like /healthz, /metrics, /api). ClusterRoles are templates that can be reused bind the same ClusterRole to different users in different namespaces via RoleBindings.
When to use ClusterRole:
- Granting access to non-namespaced resources (Nodes, PVs, Namespaces)
- Defining reusable permission sets that can be bound in multiple namespaces
- Cluster-admin type permissions for SREs who need broad access
- Monitoring or system components that need to watch resources across all namespaces
3. RoleBinding: Connecting Users to Namespace Permissions
A RoleBinding connects subjects (users, groups, or service accounts) to a Role, granting the permissions defined in that Role within a specific namespace. RoleBindings can reference either a Role (in same namespace) or a ClusterRole (reusing cluster-wide permission template in just this namespace). This is key for reusability define ClusterRole "view" once, bind it to different users in different namespaces via RoleBindings.
4. ClusterRoleBinding: Connecting Users to Cluster-Wide Permissions
A ClusterRoleBinding grants permissions defined in a ClusterRole cluster-wide (all namespaces). This is powerful but dangerous use sparingly. ClusterRoleBindings are appropriate for cluster administrators, monitoring systems that need to watch all namespaces, and system components, but should never be used for regular application developers or most service accounts.
The RBAC Permission Formula
Every RBAC permission can be expressed as this simple formula:
WHO (Subject) + CAN DO WHAT (Verbs) + ON WHICH RESOURCES = Permission Grant
Example: User "alice" + can "get" and "list" + "pods" in namespace "production"
Subject Types (Who):
- User: Human users authenticated via certificates, OIDC tokens, or webhook. Format:
kind: User, name: [email protected] - Group: Groups of users from authentication system (OIDC groups, certificate O field). Format:
kind: Group, name: developers, apiGroup: rbac.authorization.k8s.io - ServiceAccount: Pod identities for applications running in cluster. Format:
kind: ServiceAccount, name: my-app-sa, namespace: production
Verbs (Can Do What):
get: Read a specific resource by name (kubectl get pod my-pod)list: List all resources of a type (kubectl get pods)watch: Subscribe to resource changes (kubectl get pods --watch)create: Create new resources (kubectl apply, kubectl create)update: Modify existing resources completely (kubectl apply with changes)patch: Partially update resources (kubectl patch, kubectl set)delete: Remove individual resources (kubectl delete pod my-pod)deletecollection: Delete multiple resources (kubectl delete pods --all)*: All verbs (wildcard—use very carefully)
Special Verbs for Subresources:
getonpods/log: View container logscreateonpods/exec: Execute commands in containers (shell access)createonpods/portforward: Port forward to podsgetonpods/status: Read pod status subresourceupdateondeployments/scale: Scale deployments
Resources (On Which Resources):
Resources are grouped by API groups. Common mappings:
- Core API group (""): pods, services, configmaps, secrets, persistentvolumeclaims, namespaces, nodes, events
- apps: deployments, statefulsets, daemonsets, replicasets
- batch: jobs, cronjobs
- networking.k8s.io: networkpolicies, ingresses
- rbac.authorization.k8s.io: roles, rolebindings, clusterroles, clusterrolebindings
- autoscaling: horizontalpodautoscalers
- storage.k8s.io: storageclasses
Creating Roles: Namespace-Scoped Permissions
Basic Role Example with Detailed Explanation
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production # This Role only applies in production namespace
name: pod-reader # Descriptive name
rules:
- apiGroups: [""] # Core API group (pods, services, configmaps)
resources: ["pods"] # Can access pod resources
verbs: ["get", "list", "watch"] # Read-only verbs (no create/delete)
What this Role allows:
- ✅
kubectl get pods -n production: List all pods - ✅
kubectl get pod my-pod -n production: Get specific pod - ✅
kubectl get pods -n production --watch: Watch pod changes - ❌
kubectl delete pod my-pod -n production: Cannot delete (no delete verb) - ❌
kubectl get pods -n staging: Cannot access staging namespace - ❌
kubectl logs my-pod -n production: Cannot view logs (needs pods/log resource)
Multi-Rule Role for Complete Access
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: developer-full-access
rules:
# Read-write access to common resources
- apiGroups: ["", "apps", "batch"]
resources:
- pods
- services
- configmaps
- deployments
- jobs
- cronjobs
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# Read-only access to secrets (view but not modify)
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list"] # Deliberately no create/update/delete
# View logs
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get", "list"]
# View pod status
- apiGroups: [""]
resources: ["pods/status"]
verbs: ["get"]
# Scale deployments
- apiGroups: ["apps"]
resources: ["deployments/scale"]
verbs: ["get", "update", "patch"]
# EXPLICITLY no pods/exec (no shell access to containers)
# EXPLICITLY no RBAC resources (cannot modify roles/bindings)
What this allows: Developers can deploy, update, delete their applications, view logs for troubleshooting, scale deployments, read secrets (to verify they exist) but not modify them, but CANNOT exec into containers for security reasons and CANNOT modify RBAC to grant themselves more permissions.
Creating ClusterRoles: Cluster-Wide Permission Templates
ClusterRole for Non-Namespaced Resources
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-manager
rules:
# Nodes are cluster-scoped (no namespace)
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch", "update", "patch"]
# Also grant access to node metrics
- apiGroups: ["metrics.k8s.io"]
resources: ["nodes"]
verbs: ["get", "list"]
# PersistentVolumes are also cluster-scoped
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch"]
Use case: Infrastructure team managing nodes and storage, but not application workloads.
ClusterRole for Reusable Cross-Namespace Permissions
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: readonly-all-namespaces
rules:
- apiGroups: ["", "apps", "batch"]
resources: ["pods", "services", "deployments", "jobs"]
verbs: ["get", "list", "watch"]
This ClusterRole can be bound via:
- ClusterRoleBinding: User gets read-only access to ALL namespaces cluster-wide
- RoleBinding (in specific namespace): User gets read-only access only in that namespace
This reusability is powerful define permission set once, reuse across multiple namespaces.
Understanding RoleBindings: Granting Permissions
RoleBinding Connecting User to Role
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: alice-developer-binding
namespace: production # Bindings are namespace-scoped
subjects:
# Human user
- kind: User
name: [email protected] # From OIDC authentication
apiGroup: rbac.authorization.k8s.io
# Service account (for pods)
- kind: ServiceAccount
name: my-app-sa
namespace: production # ServiceAccount namespace
# Group of users
- kind: Group
name: developers # From OIDC group claim
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role # Or ClusterRole if binding to ClusterRole
name: developer-full-access
apiGroup: rbac.authorization.k8s.io
Key points:
- One RoleBinding can grant permissions to multiple subjects (users, groups, service accounts)
- RoleBinding exists in a namespace, grants permissions only in that namespace
- Can bind to Role (same namespace) or ClusterRole (reusing cluster-wide template)
- roleRef is immutable to change which role is bound, delete and recreate RoleBinding
ClusterRoleBinding: Cluster-Wide Permission Grant
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-monitoring # No namespace (cluster-scoped)
subjects:
- kind: ServiceAccount
name: prometheus
namespace: monitoring
roleRef:
kind: ClusterRole
name: prometheus-server # Must be ClusterRole
apiGroup: rbac.authorization.k8s.io
Use cases for ClusterRoleBinding:
- Cluster administrators needing full access everywhere
- Monitoring systems (Prometheus, Datadog) needing to scrape metrics across all namespaces
- Cluster-level automation or operators
- Security scanning tools needing read access to all resources
⚠️ Warning: ClusterRoleBinding grants permissions cluster-wide. Use sparingly. Most users should have RoleBindings (namespace-limited), not ClusterRoleBindings.
Real-World RBAC Examples for Common Scenarios
Example 1: Read-Only Developer (View Only, No Changes)
Requirement: Junior developers need to view resources in staging namespace for learning and troubleshooting, but cannot make any modifications to prevent accidental breakage.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: staging
name: developer-readonly
rules:
# Read access to common resources
- apiGroups: ["", "apps", "batch", "networking.k8s.io"]
resources:
- pods
- services
- configmaps
- deployments
- replicasets
- statefulsets
- daemonsets
- jobs
- cronjobs
- ingresses
verbs: ["get", "list", "watch"] # Read-only
# View container logs (critical for troubleshooting)
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get", "list"]
# View pod status and metrics
- apiGroups: [""]
resources: ["pods/status"]
verbs: ["get"]
# View events (helps understand what happened)
- apiGroups: [""]
resources: ["events"]
verbs: ["get", "list", "watch"]
# EXPLICITLY no secrets access (not even read)
# EXPLICITLY no pods/exec (no shell access)
# EXPLICITLY no delete permissions on anything
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: junior-developers-readonly
namespace: staging
subjects:
- kind: Group
name: junior-developers # From OIDC
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: developer-readonly
apiGroup: rbac.authorization.k8s.io
Example 2: Senior Developer (Full Application Access, No Infrastructure)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: senior-developer
rules:
# Full CRUD on application resources
- apiGroups: ["apps"]
resources: ["deployments", "replicasets", "statefulsets"]
verbs: ["*"] # All verbs for these resources
# Full CRUD on services and config
- apiGroups: [""]
resources: ["services", "configmaps", "secrets"]
verbs: ["*"]
# Pod management including exec access for debugging
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["pods/log", "pods/exec", "pods/portforward"]
verbs: ["get", "create"] # Can exec into containers, port-forward, view logs
# Manage horizontal pod autoscalers
- apiGroups: ["autoscaling"]
resources: ["horizontalpodautoscalers"]
verbs: ["*"]
# EXPLICITLY no PersistentVolumeClaim deletion (data safety)
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "create"] # Can create but not delete
# EXPLICITLY no RBAC resources (cannot escalate privileges)
# EXPLICITLY no node access (infrastructure managed separately)
Example 3: CI/CD Pipeline Service Account
apiVersion: v1
kind: ServiceAccount
metadata:
name: cicd-deployer-sa
namespace: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: cicd-deployer
rules:
# Deploy and update applications
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "create", "update", "patch"]
# Manage services
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list", "create", "update", "patch"]
# Update configmaps and secrets during deployment
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list", "create", "update"]
# Read pods to verify deployment success
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
# Read events to troubleshoot deployment failures
- apiGroups: [""]
resources: ["events"]
verbs: ["get", "list"]
# EXPLICITLY no delete permissions (CI/CD should not delete production resources)
# EXPLICITLY no pods/exec (pipelines should not shell into containers)
# EXPLICITLY no RBAC modification
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: cicd-deployer-binding
namespace: production
subjects:
- kind: ServiceAccount
name: cicd-deployer-sa
namespace: production
roleRef:
kind: Role
name: cicd-deployer
apiGroup: rbac.authorization.k8s.io
[Content continues with monitoring service account example, DevOps role, advanced patterns, aggregated ClusterRoles, resource name restrictions, testing permissions, troubleshooting, security best practices, Atmosly automation, and comprehensive conclusion...]
How Atmosly Automates and Simplifies RBAC Management
Pre-Configured Production-Ready Role Templates
Instead of writing complex RBAC YAML from scratch and hoping you got API groups and verbs correct, Atmosly provides three battle-tested role templates designed for common use cases:
1. super_admin Role Template:
- Cluster-wide full privileges (equivalent to cluster-admin)
- All resources (* in apiGroups, resources, verbs)
- All namespaces (via ClusterRoleBinding)
- Use for: Cluster administrators, SRE team leads
- Users: Very limited (2-5 max in production clusters)
2. read_only Role Template:
- Get/list/watch permissions only (no modifications)
- All standard resource groups (core, apps, batch, networking, storage, policy, autoscaling)
- EXCLUDES RBAC resources (cannot view roles/bindings for security)
- EXCLUDES secrets (view pods/configmaps but not sensitive secrets)
- Use for: Auditors, junior developers, support teams, monitoring dashboards
3. devops Role Template:
- Full verbs (get, list, watch, create, update, patch, delete) on application resources
- Resources: Deployments, Services, Pods, ConfigMaps, Jobs, CronJobs, HPAs, NetworkPolicies
- EXCLUDES RBAC modification rights (cannot escalate own privileges)
- EXCLUDES node management (infrastructure team responsibility)
- Use for: DevOps engineers, senior developers, SREs
Automatic Subject Binding (Critical for RBAC to Actually Work)
A common RBAC mistake: Creating perfect Roles/ClusterRoles but forgetting proper subjects in bindings. Without subjects, RBAC grants no permissions to anyone.
Atmosly prevents this by:
- Automatically creating Kubernetes ServiceAccounts for each Atmosly platform user
- Applying ClusterRoles via ops-agent with proper labels and annotations
- Creating ClusterRoleBindings with correctly formatted subjects referencing ServiceAccounts
- Validating bindings have at least one subject before applying (empty subjects = useless binding)
- Testing permissions with
kubectl auth can-iafter binding to confirm it works
Without proper subjects:
# Broken RoleBinding (no one gets permissions!)
subjects: [] # Empty subjects array
# Ops-agent reports:
# "ClusterRole applied successfully; no subjects to bind - no permissions granted"
Atmosly ensures subjects always populated:
subjects:
- kind: ServiceAccount
name: alice-atmosly-sa # Auto-created by Atmosly
namespace: default
- kind: ServiceAccount
name: bob-atmosly-sa
namespace: default
Advanced RBAC Patterns for Complex Scenarios
Once you move beyond a few teams and one or two namespaces, simple Role + RoleBinding patterns quickly become hard to maintain. These patterns help you stay secure and keep RBAC manageable.
Aggregated ClusterRoles for layered access
Instead of maintaining one giant “editor” ClusterRole, you can define small, focused roles (logs, workloads, config, etc.) and aggregate them into a single higher-level role.
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: app-view-pods labels: rbac.authorization.k8s.io/aggregate-to-app-edit: "true" rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: app-editor aggregationRule: clusterRoleSelectors: - matchLabels: rbac.authorization.k8s.io/aggregate-to-app-edit: "true" rules: [] # rules are populated from matching roles
Platform teams can now add/remove capabilities by creating or updating small roles, instead of editing one huge YAML file.
Resource-name and subresource scoping
You don’t always want access to all objects of a type. resourceNames lets you scope a role to specific objects, e.g. a single Secret:
rules: - apiGroups: [""] resources: ["secrets"] resourceNames: ["db-credentials-prod"] verbs: ["get"]
Combine this with subresources to separate logs vs shell access:
pods – basic pod metadata and status
pods/log – log access
pods/exec – shell/command execution
pods/portforward – port-forwarding
A common pattern in production:
Allow pods + pods/log for developers
Restrict pods/exec and pods/portforward to SRE / on-call only
Namespace and tenant isolation
For multi-tenant scenarios, a clean pattern is:
One or more namespaces per team/tenant: acme-dev, acme-prod, …
A reusable tenant-admin ClusterRole
Namespace-scoped RoleBindings per tenant
This gives each team full control over their own namespaces without needing custom roles for every project, and keeps cross-tenant access easy to reason about.
Testing and Validating RBAC Permissions
RBAC should be treated like code: you test it before trusting it. That avoids “grant random extra permissions until it works” in production.
Use kubectl auth can-i for quick checks
kubectl auth can-i is the primary tool to validate permissions:
# Check if a user can list pods in staging kubectl auth can-i list pods \ --as [email protected] \ -n staging # List everything a group can do kubectl auth can-i --list \ --as-group dev-team \ -n staging
You can also test service accounts:
kubectl auth can-i get secrets \ --as system:serviceaccount:staging:api-sa \ -n staging
If this command returns no, your RBAC is missing something. Fix the role, then re-run the same command.
Validate in a sandbox namespace
Before touching production, validate new roles in a sandbox like rbac-sandbox:
Create rbac-sandbox namespace.
Bind the new Role/ClusterRole to a test user/service account there.
Ask the team (or use impersonation) to run:
A few expected-to-succeed commands.
A few expected-to-fail commands (delete, exec in prod-like namespace, etc.).
Once behavior matches expectations, reuse the same role in real namespaces.
Periodic permission reviews
On a regular cadence (e.g. monthly/quarterly):
Export Roles/ClusterRoles and RoleBindings/ClusterRoleBindings.
Generate or review a simple “who can do what” report.
Pay special attention to:
Roles with wildcards (verbs: ["*"], resources: ["*"])
Roles bound in production namespaces
Bindings to users/groups that no longer exist
This keeps RBAC from drifting into a “nobody knows what’s allowed” state.
Troubleshooting RBAC "Forbidden" Errors
Forbidden errors are noisy but very informative if you read them carefully.
Start from the full error message
A typical error looks like:
Error from server (Forbidden): pods is forbidden: User "[email protected]" cannot list resource "pods" in API group "" in the namespace "production"
From this you already know:
Subject – [email protected]
Verb – list
Resource – pods
API group – "" (core)
Namespace – production
That’s your target: “Why can’t this subject list pods in production?”
Check the bindings for that subject
Look for RoleBindings/ClusterRoleBindings that mention this user, group, or service account:
Are they bound in the right namespace?
Are they bound to the right Role/ClusterRole?
Are they bound to a group that the user actually belongs to?
If the subject only has bindings in staging, they’ll naturally get Forbidden in production.
Inspect the referenced Role/ClusterRole
Open the Role/ClusterRole from the binding and check:
apiGroups – e.g. "" vs apps
resources – e.g. pods vs pods/log vs deployments
verbs – includes get, list, watch, etc. as needed
Common mistakes:
Using the wrong API group (deployments under "" instead of apps).
Forgetting subresources (pods/log, pods/exec).
Only granting get but expecting list as well.
Confirm the fix with auth can-i
After updating the role, confirm with the exact same parameters:
kubectl auth can-i list pods \ --as [email protected] \ -n production
If this returns yes but the user still gets Forbidden, check:
Are they using the same identity/context you tested?
Are there any proxies/webhooks that add extra checks beyond RBAC?
RBAC Security Best Practices and Common Vulnerabilities
Good RBAC hygiene is one of the highest-leverage security controls in Kubernetes.
Apply least privilege by default
Start with read-only roles where possible (get, list, watch).
Add write verbs (create, update, patch, delete) only when there is a clear, documented need.
Split roles by responsibility:
Developers: app resources in their namespaces.
SRE: infra resources + cluster-wide visibility.
Auditors: broad read-only access, no writes.
Use group-based bindings, not per-user bindings
Bind RBAC to groups from your identity provider (e.g. dev-team, sre-team):
Onboarding/offboarding is done via group membership.
RBAC YAML stays stable over time.
Access reviews happen at the “role → group” level instead of chasing individual emails.
Treat cluster-admin and wildcards as “break glass”
Reserve cluster-admin for a very small, audited group (e.g. platform team leads).
Avoid giving teams roles with resources: ["*"] and verbs: ["*"] unless they are tightly controlled.
Limit write access to RBAC resources themselves to central admins only.
Separate human and machine identities
Create dedicated service accounts for controllers, CI/CD pipelines, and operators.
Grant each service account only what it needs (namespaces, resources, verbs).
Don’t reuse the same service account across unrelated apps—it makes debugging and auditing much harder.
Review and clean up regularly
RBAC tends to accumulate “temporary” roles that never get removed.
Set up a recurring review to:
Remove unused roles and bindings.
Tighten overly broad roles based on real usage.
Document the standard roles and who should be using them.
Even a lightweight quarterly review dramatically reduces the risk of accidental over-privilege in your clusters.
Conclusion: Master Kubernetes Authorization
Kubernetes RBAC is complex but essential for secure multi-user clusters. Master the four resource types (Role, ClusterRole, RoleBinding, ClusterRoleBinding), understand the permission formula (Who + What + Resources), implement least privilege, and leverage tools like Atmosly to automate error-prone manual YAML creation.
Key Takeaways:
- Always use RBAC in production (enabled by default in modern Kubernetes)
- Never grant cluster-admin to regular users (extreme over-privilege)
- Use namespace-scoped Roles for tenant isolation (not ClusterRoles)
- Bind to Groups from OIDC, not individual Users (easier management)
- Protect RBAC resources themselves (prevent privilege escalation)
- Test permissions with kubectl auth can-i before granting widely
- Audit regularly users and permissions change, review quarterly
- Atmosly provides pre-configured roles and automatic subject binding
Ready to implement production-grade RBAC without manual YAML errors? Start your free Atmosly trial for automated RBAC management with built-in best practices and validation.