Documentation
¶
Overview ¶
Package gateway is the funcd lake PEP proxy over the Quack/DuckLake serving path (ADR-0137, FEAT-0008/F102). It brings lake under the same per-caller, per-query Cedar PEP as blob/kv/S3, for BOTH caller classes, by putting funcd on the query path via a proxy that fronts the engine — the S3 gateway shape (ADR-0085/0088): one proxy door, a per-caller credential resolved to a Cedar principal, a per-op PEP, the real backend credential (the shared engine token) used only after allow.
A Quack token is a BARE BEARER credential (unlike an S3 access key, which is inert without the SigV4 secret), so the internal per-function token must be unforgeable on its own. It is a standard HS256 JWT (go-jose) signed with the node master: DeriveLakeToken signs it, PrincipalFor verifies the signature (alg pinned to HS256) before trusting its {ns, fn} claims. The external Identity gets a minted token: its public access key id (ADR-0135), ".", and a random, rotatable part. The prefix names the owner, so the lookup is two store reads (ADR-0153), the shape of the Identity's S3 credential lookup.
Index ¶
- func DeriveLakeToken(master []byte, ns v1.NamespaceName, fn v1.ObjectName) (string, error)
- func IdentityLakeToken(ns v1.NamespaceName, name v1.ObjectName, random string) string
- func NewLakeProxy(keys LakeKeys, pdp auth.Authorizer, engine EngineTarget, log *slog.Logger) http.Handler
- type EngineTarget
- type LakeKeys
- type Manager
- func (m *Manager) Ensure(lake auth.EntityRef, upstream, engineToken, saveURL string) (string, error)
- func (m *Manager) Listen(ns v1.NamespaceName, name v1.ObjectName, port int) (bound int, moved bool, err error)
- func (m *Manager) ProxyURL(ns v1.NamespaceName, name v1.ObjectName) (string, bool)
- func (m *Manager) Release(ns v1.NamespaceName, name v1.ObjectName)
- func (m *Manager) Released(ns v1.NamespaceName) []v1.ObjectName
- func (m *Manager) Remove(ns v1.NamespaceName, name v1.ObjectName)
- func (m *Manager) SaveURL(ns v1.NamespaceName, name v1.ObjectName) (string, bool)
- func (m *Manager) Shutdown()
- func (m *Manager) Suspend(ns v1.NamespaceName, name v1.ObjectName)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DeriveLakeToken ¶
func DeriveLakeToken(master []byte, ns v1.NamespaceName, fn v1.ObjectName) (string, error)
DeriveLakeToken mints the per-(namespace, function) lake token as an HS256 JWT signed with the node master (ADR-0137). A Quack token is a bare bearer credential, so it must be unforgeable on its own: only the master holder can produce the signature, so a function cannot forge a peer's token. Deterministic — the same (master, ns, fn) always yields the same compact JWT (no time claims), so injection re-derives it without stored state.
func IdentityLakeToken ¶
func IdentityLakeToken(ns v1.NamespaceName, name v1.ObjectName, random string) string
IdentityLakeToken builds an Identity's lake token (ADR-0153): its access key id, ".", random.
func NewLakeProxy ¶
func NewLakeProxy(keys LakeKeys, pdp auth.Authorizer, engine EngineTarget, log *slog.Logger) http.Handler
NewLakeProxy builds the lake PEP proxy handler fronting one Lake engine (ADR-0137). It logs through log (nil means slog.Default()), as the Manager's proxies log through its logger (ADR-0002 §6).
Types ¶
type EngineTarget ¶
type EngineTarget struct {
Lake auth.EntityRef // Type=KindLake, Namespace/Name = the fronted Lake
Upstream string // the netns engine endpoint (an http URL)
EngineToken string // the shared engine token, never exposed to callers
SaveURL string // the engine's save endpoint; "" when lake.saveInterval is set: no barrier (ADR-0279)
}
EngineTarget is the single Lake this proxy endpoint fronts (ADR-0137): its Cedar resource ref (the lake::query resource, namespace and name both fixed by the endpoint), its netns engine URL, and the shared engine token the caller token is swapped for on allow. One EngineTarget per listener endpoint, so the target lake is fixed by the endpoint (never parsed from the opaque Quack body).
The ADR Contracts sketch typed Lake as `v1.EntityRef`; there is no such type — the PDP resource is auth.EntityRef (a Lake ref), which is what this carries.
type LakeKeys ¶
type LakeKeys interface {
// PrincipalFor resolves token to its principal. First: verify it as an HS256 JWT signed with the node
// master (a forged {ns, fn} fails the signature) ⇒ a Function principal. Else: decode the owner an
// Identity token's prefix names and read that Identity and its Secret (two Gets) ⇒ an Identity
// principal. Else: default-deny (ok=false).
PrincipalFor(token string) (auth.EntityRef, bool)
}
LakeKeys resolves a presented lake token to its Cedar principal (ADR-0137). It mirrors s3gateway.principalFor, with the JWT signature standing in for SigV4's per-request possession proof.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager owns the per-Lake lake PEP proxies (ADR-0137): it runs ONE node-private http.Server per lake, each fronting that lake's engine. The Lake reconciler calls Listen on every pass to bind the lake's listener on its recorded port (ADR-0162), Ensure on its Ready branch to target the engine, Suspend while it is not Ready, and Release on delete; it calls Remove only once no Function binds a deleted lake, so the URL internal functions are injected with (FUNCD_LAKE_<ALIAS>_URL) never changes within a daemon run. One listener endpoint per lake fixes the PEP's target lake by the endpoint (the proxy takes the namespace from the resolved principal — see NewLakeProxy).
func NewManager ¶
NewManager builds the lake proxy Manager over the shared token resolver + PDP (ADR-0137). The same LakeKeys/Authorizer back every per-lake proxy; each proxy differs only in its EngineTarget (the lake ref + its netns engine URL + shared engine token). host is the address each proxy binds and publishes (see Manager); empty ⇒ 127.0.0.1.
func (*Manager) Ensure ¶
func (m *Manager) Ensure(lake auth.EntityRef, upstream, engineToken, saveURL string) (string, error)
Ensure guarantees a node-private proxy is running for lake, fronting upstream with engineToken, and returns the bare "<host>:<port>" host:port the function injects as FUNCD_LAKE_<ALIAS>_URL (its handler wraps it in quack://; the engine endpoint was bare too). If a proxy already runs for the lake it is reused (idempotent — a re-reconcile does not rebind); if the upstream or engineToken differs, the running proxy is retargeted in place and its URL stays the same. Thread-safe.
func (*Manager) Listen ¶
func (m *Manager) Listen(ns v1.NamespaceName, name v1.ObjectName, port int) (bound int, moved bool, err error)
Listen binds the lake's listener on port, its recorded status.proxyPort, unless one is bound in this daemon run (ADR-0162). When port is 0 or that bind fails it binds a new port; moved reports a failed non-zero bind. A new listener answers 503 until Ensure targets the engine; a bound one stops being released. A failed last bind is fault.Unavailable.
func (*Manager) ProxyURL ¶
func (m *Manager) ProxyURL(ns v1.NamespaceName, name v1.ObjectName) (string, bool)
ProxyURL returns the bare "<host>:<port>" of the lake's listener when one is bound in this daemon run, and false when none is: a restarted daemon binds none until the lake's first pass, so a URL stored before the restart may be dead (#662, ADR-0162).
func (*Manager) Release ¶
func (m *Manager) Release(ns v1.NamespaceName, name v1.ObjectName)
Release suspends a deleted lake's listener as Suspend does and marks it released: its URL stays bound for the Functions that bind the lake until Remove closes it (ADR-0162). Releasing an unknown lake is a no-op.
func (*Manager) Released ¶
func (m *Manager) Released(ns v1.NamespaceName) []v1.ObjectName
Released returns the lakes of ns whose listener is released, sorted.
func (*Manager) Remove ¶
func (m *Manager) Remove(ns v1.NamespaceName, name v1.ObjectName)
Remove stops and forgets the proxy for a lake (ADR-0137 teardown path). Idempotent: removing an unknown lake is a no-op.
func (*Manager) SaveURL ¶ added in v0.29.0
func (m *Manager) SaveURL(ns v1.NamespaceName, name v1.ObjectName) (string, bool)
SaveURL is the save endpoint the lake's proxy calls before it answers (ADR-0279), "" for none; false when the lake has no proxy.
func (*Manager) Shutdown ¶
func (m *Manager) Shutdown()
Shutdown stops every running proxy (daemon shutdown). Thread-safe and idempotent.
func (*Manager) Suspend ¶
func (m *Manager) Suspend(ns v1.NamespaceName, name v1.ObjectName)
Suspend keeps a lake's listener, so the URL consumers were injected with stays valid (#59), but answers every request 503 and drops the engine target and token until Ensure retargets it: a not-Ready lake serves no caller (#372). Suspending an unknown lake is a no-op.