Documentation
¶
Index ¶
- Constants
- Variables
- func AttenuateBiscuit(biscuitData []byte, rule *api.TaskAuthorizationRule) ([]byte, error)
- func AttenuateBiscuitWithRand(rng io.Reader, biscuitData []byte, rule *api.TaskAuthorizationRule) ([]byte, error)
- func AuthorizeMeshRequest(authorizer biscuit.Authorizer, req MeshRequest, pol MeshPolicy) error
- func AuthorizerOptions(timeout time.Duration) []biscuit.AuthorizerOption
- func DecodeBase64Biscuit(encoded string) ([]byte, error)
- func EnforceExpiration(authorizer biscuit.Authorizer)
- func ExtractTaskRules(biscuitData []byte) ([]*api.TaskAuthorizationRule, error)
- func MintBiscuitToken(signingKey ed25519.PrivateKey, claims jwt.MapClaims, token *oidc.IDToken, ...) ([]byte, []string, error)
- func MintBootstrapBiscuitToken(signingKey ed25519.PrivateKey, remotePeer peer.ID, role string, ...) ([]byte, error)
- func MintDelegatedBiscuitToken(signingKey ed25519.PrivateKey, claims jwt.MapClaims, actorPeer peer.ID, ...) ([]byte, error)
- func MintDelegatedBiscuitTokenWithRand(rng io.Reader, signingKey ed25519.PrivateKey, claims jwt.MapClaims, ...) ([]byte, error)
- func RequireAuthorityBinding(b *biscuit.Biscuit, expectedPeer peer.ID) error
- func RequireAuthorityRequestBinding(b *biscuit.Biscuit, expectedPeer peer.ID) error
- func RequireIngress(b *biscuit.Biscuit, key ed25519.PublicKey, svcType, svcName, mode string, ...) error
- func RequirePublish(b *biscuit.Biscuit, key ed25519.PublicKey, svcType, svcName string, ...) error
- func RequireRole(b *biscuit.Biscuit, key ed25519.PublicKey, expectedRole string, ...) error
- func SealBiscuit(biscuitData []byte) ([]byte, error)
- func SealBiscuitWithRand(rng io.Reader, biscuitData []byte) ([]byte, error)
- func TargetFactsFromBiscuit(b *biscuit.Biscuit, trustedKeys []ed25519.PublicKey, timeout time.Duration) ([]biscuit.Fact, error)
- func UnmarshalInbound(biscuitData []byte) (*biscuit.Biscuit, []*api.TaskAuthorizationRule, error)
- func ValidateIngressCallerPreDial(claims *VerifiedBiscuitClaims, p IngressEvalParams) (map[string][]string, error)
- func VerifyAndExtractPeerID(trustedPublicKeys []ed25519.PublicKey, biscuitData []byte, ...) (peer.ID, error)
- func VerifyBiscuit(biscuitData []byte, expectedPeer peer.ID, ...) (*biscuit.Biscuit, error)
- func VerifyBiscuitAdmission(biscuitData []byte, expectedPeer peer.ID, ...) (*biscuit.Biscuit, ed25519.PublicKey, time.Time, error)
- func VerifyBiscuitAndGetExpiry(biscuitData []byte, expectedPeer peer.ID, ...) (time.Time, error)
- func VerifyBiscuitAndGetKey(biscuitData []byte, expectedPeer peer.ID, ...) (*biscuit.Biscuit, ed25519.PublicKey, error)
- func VerifyBiscuitRole(biscuitData []byte, controlPlanePubKey ed25519.PublicKey, expectedRole string, ...) error
- func VerifyExpiredAndExtractPeerID(trustedPublicKeys []ed25519.PublicKey, biscuitData []byte, ...) (peer.ID, error)
- func VerifyJWT(ctx context.Context, jwtStr string, allowedAudiences []string, ...) (jwt.MapClaims, *oidc.IDToken, error)
- type IngressCallerResult
- type IngressEvalParams
- type MeshPolicy
- type MeshRequest
- type UnknownIssuerError
- type VerifiedBiscuitClaims
Constants ¶
const DefaultAuthorizerTimeout = 1 * time.Second
DefaultAuthorizerTimeout bounds Datalog evaluation when no timeout is configured. biscuit-go defaults to 2ms of wall-clock time, of which a single authorization of a realistic token already spends ~0.14ms (~1.1ms under -race), so ordinary scheduling noise turns into a spurious denial.
Variables ¶
var ErrAppendedBlocks = errors.New("biscuit carries invalid appended blocks; only tar_block attenuation facts are permitted")
ErrAppendedBlocks is returned for a token that carries an invalid appended attenuation block (more than api.MaxAttenuationBlocks blocks, or any block that does not consist solely of 0 rules, 0 checks, and 1 valid tar_block fact).
Functions ¶
func AttenuateBiscuit ¶
func AttenuateBiscuit(biscuitData []byte, rule *api.TaskAuthorizationRule) ([]byte, error)
AttenuateBiscuit appends a validated TaskAuthorizationRule as a single tar_block("<base64url>") fact block (with 0 rules and 0 checks) to an existing Biscuit token.
func AttenuateBiscuitWithRand ¶
func AttenuateBiscuitWithRand(rng io.Reader, biscuitData []byte, rule *api.TaskAuthorizationRule) ([]byte, error)
AttenuateBiscuitWithRand is AttenuateBiscuit with an explicit random source (used by deterministic conformance vector generators).
func AuthorizeMeshRequest ¶ added in v0.2.0
func AuthorizeMeshRequest(authorizer biscuit.Authorizer, req MeshRequest, pol MeshPolicy) error
AuthorizeMeshRequest loads req and pol into authorizer in the one order every enforcement point uses and runs it. The authorizer must already be built on the credential under the key that verified it; the caller checks revocation, bans and the authority-block binding before, and evaluates TaskAuthorizationRules (req.TaskRequest) after.
func AuthorizerOptions ¶
func AuthorizerOptions(timeout time.Duration) []biscuit.AuthorizerOption
AuthorizerOptions returns the authorizer options enforcing a Datalog evaluation budget. A non-positive timeout falls back to DefaultAuthorizerTimeout.
func DecodeBase64Biscuit ¶ added in v0.2.0
DecodeBase64Biscuit decodes a base64 or unpadded base64url encoded Biscuit.
func EnforceExpiration ¶
func EnforceExpiration(authorizer biscuit.Authorizer)
EnforceExpiration injects the current time and the expiration check into an authorizer. Every path that admits a biscuit must call this: expiry is a Datalog check over a time fact, so an authorizer built without the fact silently accepts expired tokens (see #296). A token carrying no expiration() fact fails the check, so this is fail-closed.
func ExtractTaskRules ¶
func ExtractTaskRules(biscuitData []byte) ([]*api.TaskAuthorizationRule, error)
ExtractTaskRules validates an inbound Biscuit's appended blocks and returns its decoded TaskAuthorizationRule chain (nil if authority-only).
func MintBiscuitToken ¶
func MintBiscuitToken(signingKey ed25519.PrivateKey, claims jwt.MapClaims, token *oidc.IDToken, remotePeer peer.ID, biscuitExpiry time.Time, roles []string, policyRoles []*api.PolicyRole, labels map[string]string) ([]byte, []string, error)
MintBiscuitToken generates a signed Biscuit token for a peer with policy rules based on JWT claims. labels are control-plane-attested key=value claims (canonical, pre-validated); empty means no claims.
func MintBootstrapBiscuitToken ¶
func MintBootstrapBiscuitToken(signingKey ed25519.PrivateKey, remotePeer peer.ID, role string, expiration time.Time, policyRoles []*api.PolicyRole, labels map[string]string) ([]byte, error)
MintBootstrapBiscuitToken generates a signed Biscuit token for a peer using a bootstrap role. labels are control-plane-attested key=value claims (canonical, pre-validated); empty means no claims.
func MintDelegatedBiscuitToken ¶
func MintDelegatedBiscuitToken(signingKey ed25519.PrivateKey, claims jwt.MapClaims, actorPeer peer.ID, biscuitExpiry time.Time, roles []string, policyRoles []*api.PolicyRole, taskRule *api.TaskAuthorizationRule, seal bool) ([]byte, error)
MintDelegatedBiscuitToken generates a stateless Delegated Session Biscuit for a subject whose credential was exchanged by actorPeer at POST /token/exchange. The authority block carries client_peer_id(actorPeer) and actor_node(actorPeer), and deliberately omits node(actorPeer) so policy bindings targeting node:<actorPeer> never attach the node's roles to the delegated subject.
func MintDelegatedBiscuitTokenWithRand ¶
func MintDelegatedBiscuitTokenWithRand(rng io.Reader, signingKey ed25519.PrivateKey, claims jwt.MapClaims, actorPeer peer.ID, biscuitExpiry time.Time, roles []string, policyRoles []*api.PolicyRole, taskRule *api.TaskAuthorizationRule, seal bool) ([]byte, error)
MintDelegatedBiscuitTokenWithRand is MintDelegatedBiscuitToken with an explicit random source (used by deterministic conformance vector generators).
func RequireAuthorityBinding ¶
RequireAuthorityBinding checks that the token is bound to expectedPeer by an api.FactNode fact in the authority block.
The block matters. biscuit-go's GetBlockID searches appended attenuation blocks too, and appending needs no root key, so a holder of anyone's token can append node(<their own peer id>) offline and satisfy a binding that only tests the error. Those facts are invisible to the Datalog authorizer (see TestAttenuationBlockFactsAreInvisibleToTheAuthorizer), so this lookup is the only place the distinction has to be made by hand.
func RequireAuthorityRequestBinding ¶
RequireAuthorityRequestBinding checks that a request token is bound to expectedPeer in the authority block: either as a direct member token carrying node(expectedPeer), or as a delegated session token (minted at POST /token/exchange) carrying both actor_node(expectedPeer) and client_peer_id(expectedPeer) in the authority block without node().
func RequireIngress ¶ added in v0.2.0
func RequireIngress(b *biscuit.Biscuit, key ed25519.PublicKey, svcType, svcName, mode string, policyRules []biscuit.Rule, timeout time.Duration) error
RequireIngress reports whether the credential grants exposing the inbound service svcType://svcName on external router HTTP ingress under mode ("edge" or "passthrough"): api.IngressPolicies over the token's granted_ingress_* facts, those the mesh policy rules derive from its role() and label() facts, and an ingress() fact. b must have passed verification and key must be the key that verified it.
func RequirePublish ¶
func RequirePublish(b *biscuit.Biscuit, key ed25519.PublicKey, svcType, svcName string, policyRules []biscuit.Rule, timeout time.Duration) error
RequirePublish reports whether the credential grants serving the service svcType://svcName: api.PublishPolicies over the token's granted_publish_* facts, those the mesh policy rules derive from its role() and label() facts, and a publish() fact. The rules are what a policy change reaches a verifier through before the holder's credential is minted again. b must have passed verification and key must be the key that verified it; what is decided here is the grant alone.
func RequireRole ¶
func RequireRole(b *biscuit.Biscuit, key ed25519.PublicKey, expectedRole string, timeout time.Duration) error
RequireRole checks that the token carries role(expectedRole) under the given key. It checks nothing else: a token received from a peer must already have passed VerifyBiscuitAndGetKey, which is where expiry and the peer binding are enforced, and key must be the key that verified it.
func SealBiscuit ¶
SealBiscuit cryptographically seals a Biscuit token so no further blocks can be appended by a downstream holder.
func SealBiscuitWithRand ¶
SealBiscuitWithRand is SealBiscuit with an explicit random source (used by deterministic conformance vector generators).
func TargetFactsFromBiscuit ¶ added in v0.2.0
func TargetFactsFromBiscuit(b *biscuit.Biscuit, trustedKeys []ed25519.PublicKey, timeout time.Duration) ([]biscuit.Fact, error)
TargetFactsFromBiscuit queries api.TargetFactRules on a provider's own verified Biscuit to produce the target_fact(type, val) facts injected when evaluating BaselineTargetCheck against a caller.
func UnmarshalInbound ¶
UnmarshalInbound parses a token received from a peer or a client and validates any appended attenuation blocks BEFORE building a Datalog authorizer.
Appending needs no root key, so appended blocks are the one place a token holder could otherwise put Datalog of their own (such as a self-join rule or check that pins a core for the evaluation budget and leaks a worker goroutine). UnmarshalInbound inspects the raw pb.Biscuit envelope and block sources first, admitting at most api.MaxAttenuationBlocks blocks and requiring every appended block to contain 0 rules, 0 checks, and exactly 1 tar_block("<base64url-proto>") fact encoding a valid api.TaskAuthorizationRule. It returns both the parsed Biscuit and the decoded TaskAuthorizationRule chain so callers never parse twice.
func ValidateIngressCallerPreDial ¶ added in v0.2.0
func ValidateIngressCallerPreDial(claims *VerifiedBiscuitClaims, p IngressEvalParams) (map[string][]string, error)
ValidateIngressCallerPreDial checks the caller's verified Biscuit claims, TAR attenuation chain, and ServiceIngress.allow ACL locally before opening a network connection or /mesh/auth handshake to the serving provider.
func VerifyAndExtractPeerID ¶
func VerifyAndExtractPeerID(trustedPublicKeys []ed25519.PublicKey, biscuitData []byte, timeout time.Duration) (peer.ID, error)
VerifyAndExtractPeerID checks that the biscuit is signed by one of the trusted keys and is unexpired, and returns the peer ID.
func VerifyBiscuit ¶
func VerifyBiscuit(biscuitData []byte, expectedPeer peer.ID, trustedPublicKeys []ed25519.PublicKey, timeout time.Duration) (*biscuit.Biscuit, error)
VerifyBiscuit verifies the validity of a Biscuit token. It ensures that: 1. The token is cryptographically signed by one of the trustedPublicKeys. 2. The token is not expired. 3. The token is securely bound to the expected remotePeer.
func VerifyBiscuitAdmission ¶
func VerifyBiscuitAdmission(biscuitData []byte, expectedPeer peer.ID, trustedPublicKeys []ed25519.PublicKey, timeout time.Duration) (*biscuit.Biscuit, ed25519.PublicKey, time.Time, error)
VerifyBiscuitAdmission is VerifyBiscuit that reports both the key that verified the token and when it lapses, for a caller that caches the admission and goes on to evaluate the token under that key.
func VerifyBiscuitAndGetExpiry ¶
func VerifyBiscuitAndGetExpiry(biscuitData []byte, expectedPeer peer.ID, trustedPublicKeys []ed25519.PublicKey, timeout time.Duration) (time.Time, error)
VerifyBiscuitAndGetExpiry is VerifyBiscuit that also reports when the token lapses, for callers that cache the admission and must drop it on time.
func VerifyBiscuitAndGetKey ¶
func VerifyBiscuitAndGetKey(biscuitData []byte, expectedPeer peer.ID, trustedPublicKeys []ed25519.PublicKey, timeout time.Duration) (*biscuit.Biscuit, ed25519.PublicKey, error)
VerifyBiscuitAndGetKey is VerifyBiscuit that also reports which trusted key verified the token, for callers that go on to evaluate it under that key.
func VerifyBiscuitRole ¶
func VerifyBiscuitRole(biscuitData []byte, controlPlanePubKey ed25519.PublicKey, expectedRole string, timeout time.Duration) error
VerifyBiscuitRole checks that the biscuit is signed by the control plane's public key and contains the specified role fact. It deliberately does NOT enforce expiry: its callers either hold a token the control plane minted moments ago, or are deciding whether an identity loaded from disk is worth starting with, where a lapsed token should trigger a refresh rather than refuse to boot. Do not use it to admit a token received from a peer.
func VerifyExpiredAndExtractPeerID ¶
func VerifyExpiredAndExtractPeerID(trustedPublicKeys []ed25519.PublicKey, biscuitData []byte, timeout time.Duration) (peer.ID, error)
VerifyExpiredAndExtractPeerID checks that the biscuit is signed by one of the trusted keys and returns the peer ID, deliberately WITHOUT enforcing expiry. Only the refresh flow may use it: a node refreshes precisely because its token lapsed, so it has nothing unexpired to present. Callers must bound the request some other way (the refresh handler gates on the session record and a signed challenge). Everywhere else, use VerifyAndExtractPeerID.
Types ¶
type IngressCallerResult ¶ added in v0.2.0
type IngressCallerResult struct {
Principal string
Roles []string
TaskName string
ActorNodeID string
IdentityFacts map[string][]string
}
IngressCallerResult describes an authorized external ingress caller.
func AuthorizeIngressDelegatedBiscuit ¶ added in v0.2.0
func AuthorizeIngressDelegatedBiscuit(claims *VerifiedBiscuitClaims, p IngressEvalParams) (*IngressCallerResult, error)
AuthorizeIngressDelegatedBiscuit authorizes a verified Delegated Session Biscuit or task-attenuated Task Biscuit (minted via RFC 8693 /oauth/token, POST /token/exchange, or SDK task attenuation) against mesh Datalog policy, local node attenuation, TAR blocks, and ServiceIngress.allow. Unattenuated standing member/router transport Biscuits are rejected.
type IngressEvalParams ¶ added in v0.2.0
type IngressEvalParams struct {
ServiceType string
ServiceName string
Method string
Path string
MCPTool string
AllowMCPStreamInit bool
TargetFacts []biscuit.Fact
MeshPolicyRules []biscuit.Rule
LocalPolicies []biscuit.Policy
LocalChecks []biscuit.Check
LocalRules []biscuit.Rule
Allow []string
Timeout time.Duration
}
IngressEvalParams configures Datalog + TAR + ServiceIngress.allow evaluation for an external HTTP ingress request in INGRESS_AUTH_MODE_EDGE. Method and Path are present on every ingress request (it is HTTP); the credential is a bearer over HTTPS, so there is no connection peer to bind it to.
type MeshPolicy ¶ added in v0.2.0
type MeshPolicy struct {
// TargetFacts are target_fact(type, value) facts from the provider's own
// credential (TargetFactsFromBiscuit); BaselineTargetCheck is always
// added, so a caller whose grant names a target the provider does not
// carry is refused, and so is every caller when the provider has none.
TargetFacts []biscuit.Fact
// LocalPolicies, LocalChecks and LocalRules are the enforcement point's
// own attenuation (agentmesh-node.yaml, or a PEP's static rules).
LocalPolicies []biscuit.Policy
LocalChecks []biscuit.Check
LocalRules []biscuit.Rule
// MeshRules are PolicyConfigGetResponse.datalog_rules as parsed.
MeshRules []biscuit.Rule
}
MeshPolicy is what the enforcement point adds to every evaluation on top of the credential: the provider's own target facts, its local attenuation, and the rules the control plane rendered from the mesh policy.
type MeshRequest ¶ added in v0.2.0
type MeshRequest struct {
// ServiceType and ServiceName are the service() fact: the service the
// request targets, or (api.SystemNamespace, <protocol>) for a bare stream
// that names no service.
ServiceType string
ServiceName string
// HasHTTP reports whether Method and Path were carried on the wire. They
// become method() and path() only then, so a grant narrowed to methods
// and paths (PolicyRole.http) has nothing to match on a bare stream and
// fails closed.
HasHTTP bool
Method string
Path string
// HasEgress reports whether the request is an egress call to
// EgressHost:EgressPort, which become host() and port().
HasEgress bool
EgressHost string
EgressPort int64
// Unrestricted adds target_unrestricted: the caller is this node's own
// sidecar, or the verifier has no provider identity to match target
// grants against (the control plane minting a border JWT).
Unrestricted bool
// ConnectionPeer, when set, is the libp2p peer the credential arrived
// from: connection_peer_id() and BaselineReplayCheck then bind
// client_peer_id to it, so an exfiltrated token cannot be replayed from
// another peer. It stays empty for a bearer presented over HTTPS at the
// border, where there is no libp2p connection to bind to
// (security-architecture, section 5.2).
ConnectionPeer peer.ID
// MCPTool and AllowMCPStreamInit describe the MCP call for
// TaskAuthorizationRule evaluation (TaskRequest).
MCPTool string
AllowMCPStreamInit bool
}
MeshRequest is what a policy enforcement point knows about one request, whichever path it arrived on: a mesh stream from another member, the node's own sidecar, router external ingress, or the control plane's /sts/token. Every PEP turns its request into one of these and hands it to AuthorizeMeshRequest, so the facts and checks a credential is evaluated against are decided in one place and a rule added for one path reaches the others. The fields a path does not have stay at their zero value, and the zero value always means "not present", never "unrestricted".
func (MeshRequest) TaskRequest ¶ added in v0.2.0
func (req MeshRequest) TaskRequest() api.TaskRequestContext
TaskRequest is req as TaskAuthorizationRule evaluation sees it, so the TAR intersection is computed from the same request on every path.
type UnknownIssuerError ¶ added in v0.1.1
type UnknownIssuerError struct {
Issuer string
}
UnknownIssuerError is returned by VerifyJWT when the token names an issuer that has no resolved provider: either one that was never configured, or one whose OpenID discovery has not succeeded yet. The caller tells the two apart.
func (*UnknownIssuerError) Error ¶ added in v0.1.1
func (e *UnknownIssuerError) Error() string
type VerifiedBiscuitClaims ¶
type VerifiedBiscuitClaims struct {
Biscuit *biscuit.Biscuit
VerifyingKey ed25519.PublicKey
User string
Email string
Groups []string
IdpRoles []string
Roles []string
Labels map[string]string
NodePeerID string
ActorNodePeerID string
ClientPeerID string
Expiration time.Time
RevocationIDs [][]byte
TaskRules []*api.TaskAuthorizationRule
}
VerifiedBiscuitClaims holds the authority facts, effective expiration, revocation IDs, and TaskAuthorizationRule chain extracted from a verified Biscuit token.
func InspectVerifiedBiscuit ¶
func InspectVerifiedBiscuit(biscuitData []byte, trustedPublicKeys []ed25519.PublicKey, timeout time.Duration) (*VerifiedBiscuitClaims, error)
InspectVerifiedBiscuit parses a Biscuit, validates its appended tar_block chain, verifies its signature and expiration against trustedPublicKeys, and extracts its authority claims and effective expiration.
func (*VerifiedBiscuitClaims) IdentityClaimsMap ¶ added in v0.2.0
func (c *VerifiedBiscuitClaims) IdentityClaimsMap() map[string][]string
IdentityClaimsMap returns the attested identity claims keyed by Datalog fact name ("user", "email", "group", "idp_role", "node") for policy/allow matching.
func (*VerifiedBiscuitClaims) InnermostTaskName ¶
func (c *VerifiedBiscuitClaims) InnermostTaskName() string
InnermostTaskName returns the name of the last appended TaskAuthorizationRule block, or "" if the token carries no appended blocks.
func (*VerifiedBiscuitClaims) Principal ¶
func (c *VerifiedBiscuitClaims) Principal() string
Principal returns the primary subject identifier for audit logs and border JWTs: Email when present, otherwise User, otherwise "node:<NodePeerID>" or "peer:<ClientPeerID>".