Rather than narrow a three-year-old wildcard grant, a team adds a deny rule over its riskiest names — what does that actually buy?
answer
- reach reduced, width unchanged
- a blocklist fails open
- tomorrow's name is not listed
- each denial names a consumer
- an admission with a review date
basics
~20 sFencing removes the worst outcomes from a grant's reach without anyone knowing what the grant is used for — and it fails open: a name created on that branch tomorrow matches the allow and no deny, so it is readable.
solid answer
~50 sFencing the names you could not afford to lose buys blast-radius reduction you can ship today, which is exactly what narrowing cannot give you: narrowing needs to know every consumer, fencing needs only to know the crown jewels. It doubles as a probe — each denial that fires hands you a consumer, a name and usually an owner that nobody could produce by asking. The cost is that the grant is still wide. You are maintaining a blocklist now, and a blocklist fails open: a name filed on that branch next week matches the allow and no deny. It also depends on how your rules combine — some systems apply denies last, others stop at the first match — so know which you have before claiming the fence holds. Treat it as debt: give the deny rule a reason, a review date and a ticket for the real derivation.
code
yaml · 16 linesprecedence: deny-overrides # this system evaluates every match; others stop at the first
allow:
- grantedTo: internal-admin-tool
scope: "billing/*" # untouched - still open-ended
rights: [read]
deny:
- appliesTo: internal-admin-tool
scope:
- billing/payout-keys
- billing/statement-signer
reason: "grant unattributable; riskiest names fenced"
reviewBy: "2026-12-19"
# billing/refund-keys, filed next week, matches the allow and no deny -> readablego deeper
Learn the two shapes first. An allow list names what may be read; a deny list carves exceptions out of something wider. They behave very differently the moment a new name appears.
Explain the failure direction. An allow list refuses anything it does not name; a deny list permits anything it does not name, so a branch that keeps growing quietly outgrows its fence.
Show the operational use: fence the names whose loss you could not accept, alert on every denial, and read each denial as a lead that names a consumer nobody could name for you.
Decide when freezing reach is worth more than reducing it, what a fence costs in review credibility, and how you stop a temporary deny rule becoming the estate's standing answer to grants nobody can attribute.
## What fencing buys that narrowing cannot Narrowing a grant is an inventory problem. To replace `branch/*` with a list, you must know every consumer of every name under it, and the three-year-old grant you are looking at is exactly the case where nobody does. Fencing inverts the question: instead of "what does this identity legitimately need?", which nobody can answer, you ask "which names could we not afford this identity to read?", which the data owner usually can answer in an afternoon. That asymmetry is the whole value. The fence: - **reduces reach today**, without waiting on an inventory that may never be completed; - **needs no consumer list**, so it is not blocked by the missing owner; - **is reversible per name** — lifting one entry is a small, explainable change; - **leaves the legitimate traffic untouched**, because the names being fenced are, by hypothesis, not the ones the tool uses daily. ## The deny rule as a probe The second use is diagnostic, and it is the one teams under-use. A grant nobody can attribute is an unknown; a denial is an event with a timestamp, an identity, a name and, once you chase it, a team. Alert on every denial of that fence and treat each one as an attribution lead rather than a fault. Within a cycle or two you typically learn more about who exercises that right than three rounds of asking would have produced — because the thing exercising it is often a scheduled job whose author left, and jobs do not answer questionnaires. This is why "the fence broke something" is a success condition with a rollback attached, not a reason to abandon the approach. The correct response to a legitimate denial is to lift that one name, record who asked and why, and note that one previously invisible consumer is now documented. ## What it admits A fence is also a statement about the team that wrote it: **the grant's consumers were unknown, so its reach was frozen rather than reduced.** That is an honest position under time pressure, and it is a bad permanent one, because the rule now looks constrained to any later reviewer. The grant still covers the whole branch; what changed is that two names are carved out. If the deny rule carries no reason, no review date and no ticket, the next reviewer reads a tidy pair of rules and moves on. One more mechanical caveat: how rules combine differs between systems. Some evaluate every matching rule and let a deny override; some stop at the first match and never reach the deny at all. A fence written for one model and deployed on the other is decoration. ## The direction each list fails in | | allow list (narrowing) | deny list (fencing) | |---|---|---| | a new name appears on the branch | refused until someone grants it | readable immediately | | what you must know to write it | every consumer and every path | the names you could not afford to lose | | how it fails | availability — something legitimate is refused | confidentiality — something sensitive is readable | | what keeps it current | a change per new consumer, which someone will ask for | a change per new sensitive name, which nobody triggers | The last row is the one that decides the long game. An allow list is maintained by the people it inconveniences, so it stays roughly current. A deny list is maintained by nobody, because the person adding a sensitive name to the branch has no reason to think about a fence written years ago around a different grant. ## Using it honestly 1. Name the names you could not afford this identity to read, with the data owner, not from intuition. 2. Write the deny with a **reason** and a **review date** in the rule itself. 3. Alert on every denial; each one is a lead, and none of them is a page-worthy fault by default. 4. Keep the derivation work ticketed and staffed — the fence bought you time, and time is all it bought. 5. When the grant is finally narrowed, **remove the fence**. Two overlapping rules mean no single rule is the truth, and the next reader will not know which one is load-bearing. The short version: fencing reduces the damage a drifted grant can do, produces the attribution that lets you fix it properly, and does nothing at all about the drift itself.
- Why does a denial firing in production count as a success here?Because it produces the thing the grant lacked: attribution. The denial names the identity, the name it wanted and the time, which leads to a consumer and usually an owner. Lift that one name if the use is legitimate, record who asked, and one invisible consumer has become a documented grant.
- When is fencing the wrong move?When you can attribute the grant. If the consumers are known, narrowing produces a rule that stays correct as the branch grows, while a fence over a knowable grant just adds a second rule to keep in step. Fencing earns its place under time pressure or genuine ignorance, not as a preference.
saying these in an interview costs you the question
- A deny rule makes the wildcard safe.
- Anything dangerous on that branch is covered by the deny list.
- Denies always win, whatever the system.
- A denial in production means the fence is wrong and should be lifted.
- Once the fence is in place, the derivation work can be closed.