Documentation
¶
Overview ¶
package macaroon defines Fly.io's Macaroon token format.
Tokens are created with New, and refined with [Add] and [Add3P] to add conditions, called caveats. Their signature is updated as caveats are added. They're serialized with [Encode]
Serialized tokens are parsed with Decode, to get a Macaroon. To do real things with it, [Verify] it to receive the set of usable caveats.
Serialized tokens can also be scanned with [DischargeMacaroon] to find caveats that need third-party discharges.
Once fully parsed, a service using these tokens calls Validate to check the caveats.
Index ¶
- Constants
- Variables
- func DischargeCID(ka EncryptionKey, location string, cid []byte) ([]Caveat, *Macaroon, error)
- func FindPermissionAndDischargeTokens(tokens [][]byte, location string) ([]*Macaroon, [][]byte, []*Macaroon, [][]byte, error)
- func GetCaveats[T Caveat](c *CaveatSet) (ret []T)
- func Parse(header string) ([][]byte, error)
- func ParsePermissionAndDischargeTokens(header string, location string) ([]byte, [][]byte, error)
- func RegisterCaveatType(name string, typ CaveatType, zeroValue Caveat)
- func ThirdPartyCID(encodedMacaroon []byte, thirdPartyLocation string) ([]byte, error)
- func ToAuthorizationHeader(toks ...[]byte) string
- func Validate[A Access](cs *CaveatSet, accesses ...A) error
- type Access
- type Action
- type BindToParentToken
- type Caveat
- type Caveat3P
- type CaveatSet
- func (c *CaveatSet) DecodeMsgpack(dec *msgpack.Decoder) error
- func (c CaveatSet) EncodeMsgpack(enc *msgpack.Encoder) error
- func (c CaveatSet) MarshalJSON() ([]byte, error)
- func (c CaveatSet) MarshalMsgpack() ([]byte, error)
- func (c *CaveatSet) UnmarshalJSON(b []byte) error
- func (c *CaveatSet) Validate(accesses ...Access) error
- type CaveatType
- type EncryptionKey
- type IfPresent
- type Macaroon
- func (m *Macaroon) Add(caveats ...Caveat) error
- func (m *Macaroon) Add3P(ka EncryptionKey, loc string, cs ...Caveat) error
- func (m *Macaroon) Bind(parent []byte) error
- func (m *Macaroon) BindToParentMacaroon(parent *Macaroon) error
- func (m *Macaroon) Encode() ([]byte, error)
- func (m *Macaroon) Expiration() time.Time
- func (m *Macaroon) ThirdPartyCID(location string, existingDischarges ...[]byte) ([]byte, error)
- func (m *Macaroon) ThirdPartyCIDs(existingDischarges ...[]byte) (map[string][]byte, error)
- func (m *Macaroon) Verify(k SigningKey, discharges [][]byte, trusted3Ps map[string]EncryptionKey) (*CaveatSet, error)
- type Nonce
- type SigningKey
- type ValidityWindow
Constants ¶
const ( ActionAll = ActionRead | ActionWrite | ActionCreate | ActionDelete | ActionControl ActionNone = Action(0) )
const ( CavValidityWindow CaveatType Cav3P CavBindToParentToken CavIfPresent // Globally-recognized user-registerable caveat types may be requested via // pull requests to this repository. Add a meaningful name of the caveat // type (e.g. CavAcmeCorpWidgetID) on the line prior to // CavMaxUserRegisterable. CavMinUserRegisterable = 1 << 32 CavMaxUserRegisterable = 1<<48 - 1 CavMinUserDefined = 1 << 48 CavMaxUserDefined = 1<<64 - 2 CavUnregistered = 1<<64 - 1 )
const (
EncryptionKeySize = 32
)
Variables ¶
var ( ErrUnrecognizedToken = errors.New("bad token") ErrInvalidAccess = fmt.Errorf("%w: bad data for token verification", ErrUnauthorized) ErrResourcesMutuallyExclusive = fmt.Errorf("%w: resources are mutually exclusive", ErrInvalidAccess) ErrResourceUnspecified = fmt.Errorf("%w: must specify", ErrInvalidAccess) ErrBadCaveat = fmt.Errorf("%w: bad caveat", ErrUnauthorized) )
Functions ¶
func DischargeCID ¶
Decyrpts the CID from the 3p caveat and prepares a discharge token. Returned caveats, if any, must be validated before issuing the discharge token to the user.
func GetCaveats ¶
GetCaveats gets any caveats of type T, including those nested within IfPresent caveats.
func ParsePermissionAndDischargeTokens ¶
Parse a string token and find the contained permission token for the given location.
func RegisterCaveatType ¶
func RegisterCaveatType(name string, typ CaveatType, zeroValue Caveat)
Register a caveat type for use with this library.
func ThirdPartyCID ¶
Checks the macaroon for a third party caveat for the specified location. Returns the caveat's encrypted CID, if found.
func ToAuthorizationHeader ¶
ToAuthorizationHeader formats a collection of tokens as an HTTP Authorization header.
Types ¶
type Access ¶
type Access interface {
// The action being attempted by the principal
GetAction() Action
// The current time
Now() time.Time
// Callback for validating the structure
Validate() error
}
Access represents the user's attempt to access some resource. Different caveats will require different contextual information.
type Action ¶
type Action uint16
Action is an RWX-style bitmap of actions that can be taken on a resource (eg org, app, machine). An Action can describe the permission limitations expressed by a caveat or the action a principal is attempting to take on a resource. The precise semantics of Actions are left to Caveat/AuthAttempt implementations.
const ( // ActionRead indicates reading attributes of the specified objects. ActionRead Action = 1 << iota // ActionWrite indicates writing attributes of the specified objects. ActionWrite // ActionCreate indicates creating the specified object. Since the ID of an // object will be unknown before creation, this is mostly meaningless // unless inherited from a parent. E.g. org:123:create lets you create // app:234 belonging to org:123. ActionCreate // ActionDelete indicates deleting the specified object. ActionDelete // ActionControl indicates changing the state of the specified object, but // not modifying other attributes. In practice, this mostly applies to // starting/stopping/signaling machines. ActionControl )
func ActionFromString ¶
func (Action) IsSubsetOf ¶
IsSubsetOf returns wether all bits in p are set in other.
func (Action) MarshalJSON ¶
func (*Action) UnmarshalJSON ¶
type BindToParentToken ¶
type BindToParentToken []byte
BindToParentToken is used by discharge tokens to state that they may only be used to discharge 3P caveats for a specific root token or further attenuated versions of that token. This prevents a discharge token from being used with less attenuated versions of the specified token, effectively binding the discharge token to the root token. This caveat may appear multiple times to iteratively clamp down which versions of the root token the discharge token may be used with.
The parent token is identified by a prefix of the SHA256 digest of the token's signature.
func (*BindToParentToken) CaveatType ¶
func (c *BindToParentToken) CaveatType() CaveatType
func (*BindToParentToken) IsAttestation ¶
func (c *BindToParentToken) IsAttestation() bool
func (*BindToParentToken) Prohibits ¶
func (c *BindToParentToken) Prohibits(f Access) error
type Caveat ¶
type Caveat interface {
// The numeric caveat type identifier.
CaveatType() CaveatType
// Callback for checking if the authorization check is blocked by this
// caveat. Implementors must take care to return appropriate error types,
// as they have bearing on the evaluation of IfPresent caveats.
// Specifically, returning ErrResourceUnspecified indicates that caveat
// constrains access to a resource type that isn't specified by the Access.
Prohibits(f Access) error
// Whether or not this caveat type is an attestation. Attestations make a
// positive assertion rather than constraining access to a resource. Most
// caveats are not attestations.
IsAttestation() bool
}
Caveat is the interface implemented by all caveats.
type Caveat3P ¶
type Caveat3P struct {
Location string
VID []byte // used by the initial issuer to verify discharge macaroon
CID []byte // used by the 3p service to construct discharge macaroon
// contains filtered or unexported fields
}
Caveat3P is a requirement that the token be presented along with a 3P discharge token.
func (*Caveat3P) CaveatType ¶
func (c *Caveat3P) CaveatType() CaveatType
func (*Caveat3P) IsAttestation ¶
type CaveatSet ¶
type CaveatSet struct {
Caveats []Caveat
}
CaveatSet is how a set of caveats is serailized/encoded.
func DecodeCaveats ¶
Decodes a set of serialized caveats.
func NewCaveatSet ¶
Create a new CaveatSet comprised of the specified caveats.
func (*CaveatSet) DecodeMsgpack ¶
Implements msgpack.CustomDecoder
func (CaveatSet) EncodeMsgpack ¶
Implements msgpack.CustomEncoder
func (CaveatSet) MarshalJSON ¶
func (CaveatSet) MarshalMsgpack ¶
Implements msgpack.Marshaler
func (*CaveatSet) UnmarshalJSON ¶
type CaveatType ¶
type CaveatType uint64
A numeric identifier for caveat types. Values less than CavMinUserRegisterable (0x100000000) are reserved for use by fly.io. Users may request a globally-recognized caveat type via pull requests to this repository. Implementations that don't need to integrate with fly.io itself can pick from the user-defined range (>0x1000000000000).
type EncryptionKey ¶
type EncryptionKey []byte
func NewEncryptionKey ¶
func NewEncryptionKey() EncryptionKey
type IfPresent ¶
IfPresent attempts to apply the specified `Ifs` caveats if the relevant resources are specified. If none of the relevant resources are specified, the `Else` caveats are applied.
This is only meaningful to use with "resource" caveats: org, app, feature, volume, machine. Notably, it explicitly doesn't work with the Mutations caveat.
func (*IfPresent) CaveatType ¶
func (c *IfPresent) CaveatType() CaveatType
func (*IfPresent) IsAttestation ¶
type Macaroon ¶
type Macaroon struct {
Nonce Nonce `json:"-"`
Location string `json:"location"`
UnsafeCaveats CaveatSet `json:"caveats"`
Tail []byte `json:"-"`
// contains filtered or unexported fields
}
Macaroon is the fully-functioning internal representation of a token --- you've got a Macaroon either because you're constructing a new token yourself, or because you've parsed a token from the wire.
func New ¶
func New(kid []byte, loc string, key SigningKey) (*Macaroon, error)
New creates a new token given a key-id string (which can be any opaque string and doesn't need to be cryptographically random or anything; the key-id is how you're going to relate the token back to a key you've saved somewhere; it's probably a database rowid somehow) and a location, which is ordinarily a URL. The key is the signing secret.
func (*Macaroon) Add ¶
Add adds a caveat to a Macaroon, adjusting the tail signature in the process. This is how you'd "attenuate" a token, taking a read-write token and turning it into a read-only token, for instance.
func (*Macaroon) Add3P ¶
func (m *Macaroon) Add3P(ka EncryptionKey, loc string, cs ...Caveat) error
Add3P adds a third-party caveat to a Macaroon. A third-party caveat is checked not by evaluating what it means, but instead by looking for a "discharge token" --- a second token sent along with the token that says "some other service verified that the claims corresponding to this caveat are true".
Add3P needs a key, which binds this token to the service that validates it. Every authentication caveat, for instance, shares an authentication key; the key connects the root service to the authentication service.
Add3P takes a location, which is used to figure out which keys to use to check which caveats. The location is normally a URL. The authentication service has an authentication location URL.
func (*Macaroon) Bind ¶
Bind binds this (discharge) token to the specified root token (parent) with a BindToParentToken caveat.
func (*Macaroon) BindToParentMacaroon ¶
func (*Macaroon) Encode ¶
Encode encodes a Macaroon to bytes after creating it or decoding it and adding more caveats.
func (*Macaroon) Expiration ¶
Expiration calculates when this macaroon will expire
func (*Macaroon) ThirdPartyCID ¶
Checks the macaroon for a third party caveat for the specified location. Returns the caveat's encrypted CID, if found.
func (*Macaroon) ThirdPartyCIDs ¶
ThirdPartyCIDs extracts the encrypted CIDs from a token's third party caveats. Each is identified by the location of the third party. The CID can then be exchanged with the third party for a discharge token. Third party caveats are checked against existing discharge tokens and discharged caveats are omitted from the results.
func (*Macaroon) Verify ¶
func (m *Macaroon) Verify(k SigningKey, discharges [][]byte, trusted3Ps map[string]EncryptionKey) (*CaveatSet, error)
Verify checks the signature on a Decode()'ed Macaroon and returns the the set of caveats that require validation against the user's request. This excludes caveats that have already been validated (e.g. 3P caveats and others relating to the signing of the Macaroon).
type Nonce ¶
type Nonce struct {
// contains filtered or unexported fields
}
Nonce encodes the key ID that signed the macaroon as well as some randomness
func DecodeNonce ¶
DecodeNonce parses just the nonce from an encoded macaroon.
func (*Nonce) DecodeMsgpack ¶
DecodeMsgpack implements msgpack.CustomDecoder
func (*Nonce) EncodeMsgpack ¶
DecodeMsgpack implements msgpack.CustomDecoder
func (Nonce) MustEncode ¶
type ValidityWindow ¶
type ValidityWindow struct {
NotBefore int64 `json:"not_before"`
NotAfter int64 `json:"not_after"`
}
ValidityWindow establishes the window of time the token is valid for.
func (*ValidityWindow) CaveatType ¶
func (c *ValidityWindow) CaveatType() CaveatType
func (*ValidityWindow) IsAttestation ¶
func (c *ValidityWindow) IsAttestation() bool
func (*ValidityWindow) Prohibits ¶
func (c *ValidityWindow) Prohibits(f Access) error