Where tonight sits
Session 1 ended with three numbers and a name. Tonight turns the first of those numbers into something you can act on, because the biggest single move in the whole ladder is not a masking policy or a row filter but a role list that reflects the jobs people actually do. Session 3 is least privilege that survives contact with a working week. Session 4 is classification and what a masked column commits you to. Session 5 is evidence an auditor accepts. Session 6 is the operating model. The example stays saltbox.customers at Saltbox, a consumer lending startup: ten columns, three regions, five jobs.
★ What you walk out with tonight. A straight answer to "should we move to attribute-based access", which is usually neither yes nor no but "you already have, in the worst possible shape". The mechanism that produces role sprawl, stated plainly enough that you can point at which step your own organisation is on. And the counted result that splitting one shared role five ways moves leaks from 70 to 22 and standing privileges from 17 to 1, which is a better return than any policy you will write afterwards.
LiveThe question underneath both models3 min▶
Strip the vocabulary away and every access system answers one question at the moment somebody runs a query: given who is asking, what they are asking for, and what they intend to do with it, is the answer yes? The models differ only in how much of that question they are willing to look at.
- Look at one thing. Read the person's role, check whether that role holds the privilege, answer. Fast, cheap, and it forces every distinction you care about to become a separate role.
- Look at everything. Read attributes of the person, the object, the operation and sometimes the surrounding conditions, and evaluate a rule over all of them. Expressive, and it moves the difficulty somewhere less visible.
The reason this matters to an approver rather than an engineer is that the model decides what a request even looks like. Under the first, every request is "add me to a role", and the role list absorbs every distinction anybody ever needed. Under the second, requests become "my attributes are wrong", which is a very different conversation and often a shorter one.
Self-studyThe words people use interchangeably and should not4 min▶
- Role - a named bundle of permissions that people are put into. In the strict model it is the only thing the decision looks at.
- Attribute - a fact about the person, the data, the action or the moment. Region, tenure, contract status, sensitivity class, whether the operation is a read or an export.
- Policy - a rule that combines attributes and returns allowed or denied. Written once, evaluated on every request, which is what lets its answer change without anybody editing anything.
- Group - usually an identity-provider construct, often mapped one to one onto a role. Two lists that must agree, held by two teams, which is a durable source of drift.
- Entitlement - what an auditor calls the end state: this named human can read this column. It is what gets certified, and it is downstream of all of the above.
- Sprawl - not a technical failure. A list that grew one reasonable exception at a time until nobody could hold it in their head or safely remove anything from it.
Two models, one of them older than your warehouse
11 min liveRole-based access predates every warehouse currently in use and it survives because it is legible: you can print the list. Attribute-based access is defined by NIST in SP 800-162 and it survives because reality is full of rules that a list cannot hold. Most estates run a blend without ever having chosen one, which is fine, as long as you know which half is carrying which decision.
LiveRBAC: one attribute, assigned in advance3 min▶
Role-based access control works on the single attribute of role, and that role is usually assigned from a fairly static organizational position. Somebody joins the analytics team, they get the analytics role, and the decision at query time is a lookup: does this role hold this privilege on this object.
The strength is not performance, it is legibility. You can print the whole list. You can walk into a review with it. You can tell a person exactly what they hold and they can check it. Every access model that replaced it has struggled to reproduce that one property, and it is the property an auditor cares about most.
The weakness is that every distinction has to become a role. The moment access depends on something that varies within a job - which region, how long they have been here, whether they are staff or contract - the list starts multiplying, because a list is the only place the model can put that information.
LiveABAC: attributes evaluated at the moment of the request4 min▶
NIST SP 800-162 defines attribute-based access control as determining authorization by evaluating attributes of the subject, attributes of the object, the requested operations and, in some cases, environment conditions against a policy. Four groups, one Boolean rule set, one answer.
The consequence people underestimate is the second half: a decision can change between requests as attribute values change. Nobody has to edit a role, run a script or approve anything. A contractor's end date passes and the same query that worked yesterday returns nothing today, because the rule was written against the attribute rather than against a membership somebody has to remember to remove.
Saltbox needed EU rows restricted to staff whose own region was EU. Under a role list that is three roles, kept in step by hand with whatever the HR system says, and it drifted within a quarter because two people moved country and nobody told the platform team. Written as a rule against the region attribute, the same requirement is one line and it corrects itself the day the HR record changes.
That self-correcting property is the honest case for attributes, and it is a strong one. It only holds while the attribute is accurate, which is why the real prerequisite is not a policy engine but a system of record that people trust.
LiveWhy attribute-based is not automatically the upgrade3 min▶
The pitch is that attributes replace a sprawling role list with a handful of elegant rules. What actually happens is a transfer: complexity leaves a list you can enumerate and arrives in a policy set you have to reason about. Both are complexity. Only one of them can be printed and read aloud in a review.
- A role list fails visibly. Three hundred and forty rows is obviously bad. Everybody in the room agrees on the diagnosis even if nobody agrees on the fix.
- A policy set fails quietly. Twelve rules, each defensible, whose interaction nobody has traced. It looks tidy right up until somebody asks which rule granted a particular read, and the honest answer takes an afternoon.
- Attributes have owners you do not control. The region, the tenure and the contract flag live in HR systems. Access becomes only as correct as a field somebody else maintains for a different purpose.
- The failure mode is inverted. A missing role blocks somebody and they complain within the hour. A stale attribute silently grants, and nobody complains at all.
None of that is an argument for staying on roles. It is an argument for choosing where you want your difficulty to live, and for being able to say out loud which control is holding which part of the decision.
LiveThe middle ground nearly everybody actually runs4 min▶
Warehouses in practice run a split, and it is a good split even though most teams arrived at it by accident rather than design. Roles carry the coarse decision, which is whether a job touches this table at all. Row and column policies carry the attribute-shaped part, which is which rows and which values that job is allowed to resolve.
| The decision | Where it belongs | Why |
|---|---|---|
| Does this job use the customers table | A role | Changes rarely, needs to be listable, is what a reviewer certifies |
| Which regions can this person resolve | A row policy on an attribute | Varies within the job and corrects itself when the attribute changes |
| Does this person see the real phone number | A column policy with a named exception | Depends on sensitivity class, and the exception has to be explainable |
| Is this person still with us | An attribute, upstream | Nobody should be revoking access by hand when a leaver record already exists |
The test for whether your split is right is simple. Point at any rule and ask which mechanism enforces it. If the answer is "both, sort of", you have a rule implemented twice, and the two copies will disagree at the worst possible moment.
Self-studyWhere attributes actually come from, and what that costs4 min▶
An attribute model is a data quality commitment wearing a security badge. Before promising a policy that reads region and contract status, find out three things about each attribute you intend to rely on.
- Who owns it, by name. Not a system, a person. If the region field is maintained by whoever last did the onboarding paperwork, the policy is only as good as that afternoon.
- How fast it updates. A leaver flag that lands in the warehouse the following Monday leaves a four-day window where a policy reads true and should read false. That window is the actual control gap, and it is worth writing down as a number.
- What happens when it is missing. Null is the case nobody specifies and the case that decides your exposure. A rule that grants when the attribute is absent will grant to every record created before the field existed.
One further trap: attributes read at query time can be gamed by whoever controls them. If a person can edit their own profile field, that field cannot be the thing standing between them and the national ID column. Attributes used for access decisions need the same change control as the grants they replaced.
Why sprawl happens, and what it costs
10 min liveNobody sets out to build 340 roles. The list is the accumulated residue of hundreds of small, correct decisions made under time pressure by people trying to help. Understanding the loop matters more than deploring the outcome, because the loop is what you can actually interrupt.
LiveThe mechanism, in four steps3 min▶
Sprawl is not carelessness. It is what happens when three ordinary conditions hold at once, and they hold almost everywhere.
- Every exception becomes a role. There is nowhere else to put it. Somebody needs one extra column for one project, and the mechanism available for expressing that is a new role, so a new role is created.
- No role is ever deleted. Not because anybody defends it, but because nobody can say who would break. Deletion carries all the downside and none of the credit, so the rational individual choice is always to leave it.
- The fastest path to unblocking somebody is a new grant. Understanding whether an existing role already covers the need takes an hour. Creating something new takes four minutes and the person is unblocked before the standup ends.
Notice that nobody in that loop is behaving badly. The platform engineer helped, the manager approved, the analyst got back to work. The cost is entirely deferred and lands on a person who was not in the room, usually the one preparing next year's access review.
Live340 roles and one everybody uses3 min▶
The pattern is remarkably consistent across organisations. A long tail of roles with one or two members each, created for a project that ended, and one broad role that half the company holds. The tail is embarrassing. The broad role is the actual problem.
The shared role wins because it is the only one anybody trusts to work. A new joiner needs access on their first morning. Somebody could work out which of the 340 fits, or they could add them to the one that definitely covers everything, and the second option ships. Six months later the shared role is the de facto standard and the 340 are decoration.
The tell is the onboarding instruction. Ask what a new analyst is added to on day one. If the answer is one role, and that role is not job-specific, you have found the thing carrying almost all of your exposure, regardless of how disciplined the rest of the list looks.
At Saltbox this is exactly the opening state: one shared analyst role that everybody in data holds, scoring 109 leaks, 0 over-blocks and 30 standing privileges against 150 concrete access requests. Zero over-blocks is not a compliment. It is the signature of a role that grants everything to everybody, and it is why nobody ever complained about it.
LiveWhat the role split is worth, counted4 min▶
Saltbox's policy ladder is scored the same way at every step, against a written design over 150 requests. Two of those steps are masking policies, which is where attention usually goes. One of them is the role split, which is where the value actually is.
| Policies on | Leaks | Over-blocks | Standing privileges |
|---|---|---|---|
| One shared analyst role | 109 | 0 | 30 |
| Plus mask national_id for everybody | 94 | 0 | 25 |
| Plus mask email and phone, except support | 70 | 0 | 17 |
| Plus split the shared role five ways | 22 | 0 | 1 |
Read the last row against the one above it. Two masking policies, both of them real work with a review and a deployment, moved leaks from 109 to 70. Splitting one shared role into the five jobs that actually exist moved leaks from 70 to 22 and standing privileges from 17 to 1, in a single step.
That is the highest-value control available, and it is the one that reads on a plan as administration rather than security. Nobody presents a role-modelling workstream to a board. It is worth learning to, because the alternative is spending the year on policies that are individually correct and collectively worth a third as much.
LiveThe rules that are attribute-shaped and stored as roles3 min▶
Before any migration, there is a cheap diagnostic. Go down your role list and look for families: three roles that differ only by region, four that differ only by seniority, two that differ only by whether somebody is staff or contract. Each family is one attribute-shaped rule being emulated by a list of values.
Those families are where a policy genuinely helps, because they are the rules that go stale. A role per region has to be maintained by hand every time somebody relocates. A rule against the region attribute maintains itself, and the two people who moved country stop being an incident waiting to be discovered.
The second one is longer and it is the short version of the work. A role you can define in those terms is a role somebody can safely delete when the job disappears, which is the property the 340 are missing.
Self-studyHow a role list stops growing4 min▶
Cleaning the list once achieves nothing durable, because the loop that produced it is untouched. Three interruptions, in rough order of how much they cost you.
- Give an exception somewhere to live that is not a role. Time-bound elevation with a recorded reason handles the genuine one-off, and it expires. That is session 3, and it is the single change that stops the tail growing.
- Make deletion safe rather than brave. Nobody removes a role because nobody knows who breaks. Query history against grants turns that into a fact, and the answer is usually that the role has not been used in eleven months.
- Require a job sentence before a role exists. One sentence saying what the role is for, and if two roles share a sentence they are one role. It is a small piece of friction placed exactly where the loop starts.
There is also a sequencing point worth holding on to. Role modelling before masking gives you a smaller, clearer surface to write policies against. Masking before role modelling means writing exception lists for roles you are about to delete, which is a fortnight of work you will discard.
Count your roles, and find the one that matters
★ 16 min · everyone buildsYou do not need query access for any of this. You need one number from the platform team and a willingness to ask an uncomfortable question about the biggest role. Work down the steps and write the answers where somebody else can read them.
Count your roles, and count the humans in each. Two numbers, not a list. Most leaders can guess the first within an order of magnitude and are wrong about the second by a factor of five, because a role with 40 members reads as one line on a report.
Find the role with the most members, and ask what it is for. Out loud, to the person who administers it. If the answer contains the word "general", or takes more than one sentence, you have found the role carrying most of your exposure. Write the sentence down as it was actually said.
Find the roles with exactly one member. For each, ask whether that is a job or an exception. A job with one holder is fine and will have a second holder eventually. An exception is a grant that outlived its project and is now indistinguishable from policy.
Look for families. Scan for roles that differ only by region, only by seniority, only by contract status. Each family is one attribute-shaped rule emulated as one role per value. Count the families and count the roles inside them, because that count is the size of the prize from a policy.
Write the five jobs that actually exist. Not the roles you have, the jobs people do. One sentence each. Saltbox's are EU analyst, support agent, data scientist, finance analyst and APAC contractor. If two of your sentences match, that is one job and you have just deleted a role for free.
Name what stops you deleting anything. Usually it is one of three things: nobody knows who uses the role, nobody owns the list, or the last deletion broke a dashboard and everybody remembers. Naming which one is yours decides what session 3 is actually about for you.
Take the count, not the export. Asking for a full grant dump produces a spreadsheet nobody reads and a two-week delay. Asking for "how many roles, and how many people in the largest five" produces an answer this afternoon, and it is enough to decide what to do.
Before session 3
30 min- Write the job sentence for your five most common jobs, one line each, and check that no two are the same. This is the input to everything in sessions 3 to 6.
- Get the member count for your ten largest roles. Bring the top one to session 3 by name, because least privilege is a conversation about that role and no other.
- List the role families you found and, for each, name the attribute that would replace it and the system that owns that attribute.
- For your largest role, ask one person who holds it what they actually use it for. Compare their answer with the role's stated purpose and note the gap.
- Find out who is allowed to create a new role at your company, and how long it takes them. That number is the rate at which your list grows.
Three questions
What distinguishes attribute-based access control from role-based, as NIST SP 800-162 puts it?
Role-based access works on the single attribute of role, usually assigned from a static organizational position. The four attribute groups and the Boolean rule set are the definition, and the moving decision is the consequence that matters most in practice.
An estate has 340 roles and one broad role that everybody in data holds. Which is the more urgent problem?
The tail is embarrassing and mostly inert. The shared role is what new joiners are added to on their first morning, which is why it accumulates every privilege anybody has ever needed.
Two masking policies took Saltbox from 109 leaks to 70. What did splitting the shared role five ways do?
One step of role modelling outperformed both masking policies combined, on both counters. It is the highest-value control on the ladder and the one that reads as administration rather than security.