Documentation
¶
Overview ¶
Package compile turns a policy document into an immutable generation: the route table, permits, rate rules and compiled body and header schemas that every request is decided against.
A published generation is shared by concurrent requests, so the package exposes it only through read-only methods; nothing outside may change one. Compiling has no side effects: it never reads storage or the network, and it takes time only from the trusted clock it also owns. It imports only policy and fault. Any gateway package may call it.
Index ¶
- Constants
- Variables
- func CanonicalPath(r *http.Request) (string, bool)
- func CompileModule(c module.Control, op module.Operation, raw json.RawMessage) (check module.Check, err error)
- func CompileSchema(raw json.RawMessage, kind schemaKind, field string) (*jsonschema.Schema, map[string]any, error)
- func DeadlineNow() time.Time
- func DenyAll(p policy.Policy) bool
- func GenerationID(p policy.Policy, revision int64, notAfter time.Time, overrides []int64) string
- func IsCanonical(path string) bool
- func IsGatewayHeader(name string) bool
- func IsLoopbackDial(dial string) bool
- func TrustedNow() time.Time
- func TrustedTime(wall time.Time, elapsed time.Duration) time.Time
- type Answer
- type BodyRule
- type CORS
- type ControlChange
- type Destination
- type Generation
- func (g *Generation) Authorise(asserted []string, r *Rule) (roles, ignored []string, reason string)
- func (g *Generation) Conditioned(path, method string) bool
- func (g *Generation) Decide(q Question, blocked func() bool) Answer
- func (g *Generation) Expired(now time.Time) bool
- func (g *Generation) Match(path, method string, in Inbound) (*target, *Rule)
- func (g *Generation) Preflight(path, method string, in Inbound) (*Rule, bool)
- func (g *Generation) Roles() []string
- func (g *Generation) Rules() []*Rule
- type Inbound
- type ModuleCheck
- type Question
- type RateRule
- type ResponseRule
- type Rule
- func (r *Rule) API() string
- func (r *Rule) AddressAllowed(address string) bool
- func (r *Rule) Body() *BodyRule
- func (r *Rule) CORS() *CORS
- func (r *Rule) Checks(phase module.Phase) []ModuleCheck
- func (r *Rule) Counter() string
- func (r *Rule) Destination(path string) (d Destination, ok bool)
- func (r *Rule) Dial() string
- func (r *Rule) Headers() *headerRule
- func (r *Rule) Operation() string
- func (r *Rule) Permitted() bool
- func (r *Rule) PreflightRate() *RateRule
- func (r *Rule) Public() bool
- func (r *Rule) Rate() *RateRule
- func (r *Rule) RateKey() string
- func (r *Rule) Response() *ResponseRule
- func (r *Rule) Roles() []string
- func (r *Rule) Upstream() string
Constants ¶
const ( RateAlgorithm = "sliding-window" RateKeySubject = "subject" RateKeyAddress = "client_address" MaxRateCount = 1_000_000 MaxRateWindowSec = 86_400 // Subject and public-address cardinality is untrusted. A full table fails // closed; expired counters are swept without resetting live quotas. MaxCounters = 262144 // SweepInterval is how many admissions pass between removals of expired // counters. SweepInterval = 1024 )
const ( SchemaBody schemaKind = iota SchemaHeaders )
Variables ¶
var ProcessStart = time.Now()
ProcessStart anchors this process's monotonic clock to the wall clock once, at startup. It is never changed.
Functions ¶
func CanonicalPath ¶
CanonicalPath returns the single path interpretation used for matching and forwarding. Any encoding whose meaning could differ between the gateway and an upstream is rejected rather than normalised.
func CompileModule ¶
func CompileModule(c module.Control, op module.Operation, raw json.RawMessage) (check module.Check, err error)
CompileModule calls c's Compile, turning a panic into an error.
func CompileSchema ¶
func CompileSchema(raw json.RawMessage, kind schemaKind, field string) (*jsonschema.Schema, map[string]any, error)
CompileSchema accepts a JSON Schema 2020-12 document only if every keyword in it belongs to the supported subset, then compiles it with the library. Checking the subset first means no keyword is ever silently ignored. It also returns the decoded root object.
func DeadlineNow ¶
DeadlineNow is trustedNow for setting a deadline: a provisional base's or an override's. It first keeps any lead the wall clock has over the monotonic estimate, so a deadline set from a wall clock that is ahead is still reached after its own period if that clock is later set back. The cost is that, once the lead is kept, later timestamps stay that far ahead until a restart, and that restart waits for real time to pass them (the high-water check); the deadline's own record already carries the lead. Other readings, including every request, never raise it, so a brief forward step with no new deadline leaves no trace.
func DenyAll ¶
DenyAll reports whether the policy can admit no request at all: it holds no permits, so no authenticated request can pass RBAC, and no operation is both allowed and public. Only such a policy may become the first base of an installation or the base that ends a recovery.
func GenerationID ¶
GenerationID identifies a generation by its base revision, the overrides applied to it (as "+o<id>.<id>…") and a digest of the compiled document and deadline. A generation without overrides keeps the form "r<revision>-…".
func IsCanonical ¶
func IsGatewayHeader ¶
IsGatewayHeader reports whether only the gateway may set the named header.
func IsLoopbackDial ¶
IsLoopbackDial accepts only literal loopback addresses, so a destination can neither be resolved through DNS nor expanded from request placeholders.
func TrustedNow ¶
TrustedNow is the time against which every persisted deadline is decided and every controller timestamp is taken; see trustedTime.
func TrustedTime ¶
TrustedTime returns the later of the wall clock reading wall and the wall time the monotonic clock implies after elapsed since processStart, advanced by the wall clock's largest lead when a deadline was set. A deadline has passed once either clock reaches it: a wall clock set back cannot extend it, and neither can a monotonic clock that stood still across a system suspend. A wall clock set forward ends deadlines early, which is the safe direction. The monotonic estimate is anchored at process start, not at each publication, so republishing after a wall clock change cannot move a deadline either.
Types ¶
type Answer ¶
type Answer struct {
Allowed bool
Check string
Code string
Operation string // empty when no operation matched
API string
Public bool
Forwarded string // the path an allowed request reaches its upstream with
Roles []string
Ignored []string
// NotChecked lists the checks this answer could not make.
NotChecked []string
}
Answer is a question's decision. Check and Code name the refusing check (route, access, blocked, role, forward) and its error code; both are empty when the request would be allowed.
type BodyRule ¶
type BodyRule struct {
// contains filtered or unexported fields
}
BodyRule is a compiled body declaration.
type CORS ¶
type CORS struct {
// contains filtered or unexported fields
}
CORS is an API's compiled browser access.
type ControlChange ¶
ControlChange names one control and the target it applies to. It is the identity by which a candidate's effect on enforcement is reported, and by which a temporary override will be compared with a candidate.
func PolicyChanges ¶
func PolicyChanges(before, after policy.Policy) []ControlChange
PolicyChanges lists, in a stable order, every control target whose definition differs between two complete policies: an upstream, API, operation (route, method, access, authentication, body and header rules), its rate rule, a role or a permit (role and operation).
type Destination ¶
type Destination struct {
// contains filtered or unexported fields
}
Destination is where an admitted request goes: its upstream's address and the path it is forwarded with. Only Rule.Destination makes one, after the rewritten path passed the canonical-path check, so a forwarder bound to a Destination cannot be handed an unchecked path.
func (Destination) Dial ¶
func (d Destination) Dial() string
Dial is the upstream's loopback address.
func (Destination) Path ¶
func (d Destination) Path() string
Path is the canonical path the request is forwarded with.
type Generation ¶
type Generation struct {
ID string
Revision int64
Profile string
// Overrides lists, in order, the temporary overrides applied to the base
// revision.
Overrides []int64
// NotAfter, when set, is the earliest persisted deadline the generation
// depends on (a provisional base's confirmation deadline or an override's
// expiry), after which it must no longer admit requests even if the
// controller has not yet replaced it.
NotAfter time.Time
// contains filtered or unexported fields
}
Generation is an immutable compiled effective policy. Requests capture one generation and never observe another.
func Compile ¶
Compile validates a complete policy and builds its generation. It either returns a complete generation or an error; it never returns a partial one. It has no side effects. A non-zero notAfter is the earliest persisted deadline the generation depends on.
func (*Generation) Authorise ¶
func (g *Generation) Authorise(asserted []string, r *Rule) (roles, ignored []string, reason string)
Authorise retains only declared roles from already verified claims. Unknown roles are returned for audit; a subject name never creates a permission.
func (*Generation) Conditioned ¶
func (g *Generation) Conditioned(path, method string) bool
Conditioned reports whether the method on the path's target has conditioned operations, so the operation depends on host and headers.
func (*Generation) Decide ¶
func (g *Generation) Decide(q Question, blocked func() bool) Answer
Decide answers q with g. blocked reports whether the account asked about is on the blocked list; it is asked only for a protected operation.
func (*Generation) Expired ¶
func (g *Generation) Expired(now time.Time) bool
Expired reports whether the generation's earliest deadline has passed at now, a reading of trustedNow.
func (*Generation) Match ¶
func (g *Generation) Match(path, method string, in Inbound) (*target, *Rule)
Match selects the most specific target for a canonical path, then the method on that target only, then among that method's operations the one with the most conditions the request meets, else the unconditioned one. A less specific target is never consulted for a missing method. When the method has only conditioned operations and none holds, no target matches.
func (*Generation) Preflight ¶
func (g *Generation) Preflight(path, method string, in Inbound) (*Rule, bool)
Preflight returns the rule a CORS preflight's requested method selects on the path, as Match would for the actual request, and whether the path's target has an operation of an API with browser access; only then does the gateway answer the preflight.
func (*Generation) Roles ¶
func (g *Generation) Roles() []string
Roles lists, sorted, the roles the generation's policy declares.
func (*Generation) Rules ¶
func (g *Generation) Rules() []*Rule
Rules lists every compiled endpoint rule of a generation once.
type Inbound ¶
Inbound is what a request offers to conditions: its Host value as received (any case, any port) and its header fields.
type ModuleCheck ¶
ModuleCheck is one module's compiled check.
type Question ¶
type Question struct {
// contains filtered or unexported fields
}
Question is a checked request description. Only NewQuestion makes one, so every question has passed the request handler's own input checks.
func NewQuestion ¶
func NewQuestion(method, path, host string, headers map[string]string, roles []string) (q Question, field string)
NewQuestion checks a request description: the method, the path in the form the handler accepts, the roles standing for a verified token's, and the host and headers conditions select by. field names the refused input.
type RateRule ¶
type RateRule struct {
// contains filtered or unexported fields
}
RateRule is a compiled rate rule: at most count requests per window milliseconds for each verified subject or each direct client address.
type ResponseRule ¶
type ResponseRule struct {
// contains filtered or unexported fields
}
ResponseRule is an API's compiled response header rule.
func (*ResponseRule) Apply ¶
func (r *ResponseRule) Apply(h http.Header, tls bool)
Apply removes the listed headers and adds each security header the response does not already have. Strict-Transport-Security is added only to a response sent over TLS.
func (*ResponseRule) HSTS ¶
func (r *ResponseRule) HSTS() bool
HSTS reports whether the API asks for Strict-Transport-Security.
type Rule ¶
type Rule struct {
// contains filtered or unexported fields
}
func (*Rule) AddressAllowed ¶
AddressAllowed reports whether the API's allow list admits the client address; an address that does not parse is never admitted by a list.
func (*Rule) Checks ¶
func (r *Rule) Checks(phase module.Phase) []ModuleCheck
Checks returns the module checks of the rule that run in phase, in ID order; none for a module not configured for the operation.
func (*Rule) Counter ¶
Counter is the operation whose rate counter the rule counts on: its own, or for a conditioned operation its unconditioned sibling's.
func (*Rule) Destination ¶
func (r *Rule) Destination(path string) (d Destination, ok bool)
Destination returns where a request admitted on the canonical inbound path is forwarded. The path is the inbound path without the strip prefix, after the add prefix ("/" when nothing is left), and must be canonical again; otherwise ok is false and the request must not be forwarded.
func (*Rule) Headers ¶
func (r *Rule) Headers() *headerRule
Headers is the compiled header schema; nil when there is none.
func (*Rule) PreflightRate ¶
PreflightRate is the rate rule that limits CORS preflights to the rule's API, per client address; nil when no public operation has one.
func (*Rule) Response ¶
func (r *Rule) Response() *ResponseRule
Response is the response header rule of the rule's API; nil when it has none.