02. Authorization, RBAC, ABAC, and Policies¶
⏱️ Estimated time: 32 min | Level: intermediate
ELI5 callback: In the apartment building, the front door checks identity, the elevator key limits movement, the wall keeps tenants apart, the audit records rule-following, and the safe protects valuables.
1) What authorization really decides¶
Authorization starts only after identity is established. It answers: what may this actor do here?
See. Teams often mix the identity question with the permission question. That confusion creates hidden bugs.
So what to do? Write permissions as verbs on resources, not as vague admin feelings.
Good authorization models care about tenant, action, object, context, and explicit deny rules.
Now watch. A clean decision engine prevents permission logic from leaking into every handler.
- The front door reminds you that identity must be proven before permission is evaluated.
- The elevator key reminds you that access decisions are scoped and deliberate.
- The wall reminds you that tenant boundaries sit beside permission checks, not underneath them.
- The audit reminds you that every important decision needs evidence later.
-
The safe reminds you that even approved access should protect sensitive data strongly.
-
Model actions clearly: read invoice, approve payout, export tenant data, or rotate keys.
- Name the resource owner because cross-tenant access is often the real bug.
- Decide whether missing policy means deny by default or a fallback allow path.
- Document which service is authoritative for permission facts.
2) RBAC gives speed, but also limits¶
Role-based access control maps users to roles and roles to permissions. It is easy to explain and easy to ship.
That simplicity helps early products. It also hides trouble when exceptions multiply.
Simple, no? Sales rep, finance admin, tenant owner, and support engineer feel obvious at first.
But role explosion appears when every team wants a slightly different exception.
See. RBAC is strong for common paths, weak for rich context.
- Use RBAC for stable job functions and broad product areas.
- Keep role names business-readable so audits and support stay understandable.
- Avoid special one-off roles for every customer complaint.
- Group permissions into products or domains before attaching them to roles.
- Review dormant roles because old roles quietly become permanent backdoors.
┌──────────┐ ┌──────────┐ ┌────────────┐ │ Principal│───▶│ Role │───▶│ Permission │ └──────────┘ └──────────┘ └────────────┘ │ │ └──────── tenant context ─────────┘
3) ABAC and policy engines add context¶
Attribute-based access control evaluates facts about the actor, resource, action, and environment.
That means department, region, risk score, tenant plan, record owner, and time window can all matter.
Now watch. ABAC scales nuance better than RBAC, but debugging gets harder.
Policy-as-code tools like OPA help because they centralize logic and make review possible.
A policy should read like a decision contract, not like a mystery novel.
- Pass a small, trusted input document into the engine instead of letting policies fetch everything.
- Treat missing attributes carefully because unknown data can become accidental allow logic.
- Separate policy data refresh from request-time evaluation to control latency.
- Version policies so rollbacks stay possible during incidents.
- Write deny rules intentionally when legal or tenant boundaries require hard stops.
-
Test policy bundles with realistic tenant and support scenarios.
-
OPA can run as a sidecar, library, or central decision service.
- Choose the placement based on latency, blast radius, and cache needs.
- Keep a human-readable explanation path for rejected requests.
4) Least privilege is a design habit¶
Least privilege means granting only the smallest access needed for the task at hand.
See. This is not only a security slogan. It reduces bug blast radius too.
Support access, break-glass access, and background jobs need stricter thought than happy-path user clicks.
Temporary elevation should expire automatically. Humans forget. Systems should not.
So what to do? Make privileged paths scarce, visible, and reviewable.
- Default new roles and new services to deny until permissions are explicitly added.
- Separate viewing data from changing data and from exporting data.
- Give support teams scoped impersonation with banners, approvals, and short duration.
- Restrict administrative APIs behind extra controls even if the UI already hides them.
- Review machine permissions because service accounts often grow silently over time.
- Log both the decision result and the policy version used for that decision.
5) Common traps and rollout advice¶
Authorization bugs often come from scattered checks, inconsistent defaults, and stale cached claims.
A route protected in the UI but open in the API is still open. See.
Now watch. Tenant switching can turn a harmless cached permission into a data leak.
Policy rollout should support dry-run mode so you can compare expected and actual decisions safely.
The boring practice is the winning practice: central rules, strong tests, and deny by default.
- Check list endpoints, search endpoints, and export endpoints separately.
- Review bulk actions because one approval may touch thousands of rows.
- Make policy test cases part of code review, not an afterthought.
- Store tenant context explicitly instead of guessing it from user profile defaults.
- Capture why access was denied so support and product teams can explain outcomes.
- Run permission diff reports when roles or policies change.
Policy bundles should roll forward and backward cleanly.
Deny by default is kind to future you.
ABAC without clear input contracts becomes folklore engineering.
Decision logs are useful only when they capture policy version and input shape.
Role cleanup should be scheduled work, not emergency work.
Explicit tenant context beats magical inference every time.
Support tooling needs the same policy rigor as customer-facing flows.
Permission checks belong near the resource boundary, not only in the front end.
A single hidden allow path can defeat an otherwise elegant model.
Policy readability matters because humans maintain the system after launch.
Where this lives in the wild¶
- Admin consoles controlling billing, user management, and tenant settings.
- Document systems that allow sharing by team, region, or data classification.
- Cloud platforms enforcing project, namespace, and environment permissions.
- Support tools that need temporary impersonation or case-scoped access.
- Financial systems separating creator, approver, and exporter privileges.
Pause and recall¶
- Why does RBAC become painful when exception cases grow fast?
- What extra context can ABAC evaluate that RBAC usually cannot?
- Why should policy input be small and trusted?
- How does least privilege help even when no attacker is present?
Interview Q&A¶
Q: When is RBAC a good first choice? A: RBAC works well when job functions are stable, broad permissions are enough, and teams need understandable audits. Common wrong answer to avoid: "RBAC is outdated, so skip it completely."
Q: Why do teams adopt ABAC or policy-as-code? A: They need context-aware decisions using tenant, resource, time, ownership, or risk attributes without exploding role counts. Common wrong answer to avoid: "ABAC is just RBAC with nicer naming."
Q: What is a good default when policy data is missing? A: Default to deny or fail closed for sensitive paths, then fix the missing attribute source deliberately. Common wrong answer to avoid: "If data is missing, just allow and log it."
Q: Why log policy version with decisions? A: Because incidents and audits need to know which exact rule set produced the outcome. Common wrong answer to avoid: "The current policy in git is enough evidence."
Apply now (5 min)¶
List one sensitive action in your product, like export tenant data.
Write the principal, action, resource, and tenant context needed for the decision.
Then express the rule once in plain English and once as policy input fields.
If your rule depends on hidden UI state, redesign it now.
Bridge. Permissions set. But data must be protected even if access is breached. → 03