gateway

package
v0.44.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 15, 2026 License: Apache-2.0 Imports: 29 Imported by: 0

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

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.

func NewLakeKeys

func NewLakeKeys(master []byte, s store.Store) LakeKeys

NewLakeKeys builds the production LakeKeys over the node master and the metastore.

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

func NewManager(host string, keys LakeKeys, pdp auth.Authorizer, log *slog.Logger) *Manager

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL