-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Document the caveat structure #6
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -61,8 +61,90 @@ specific authorizations | |||||
- capabilities: a request carries a token that contains a set of rights | ||||||
that will be used for authorization, instead of deploying ACLs on every node | ||||||
|
||||||
|
||||||
## Structure and semantics | ||||||
|
||||||
A biscuit is structured as a cryptographic, append-only list; its elements are | ||||||
called *caveats*, and describe authorization properties. As with Macaroons, | ||||||
an operation must comply with all caveats in order to be allowed by the biscuit. | ||||||
|
||||||
Caveats describe which operations are authorized by providing predicates over | ||||||
the operation's attributes. | ||||||
|
||||||
Attributes are data, associated with the operation, | ||||||
that is known when the policy is evaluated, such as an identifier for the | ||||||
ressource being accessed, the type of the operation (read, write, append, ...), | ||||||
the operation's parameters (if any), the client's IP address or a | ||||||
channel-binding value (like the TLS transcript hash). | ||||||
|
||||||
Available attributes, and their type, are known ahead of time by the verifier. | ||||||
Some of those attributes are *critical*, and all caveats must provide a *bound* | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
That's @tarcieri version. I would rather enforce the property for all caveats because it means we guard against the same kind of mistake in attenuation too:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. adding bounds for all those attributes might make a token that is too large (let's remember, it should fit in a cookie), especially for the first caveat that might have the largest access. How could we make that as small as possible? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Geal How big would the representation of The main thing is that you want to always provide bounds for critical properties (cf. the discussion in Slack. TL;DR: unbounded critical properties confer accidental authority when the property is added or the property gains new possible values), so it's not so much of an overhead rather than preventing people from accidentally issuing tokens missing those caveats. I guess that, if biscuit size becomes an issue, we could support a compression scheme in settings where preceeding caveats are readable (i.e. in a public-key-signed token). For example, the representation of a predicate could refer to predicates in preceeding caveats when they share a (sub)term. |
||||||
for each critical attribute. | ||||||
|
||||||
Bounds are a subset of predicates, that only allow the following: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we want to allow non-bounds predicates at all? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. some predicates could add data. Specifically, I'm thinking of revocation ids. You put that in a caveat, and then if it gets compromised, you send that id to the revocation system (revocation lists, etc) to invalidate that token and all of its derivated ones There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Geal I didn't include anything about additional data in here, because that felt like an orthogonal issue, but I had a (short) discussion with @tarcieri about adding another append-only structure for identity data. The use-cases I had in mind included revocation, but also authn and non-repudiability/audit, allowing the biscuit to carry the chain of delegations that it went through. For instance, if I have a biscuit for a service, that I attenuate, mark for delegation to you, and send to you, on every (mis)use, there is a clear indication that it was the biscuit I sent you (i.e. you cannot claim it wasn't your biscuit). I think that really deserves its own issue, because there is a bunch of pretty-subtle things to take care of, there. |
||||||
- `any`: all values match; | ||||||
- `in <subset>`: only elements in `subset` match; this can be an explicit | ||||||
enumeration, or a (non-infinite) range in the case of numeric types. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. trying to think of other things we might need here, but none coming right now There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Geal Disjunctions of bounds ( |
||||||
|
||||||
|
||||||
### Rationale | ||||||
|
||||||
Some attributes grant authority (such as ressource identifiers, operation type, | ||||||
...), and failing to include a caveat limiting acceptable values is a common | ||||||
failure with Macaroons, resulting in authority being accidentally granted. | ||||||
|
||||||
By marking them critical, two things are achieved: | ||||||
- They must be bound by caveats, preventing accidental authority grants when new | ||||||
values are added. | ||||||
- Their presence is required in all caveats for a biscuit to be valid; as such: | ||||||
- if developers accidentally fail to provide a bound, the biscuit is invalid; | ||||||
- biscuits issued before the attribute was defined are implicitely revoked. | ||||||
|
||||||
For example, consider a data store, which initially only provides read access. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the example useful? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what happens when an attribute is already critical, for which we provided a bound, yet it changed and got more general? The biscuit would still be valid, but still suddenly get more access. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (the example is useful, btw) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Geal That's the second part of the example: when new values (there, |
||||||
Assume I was granted a biscuit for ressources in it, before a developper | ||||||
implemented read-write access, along with a `type` attribute (which can be | ||||||
`Read` or `Write`). My biscuit suddenly grants me read-write access. | ||||||
|
||||||
Marking the `type` attribute as critical means that I must request a new | ||||||
biscuit, that properly specifies whether my access is read and/or write. | ||||||
|
||||||
Now, if I was to be issued a biscuit with the caveat `type != Write`, before the | ||||||
types `Append`, `Create`, and `Delete` were added, my the biscuit would again go | ||||||
from granting read-only access to granting write access; this is why critical | ||||||
attributes must use bounds. | ||||||
|
||||||
|
||||||
By requiring that all caveats provide a bound for each critical attribute, we | ||||||
can guarantee that a biscuit does not gain unintended authority when new | ||||||
attributes, or new values for them, are added in the system. (The use of `any` | ||||||
is considered intentional.) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we make a more precise statement? Without |
||||||
|
||||||
|
||||||
### Interpretation | ||||||
|
||||||
Given an operation's `attributes`, the set of `critical` attributes, a given | ||||||
`biscuit` is evaluated as follows: | ||||||
|
||||||
```python3 | ||||||
for caveat in biscuit: | ||||||
bounds = set() | ||||||
for predicate in caveat: | ||||||
if not predicate.eval(attributes): | ||||||
return False | ||||||
if predicate.isbound: | ||||||
bounds.add(predicate.attribute) | ||||||
|
||||||
if not bounds.contains(critical): | ||||||
return False | ||||||
|
||||||
return True | ||||||
``` | ||||||
|
||||||
|
||||||
## Format | ||||||
|
||||||
XXXTODO: Update for caveats | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we just remove the wire-format spec for now? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd rather keep the format and the rights management part for now, but maybe adding a comment indicating we're working on those. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK; keeping as-is then (“XXXTODO: Update for [...]” should convey clearly that the section is out-of-date). |
||||||
|
||||||
A biscuit token is an ordered list of key and value tuples, stored in HPACK | ||||||
format. HPACK was chosen to avoid specifying yet another serialization format, | ||||||
and reusing its data compression features to make tokens small enough to | ||||||
|
@@ -139,33 +221,6 @@ the token): | |||||
|
||||||
Those common keys and values will be present in the HPACK static table | ||||||
|
||||||
## Rights management | ||||||
|
||||||
The rules are defined to allow flexibility in rules verification. The default token | ||||||
will start with all the rights, and restrict them with the "rights" field in each | ||||||
new block. But what those restrictions mean will depend on which service verifies | ||||||
the token, as they might care (or even know) about different sets of capabilities. | ||||||
|
||||||
Starting from a set of rights `R`, that contains a list of namespaces. Each namespace | ||||||
has a list of tuples `(tag, feature, [options])`. Tags and features can appear in | ||||||
multiple tuples. | ||||||
A `rights` field contains a list of namespaces, and for each namespace, | ||||||
a list of right patterns matching `(tag, feature, [options])` tuples, | ||||||
and a `+` or `-` tag indicating if it should be added or removed. | ||||||
|
||||||
Appying rights attenuation: | ||||||
|
||||||
- for each namespace `N`: | ||||||
- load the current set of rights `R` | ||||||
- either the original set of rights for the verifier | ||||||
- or the set of rights after attenuation by the previous block | ||||||
- all rights in `R` are marked as `+` (active) | ||||||
- for each right pattern ( `RP = (+|-) tag : feature(options)` ): | ||||||
- for each right tuple `r = (tag, feature, [options])` in `R` matched by `RP`: | ||||||
- if r is active ( `+` ) but `RP` contains `-`, mark r as inactive ( `-` ) | ||||||
- if r is inactive ( `-` ) but `RP` contains `+`, mark r as active ( `+` ) | ||||||
- filter `R` to keep only the tuples marked as active | ||||||
- store `R` as the newt rights for `N` | ||||||
|
||||||
## Cryptography | ||||||
|
||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed from (initially) properties.