book/operation/builtin/gatekeeper
Gatekeeper
When syndicate-server starts, it creates a
gatekeeper service entity, which accepts resolve
assertions requesting conversion of a long-lived credential to a live reference. The gatekeeper is
the default object, available
as OID 0 to peers at the other end of
relay listener connections.
Gatekeeper protocol
- Relevant schema: [syndicate-protocol]/schemas/gatekeeper.prs
Resolve = <resolve @step Step @observer #:rpc.Result> .
Step = <<rec> @stepType symbol [@detail any]> .
When a request to resolve a given credential, a Step,
appears, the gatekeeper entity queries a dataspace (by default, the
server’s top-level $config dataspace) for bind
assertions:
Bind = <bind @description Description @target #:any @observer BindObserver> .
Description = <<rec> @stepType symbol [@detail any]> .
BindObserver = @present #:Bound / @absent #f .
Bound = <bound @pathStep PathStep> / rpc.Error .
A bind assertion specifies the reference that backs a
long-lived credential, and gives instructions for checking the validity
of a presented credential. Each bind assertion matching a
requested Step is checked using the
stepType-specific detail in the
Description combined with the detail from the
Step. If the checks pass, the target entity
from the bind is asserted in an ok record to
the observer in the resolve. If the checks
fail, an error record is asserted to the
observer. If no bind matching a particular
Step exists, the system just waits; this allows it to be
relaxed about ordering of events.
However, besides waiting for a bind, the gatekeeper
asserts a resolve of its own into its associated dataspace,
with the same Step that it received but a different
observer. If, before an appropriate bind
appears, an ok assertion is sent to this
resolve’s observer, the gatekeeper stops
waiting for a bind and relays the response on to the
ultimate requester directly. This way, entities can keep an eye out for
resolve requests that will never complete, and answer
error to them even when no matching bind
exists. Entities can also use resolve requests to
synthesize a bind in a “just-in-time” fashion.
Sturdyrefs
- Relevant schema: [syndicate-protocol]/schemas/sturdy.prs
A “sturdyref” is a long-lived certificate including a cryptographic signature that can be upgraded by a gatekeeper entity to a live reference to the entity named in the sturdyref. The current sturdyref implementation is based on the design of Macaroons.
Example. The sturdyref
<ref {oid: "syndicate" sig: #[acowDB2/oI+6aSEC3YIxGg==]}>
is valid for the associated Bind assertion
<bind <ref {oid: "syndicate" key: #[]}> $ds #f>.
The following definitions are taken from the sturdy.prs schema. For further detail, see the reference.
SturdyStepType = =ref .
SturdyStepDetail = Parameters .
SturdyRef = <ref @parameters Parameters> .
First, when used as a Step, a sturdyref uses
ref as its stepType and
Parameters as its detail. A sturdyref as a
whole, then, is just the combination of the type and parameters in a
record.
Parameters = {
oid: any,
sig: bytes,
} & @caveats CaveatsField .
CaveatsField =
/ @present { caveats: [Caveat ...] }
/ @invalid { caveats: any }
/ @absent {} .
The Parameters of a sturdyref are the oid
field, which is a free-form value that the targeted service chooses to
name itself, and the sig, which is an iterated keyed-HMAC
construction, just as in macaroons. The sig is
derived from the oid and the service’s secret
key:
SturdyDescriptionDetail = {
oid: any,
key: bytes,
} .
In a Bind with stepType of
ref, the detail in the
Description should be a
SturdyDescriptionDetail value. The key is the
secret key used to compute sigs on sturdyrefs; the
oid connects references with their defining
Binds.
To compute a sig for a sturdyref, the service’s secret
key is first used to key an HMAC of the oid. Then, the
result is used to key an HMAC of the (canonical form of the)
first Caveat in the ref’s caveats, if any.
Each Caveat’s HMAC becomes the key for the next in the
caveatChain. The sig is the final result.
When validating sturdyrefs, compute the sig fresh,
starting from the key and oid, and compare the
final result to the presented sig.
Attenuation of authority
When it comes to publishing assertions or sending messages to the
entity denoted by a sturdyref, the caveatChain is used to
attenuate the authority denoted
by the sturdyref by filtering and/or rewriting assertion and message
bodies. The caveatChain is run right to left, with
newer rewrites-and-filters at the right-hand end of the chain and older
ones at the left-hand end. Of course, an empty caveatChain
is an unattenuated reference. The structure and interpretation of
Caveats is described fully in the relevant section of
the Syndicate network protocol specification.
The term “caveat” is shamelessly taken from macaroons, though our caveats presently embody only what in the Macaroons paper are called “first-party caveats” over assertion structure; future versions of the server may add “third-party caveats” and other, richer, predicates over assertions.
Copyright © 2021–2023 Tony Garnock-Jones, CC BY 4.0
