open atlas
↑ Back to track
Security Foundations SECF · 05 · 02

ABAC and ReBAC

RBAC asks who you are; ABAC adds context; ReBAC asks how you are connected. Google's Zanzibar made relationship checks fast and consistent at billions of objects. This is when roles run out of road and what replaces them.

SECF Middle ◷ 15 min
Level
FoundationsJuniorMiddleSenior

Product ships a “share this folder with a teammate” button. With RBAC you reach for a role — but which one? The folder’s owner isn’t an editor globally, they’re an editor of this folder. Their teammate inherits access through the share. The folder lives in a project they were added to last week. By the time you model “can Bob view document 7?” as a set of roles, you have folder:42:editor, project:9:viewer, and a combinatorial swamp of synthetic roles that grows with every share. The role didn’t run out of permissions — it ran out of subject. The answer isn’t a bigger role table; it’s a different question: not “what role does Bob have,” but “is there a path from Bob to this document that grants view?”

By the end of this lesson you’ll know when roles stop scaling, how ABAC and ReBAC reframe the authorization question, and why Google built Zanzibar to answer “can Bob view this?” in single-digit milliseconds across billions of objects.

Where RBAC runs out of road

RBAC (role-based access control) binds permissions to roles, and roles to users. It is the right default for most systems: it is auditable, it maps to org structure, and “grant the support role” is a sentence a compliance officer understands. It breaks at a specific seam — per-resource, relationship-shaped permission. The instant access depends not on who you are but on which specific object you stand in a relationship to, roles start multiplying.

The symptom has a name: role explosion. A document-sharing app that wants “owner can edit, anyone they share with can comment, members of the parent folder can view” cannot express that with global roles. So teams synthesize per-object roles — doc:7:owner, doc:7:commenter, folder:42:viewer — and the role table grows linearly with the number of objects times the number of access levels. You are now using the role system as a clumsy join table, and you have lost the one thing RBAC was good at: a small, human-readable set of roles.

Two models answer the seam differently. ABAC keeps asking about the subject and the environment but enriches the question with attributes. ReBAC throws out roles-as-the-unit entirely and makes the relationship between subject and object the thing you check.

ABAC: authorize on attributes, not labels

ABAC (attribute-based access control) evaluates a policy at request time against attributes of four things: the subject (department, clearance, employment status), the resource (owner, classification, region), the action (read, delete, export), and the environment (time of day, source IP, device posture). A rule reads like a predicate:

Permit read if subject.department == resource.department and subject.clearance >= resource.classification and environment.time is within business hours.

This is enormously expressive. One policy covers every document in a department without enumerating a single role, and it captures context roles can’t — “deny exports from outside the corporate network,” “allow only during the on-call window.” It is the natural fit for contextual and regulatory rules: data residency, clearance levels, ABAC’s home turf in government and healthcare.

The cost is two-fold and real. First, reasoning: with enough attributes and rules, “who can actually access this document, and why?” becomes a question you answer by running the policy engine, not by reading a table — auditability drops. Second, the data plane: every attribute the policy names must be present, fresh, and trustworthy at decision time. If subject.clearance is stale because HR’s sync lagged, the policy is correct and the decision is wrong. ABAC moves the hard problem from “managing roles” to “managing attributes,” and attributes are messier.

Why this works

Why isn’t ABAC just “RBAC with more fields”? Because a role is a named bundle granted ahead of time — you assign it, then check membership. An attribute policy is evaluated fresh on every request against live data. That difference is the whole tradeoff: roles trade expressiveness for a static, auditable assignment you can list; attributes trade that static picture for context-awareness you can only get by computing it. The senior tell is which question you can answer offline. “Who has the admin role?” — a query. “Who can read this document right now?” under ABAC — a simulation.

ReBAC: the relationship is the permission

ReBAC (relationship-based access control) models authorization as a graph. Subjects, objects, and other objects are nodes; tuples like (document:7, viewer, user:bob) or (document:7, parent, folder:42) are edges. A permission check becomes a graph reachability question: starting from user:bob, is there a path to document:7 along edges that grant view? Crucially, relationships compose — folder:42 viewer can be inherited by every document whose parent is folder:42, so one edge change re-grants thousands of objects without touching them individually.

This is exactly the shape the sharing app needed. “Owner can edit, sharee can comment, parent-folder member can view” is three edge types and an inheritance rule, not a role table that grows with your object count. ReBAC is the model behind Google Drive sharing, GitHub repo collaborators, and Notion’s nested-page permissions — anywhere access flows through connections between users and resources.

Zanzibar: making the graph walk fast and consistent

A graph check sounds slow, and naively it is — a folder shared with 10,000 users, nested five levels deep, could fan out into a huge traversal on the hot path of every page load. Google Zanzibar is the system (2019 paper) that made ReBAC viable at planet scale: it powers authorization for Drive, YouTube, Calendar, Cloud, and more, storing billions of relationship tuples and serving millions of checks per second with 95th-percentile latency under 10 ms and over 99.999% availability.

Two ideas carry it. First, Zookies — a consistency token tied to Google’s Spanner TrueTime clock. The hard correctness bug in distributed authz is the “new enemy” problem: you remove someone from a folder, then add a sensitive file; if the permission check reads a stale snapshot from before the removal, the ex-member sees the new file. A Zookie pins each check to a snapshot at-or-after the relevant ACL change, so a check never decides on data older than the change that should have blocked it. Second, aggressive caching and denormalization of subgraphs so a deeply nested or widely shared object doesn’t re-walk the whole tree every request. The lesson Zanzibar generalized: ReBAC’s expressiveness is only usable if the check is both fast and causally consistent — getting one without the other ships either a slow product or a security bug. This is why the open-source descendants (SpiceDB, Keto/OpenFGA, AuthZed) all copy the tuple-plus-consistency-token shape rather than just “store edges in a graph DB.”

ModelCore questionShines atMain cost / failure mode
RBACWhat role does this user have?Org-shaped, auditable, small role setsRole explosion on per-object sharing
ABACDo the attributes satisfy the policy now?Context & regulatory rules (residency, clearance, time)Stale/missing attributes; “who can access?” is a simulation
ReBACIs there a path from subject to object?Sharing, nesting, inheritance (Drive/GitHub-style)Traversal cost + the “new enemy” consistency bug
ZanzibarReBAC, but fast & causally consistentPlanet-scale: <10 ms p95, millions of checks/sOperational weight; you run a separate authz service

How a senior actually chooses

These models are not a ladder where ReBAC is “best.” They are answers to different questions, and the senior move is to match the model to the shape of your permissions, then resist over-engineering. Most products are RBAC plus a few ownership checks, and should stay there — WHERE owner_id = ? is ReBAC-of-one and needs no Zanzibar. Reach for ABAC when access turns on context and compliance the role can’t see (region, clearance, time, device). Reach for ReBAC when access flows through relationships — sharing, groups, nesting, inheritance — and the role table is becoming a join table. And the three compose: real systems are usually RBAC for coarse org roles, ABAC for regulatory guardrails, and ReBAC for the user-facing sharing graph. The wrong answer is to deploy a Zanzibar clone for an app that has three roles and no sharing.

Pick the best fit

Your app is adding Google-Drive-style sharing: users share documents with individuals and groups, documents live in nested folders, and access is inherited down the tree. Roles are exploding into `doc:7:viewer`-style synthetic roles. Pick the model that fits the permission shape.

Quiz

What concrete problem do Zanzibar's 'Zookie' consistency tokens solve?

Quiz

A bank needs: 'a teller may view an account only if it's in their branch, only during business hours, and only from a corporate IP.' Which model fits most naturally, and why?

Order the steps

Order these by how a request flows through a ReBAC check for 'can Bob view document:7?', from the input to the decision:

  1. 1 Receive the check: subject user:bob, permission view, object document:7
  2. 2 Pin the read to a snapshot at-or-after the latest relevant ACL change (Zookie)
  3. 3 Walk relationship tuples for a path: bob → group/project → folder → document
  4. 4 Apply inheritance rules (folder viewer ⇒ child-document viewer)
  5. 5 Return allow if a granting path exists, else deny
Recall before you leave
  1. 01
    Explain role explosion: what is the seam where RBAC breaks, and how do ABAC and ReBAC each answer it?
  2. 02
    What did Google Zanzibar add on top of plain ReBAC, and why was each piece necessary?
Recap

RBAC, ABAC, and ReBAC are three answers to three different questions, not a quality ladder. RBAC (“what role does this user have?”) is the right default — small, auditable, org-shaped — until access becomes per-object and relationship-shaped, where it suffers role explosion: synthetic per-object roles that grow with objects × access levels and turn the role table into a join table. ABAC (“do these attributes satisfy the policy right now?”) reframes authorization as a predicate over subject, resource, action, and environment attributes, ideal for contextual and regulatory rules but paying in attribute-freshness and lost offline auditability. ReBAC (“is there a path from subject to object?”) makes the relationship the unit, modeling access as a graph of tuples with inheritance — the natural fit for sharing, groups, and nesting. Google’s Zanzibar made ReBAC work at scale by adding Zookie consistency tokens (defeating the “new enemy” stale-read bug) and heavy caching, hitting sub-10 ms p95 across billions of tuples. The senior reflex: match the model to the permission shape, compose them (RBAC for org roles, ABAC for guardrails, ReBAC for the sharing graph), and don’t deploy planet-scale machinery for an app with three roles and no sharing.

Practice

Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.

recallapplystretch0 of 6 done
Connected lessons

Something unclear?

Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.

shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.