Closed AljoschaMeyer closed 10 months ago
We chatted about this live a few months back, but I should probably post this here for everyone else.
This is a commonly requested feature in capability systems, but is counterintuitively a bad idea in practice (from many people's lived experience over multiple decades). Such a feature is often called the "can_redelegate
bit". The core problem is that people inevitably work around the delegation limit by either sharing private keys (which breaks the security model) or simply ignoring the limit (which defeats the purpose of adding the feature).
The trade-off is that — unlike ACLs — that you get confinement[^1]: you can't run off with someone's authority (unless they leak their private key, which is something that you really don't want to incentivise by e.g. implementing delegation depth). This also simplifies reasoning about your security model: the network of authority precisely matches delegations, always attenuates, and continues to hold under composition of authority. To make an analogy, this is like referential transparency, but at the security layer.
The other way of thinking about capabilities is that — unlike roles — you should be able to do anything you like with your authority. That includes handing it to software agents, other members of your department, etc. In order to actually use your authority, you must be allowed to delegate an attenuated version of it to your program (user agent), rather than your program assuming all of your authority.
The truth of the matter is: delegation cannot be prevented. The further truth of the matter is: we do not appreciate how fortunate it is that delegation cannot be prevented. Because in fact, delegation is the cornerstone of civilization. — Marc Stiegler
[^1]: As an aside: note that this question of delegation depth is subtly different from the confinement problem:
[...] a program can create a controlled environment within which another, possibly untrusted program, can be run safely [...] We will call the problem of constraining a service [from leaking data or authority] the confinement problem.— Lampson '73
Thank you for this spec, it was a clear and enjoyable read.
A feature I had expected to pop up from idly thinking about this problem space before are bounds to the number of times a capability can be delegated. A simple implementation: Each capability has a count, either a natural number or infinity. A root capability would have a count of infinity. Delegating a capability of count infinity allows you to set an arbitrary count for the derived capability. Delegating a capability of finite count requires that the derived capability has a strictly lower count. Hence, it is impossible to delegate a capability of count zero.
The use cases I'm envisioning here are around webs of trust or foaf-based systems. With counting, you could give capabilities like "You get to access some resource, and you can also give that access to your friends, but they cannot propagate it to their friends (your foafs)." (that's for a starting count of
1
). Secure scuttlebutt and related protocols are examples of systems that could benefit a lot from this functionality.Is that something you have considered and discarded? If so I'd be curious to hear why. Or maybe the system can already express this and I just didn't notice?
(There might also be some design space around continuous trust spectra between zero and one where instead of a strictly decreasing counter you'd have a trust threshold that (possibly not necessarily strictly) decreases along a delegation chain. But that's more of a distracting aside than what I am actually interested in.)