Skip to content
About
Main content

Views, grants and privilege inheritance

When is a view a real security boundary, and why do grants only ever accumulate?

Views as security boundaries

A view is a saved query with a name. A view is a security boundary only if the engine is the only path to the underlying bytes, and the view cannot leak through the way it is evaluated. Both conditions often fail.

The path. If the files are readable with storage , the real boundary is the storage permission and the view is documentation. This is the in its purest form, and it is exactly Mateus's problem.

The evaluation. Views can run with the rights of their creator (definer's rights) or of the caller (). A definer's-rights view is like the Unix setuid bit (a program that runs with its owner's privileges): it is a privilege-escalation tool. It reintroduces the : a program with high authority that is tricked into using it for a caller with low authority. The view happily uses its elevated rights for anyone who asks in the right words. Invoker's-rights views avoid this, but then they fail to solve the original problem, because the caller cannot read the base table. There is no clean answer. You choose per view.

The audit. Views reference other views. "Who can see this PII column?" becomes a transitive-closure question (follow every chain of views) over view definitions. You have accidentally built a relationship-based model, without any of its machinery.

In one sentence: a view is a boundary only if it is the narrowest waist and the optimizer is forbidden from looking around it.


Grants, roles and privilege inheritance

Inheritance exists for the same reason roles do. It turns O(subjects × objects) assignments into something closer to O(subjects + objects): give a permission to a folder and every table inside inherits it. The price is that effective permission becomes an implicit quantity: the transitive closure of a graph of grants, possibly minus denies, spread across objects, roles and ownership. Nobody sees it written down.

Three structural facts follow.

1. The right to grant is itself the perimeter. If a holds (the right to pass a permission on), the set of people who can be authorized is the closure under delegation, not today's list of assignments. An audit that lists current grants measures the wrong set.

2. A set of "allow" rules is monotone (adding a rule only widens access). You can cache it, merge it across sources and evaluate it in any order. When you add "deny" you need precedence rules ("deny wins", "most specific wins"), and the answer depends on evaluation order. That makes distributed evaluation and caching much harder. But without deny you cannot state exceptions, and every real organization has exceptions. This is a real, unresolved trade-off.

3. Grants accumulate and never recede. This one is not technical. Adding a grant unblocks a named person today. Removing one might break an unknown job next quarter. The costs are unequal and fall on different people at different times, so the rational local action is always grant, never revoke. (access slowly growing past what anyone intended) is therefore the default state of any system without a forcing function. Access reviews, expiring grants and just-in-time elevation (getting rights only for a short time when needed) are compensating controls for an incentive gradient, not for a missing feature.

That last point deserves to be a rule in its own right.

It is an organizational rule rather than a physical one, and it applies far beyond security. It has the same shape as data-quality checks being switched off, alerts being muted and schema contracts being loosened.

In one sentence: inheritance trades explicit assignment for implicit closure, and the closure only grows unless something external makes it shrink.