RBAC vs ABAC: A Complete Guide to Access Control Models
Authorization decides what an authenticated identity is allowed to do. Get it wrong and you either lock legitimate users out or — worse — let attackers in. This guide covers every major access control model, the policy engines that implement them, and practical patterns for APIs and Kubernetes.
The Access Control Landscape#
Every authorization system answers three questions: who is requesting access, what resource are they accessing, and under what conditions should access be granted? The models below differ in how they encode the answers.
Flexibility ──────────────►
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│ DAC │ │ MAC │ │ RBAC │ │ ReBAC│ │ ABAC │
└──────┘ └──────┘ └──────┘ └──────┘ └──────┘
Simple Complex
Discretionary Access Control (DAC)#
DAC lets the resource owner decide who can access their resource. Unix file permissions are the textbook example: the file owner sets read, write, and execute bits for owner, group, and others.
Strengths and Weaknesses#
- Simple to understand and implement.
- No central policy — every owner makes independent decisions.
- Vulnerable to privilege escalation because owners can delegate access freely.
DAC works for personal file systems but breaks down in multi-tenant systems where centralized policy enforcement is required.
Mandatory Access Control (MAC)#
MAC assigns security labels to both subjects and objects. Access is granted only when the subject's clearance dominates the object's classification. The policy is set by a central authority, not the resource owner.
Where MAC Appears#
- SELinux — Labels every process and file with a security context. Policies are compiled and enforced by the kernel.
- AppArmor — Confines programs to a limited set of resources using path-based profiles.
- Government classified systems — Documents labeled Confidential, Secret, Top Secret follow Bell-LaPadula (no read up, no write down).
MAC is overkill for most web applications but essential in defense and regulated environments.
Role-Based Access Control (RBAC)#
RBAC assigns permissions to roles, then assigns roles to users. A user's effective permissions are the union of all permissions granted by their roles.
Core Concepts#
User ──► Role ──► Permission ──► Resource + Action
│ │
│ ├── admin ──► [create, read, update, delete] on /projects
│ └── viewer ──► [read] on /projects
└── alice ──► [admin]
- Users — Identities (humans or service accounts).
- Roles — Named collections of permissions (admin, editor, viewer).
- Permissions — Actions on resources (read:document, write:document).
- Role hierarchy — Senior roles inherit permissions from junior roles (admin inherits viewer).
RBAC Strengths#
- Easy to audit: list a user's roles to see all their permissions.
- Aligns with organizational structure (departments, job titles).
- Well-supported by every identity provider (Okta, Auth0, Keycloak, AWS IAM).
RBAC Limitations#
- Role explosion — As the system grows, the number of roles multiplies. A SaaS product with 50 features and 4 access levels could need 200 roles.
- Coarse-grained — RBAC cannot natively express "editors can only edit their own documents" without per-resource roles or supplementary logic.
- Static — Decisions are based on role membership, not runtime context like time of day or device posture.
Attribute-Based Access Control (ABAC)#
ABAC evaluates policies against attributes of the subject, resource, action, and environment. It is the most flexible model.
Policy Example (Pseudocode)#
permit(
subject.department == "engineering"
AND resource.classification != "restricted"
AND action == "read"
AND environment.time.hour BETWEEN 9 AND 17
)
Attribute Categories#
| Category | Examples |
|---|---|
| Subject | department, clearance, tenure, IP address |
| Resource | owner, classification, creation date, tags |
| Action | read, write, delete, approve |
| Environment | time, location, device trust score, risk level |
ABAC Strengths#
- Fine-grained: policies can express any condition that can be evaluated from attributes.
- Fewer policies than RBAC for complex scenarios — one ABAC policy can replace dozens of roles.
- Dynamic: decisions incorporate runtime context.
ABAC Limitations#
- Policy complexity — Debugging "why was this request denied?" is harder when policies reference 10 attributes.
- Attribute provisioning — Every attribute must be reliably available at decision time. Missing attributes break policies.
- Performance — Complex attribute evaluation adds latency compared to a role-membership lookup.
Relationship-Based Access Control (ReBAC)#
ReBAC grants access based on the relationship between the subject and the resource. Google Zanzibar pioneered this model, and it powers Google Drive, Docs, and YouTube permissions.
How ReBAC Works#
(alice, owner, document:123)
(team:engineering, viewer, folder:designs)
(document:123, parent, folder:designs)
Access is determined by traversing a relationship graph. Alice can view document:123 because she is its owner. Any member of team:engineering can view it because the document is in folder:designs and the team has viewer access to that folder.
ReBAC Implementations#
- Google Zanzibar — The original paper. Not open source but widely influential.
- SpiceDB — Open-source Zanzibar-inspired system by AuthZed.
- OpenFGA — Open-source ReBAC engine by Okta/Auth0.
- Ory Keto — Part of the Ory ecosystem, implements Zanzibar-style checks.
ReBAC excels in collaborative applications (documents, folders, workspaces) where permissions are inherently relational.
RBAC vs. ABAC: When to Use Which#
| Factor | RBAC | ABAC |
|---|---|---|
| Team size | Small-medium | Medium-large |
| Permission granularity | Coarse | Fine |
| Policy count | Grows with roles | Grows with rules |
| Auditability | High (role listing) | Medium (policy tracing) |
| Runtime context | Not considered | Central to decisions |
| Implementation effort | Low | Medium-high |
Start with RBAC. When you hit role explosion or need context-aware decisions, layer ABAC on top. Many production systems use a hybrid: RBAC for broad access tiers and ABAC policies for fine-grained exceptions.
Policy Engines#
Open Policy Agent (OPA)#
OPA is a general-purpose policy engine that decouples authorization logic from application code. Policies are written in Rego, a declarative query language.
# Rego policy: allow engineers to read non-restricted docs
package authz
default allow = false
allow if {
input.subject.role == "engineer"
input.resource.classification != "restricted"
input.action == "read"
}
OPA is widely adopted for Kubernetes admission control, API gateways (Envoy, Kong), and microservice authorization.
Cedar#
Cedar is an open-source policy language created by AWS. It powers Amazon Verified Permissions and is designed for both RBAC and ABAC.
permit(
principal in Role::"editor",
action == Action::"update",
resource in Folder::"engineering"
) when {
resource.classification != "restricted"
};
Cedar's type system catches policy errors at authoring time, reducing runtime surprises.
Casbin#
Casbin is a lightweight authorization library supporting ACL, RBAC, ABAC, and custom models via a configuration-driven approach. It runs in Go, Java, Node.js, Python, and more. Casbin is best for embedding authorization directly into application code rather than running a standalone policy service.
Kubernetes RBAC#
Kubernetes implements RBAC through four API objects:
- Role — Grants permissions within a single namespace.
- ClusterRole — Grants permissions cluster-wide or across namespaces.
- RoleBinding — Binds a Role to subjects (users, groups, service accounts) in a namespace.
- ClusterRoleBinding — Binds a ClusterRole to subjects cluster-wide.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
Kubernetes RBAC Best Practices#
- Grant the minimum verbs needed. Avoid wildcard
*verbs. - Prefer namespace-scoped Roles over ClusterRoles.
- Audit bindings regularly with
kubectl auth can-i --list --as=system:serviceaccount:ns:sa. - Use aggregated ClusterRoles to compose permissions from smaller building blocks.
API Authorization Patterns#
Middleware Enforcement#
Place an authorization middleware in front of every API route. The middleware extracts the identity from the JWT, resolves roles or attributes, and evaluates the policy before the handler executes.
Per-Resource Checks#
For fine-grained authorization (e.g., "can this user edit this specific document?"), check permissions inside the handler after loading the resource. This pattern is necessary when the decision depends on resource attributes.
External Authorization Service#
Microservice architectures benefit from a dedicated authorization service. API gateways or sidecar proxies (Envoy ext_authz) call the service on every request, centralizing policy evaluation while keeping application code clean.
Client ──► API Gateway ──► AuthZ Service (OPA / Cedar)
│ │
▼ ▼
App Service Policy Decision
Least Privilege#
The principle of least privilege underpins every access control model: grant only the permissions a subject needs to perform their current task, nothing more.
Implementing Least Privilege#
- Default deny — Start with no permissions. Explicitly grant access.
- Time-bound access — Use just-in-time (JIT) elevation for privileged operations. Revoke automatically after a window.
- Scope narrowly — Prefer resource-specific permissions over wildcards.
- Review regularly — Audit role assignments quarterly. Remove unused roles.
- Separate duties — Require different identities for deploying code and approving deployments.
Key Takeaways#
- DAC and MAC are foundational models but rarely used directly in modern web applications.
- RBAC is the right starting point for most systems. Layer ABAC or ReBAC when role explosion or relationship-based access becomes necessary.
- Policy engines (OPA, Cedar, Casbin) externalize authorization logic, making it testable, auditable, and decoupled from application code.
- Kubernetes RBAC is its own domain — learn the four API objects and favor namespace-scoped Roles.
- API authorization works best when centralized in middleware or an external service, not scattered across handlers.
- Least privilege is not a model — it is a principle that applies to every model.
Start simple, measure where your current model breaks, and evolve. The goal is not the most sophisticated system — it is the one that correctly enforces your security requirements without drowning your team in policy management.
Article #302 on Codelit — Keep building, keep shipping.
Try it on Codelit
GitHub Integration
Paste any repo URL to generate an interactive architecture diagram from real code
Related articles
Try these templates
Build this architecture
Generate an interactive architecture for RBAC vs ABAC in seconds.
Try it in Codelit →
Comments