Skip to main content

Module auth

Module auth 

Source
Expand description

x-lane QoS (lane/dl-metering gate, QoS-only extraction 2026-08-02): lane types, SLO admission policy, engine-truth step stats live in the memra-lanes crate so out-of-process controllers (the sidecar shape) can share them.

pub: the key file format, lifecycle helpers, and single-key path are the API a deployment-owned binary provisions against (engine-billing-extraction-20260829). API-key management (lane/api-keys, 2026-08-05): multi-key bearer auth that maps key -> tenant, so metering, QoS lane class, and prefix-cache isolation key off a real tenant identity instead of one shared trust domain.

DESIGN (launch-shaped, not enterprise-shaped):

  • Keyring source: MEMRA_API_KEYS — a TOML file path ([[keys]] entries, see KeyEntry) or an inline env list tenant:sha256hex[:lane],... for file-less deploys. Keys are stored as SHA-256 hex ONLY — the plaintext exists exactly once, on the --gen-key terminal.
  • Hot reload: mtime-poll (default 2s throttle) on every lookup — chosen over SIGHUP because it needs no signal thread and cannot be missed; a bad reload keeps the old ring and logs loudly (auth never degrades to open because of a typo).
  • Back-compat: MEMRA_API_KEY (the single static bearer — the owner’s daily driver and every serve script) keeps working unchanged as tenant "default", with or without a keyring configured. No keyring + no single key = open (dev behavior).
  • Tenant -> cache namespace: when a keyring is configured, every request’s PC-ISO namespace is t:<tenant>\x1f<cache_salt> (see scope_namespace). Tenant ids are validated [A-Za-z0-9_-]+, so the \x1f separator cannot be forged from a client-controlled cache_salt — cross-tenant cache probing is structurally impossible. Keyring ABSENT keeps the raw-salt namespace, byte-identical to PC-ISO.
  • Lane class: a key is interactive (default) or batch. Batch-class keys default to the harvest QoS lane and are refused the protected interactive lane (403, loud — never a silent downgrade, per the honesty doctrine).
  • Per-key rate_limit: optional concurrency-slot override; the effective cap is min(override, global lane cap) — the global cap stays authoritative.

CLI (--gen-key / --revoke-key, see run_cli): prints the plaintext once and appends the hash entry; revoke flips enabled = false by key prefix. No web UI.

Structs§

KeyEntry
One keyring entry — the on-disk TOML shape ([[keys]]).
KeyStore
The live keyring: source + hot-reload state. File-backed rings re-stat on lookup (throttled to poll) and swap in the new ring when mtime moves; a reload that fails to parse KEEPS the old ring and logs the error (never fail-open, never flap).
Keyring
Parsed keyring. Request-time lookup scans fixed-length digests with constant-time equality rather than relying on short-circuit String/HashMap key comparison.
TenantCtx
The resolved identity a request acts as — what flows to cache scoping, lane admission, rate-limit headers, and the usage/meter log line.

Enums§

AuthDenied
Why a presented key was refused. Unknown -> 401, Disabled -> 403.
LaneClass
A key’s QoS lane class. Interactive keys behave exactly like pre-lane traffic (default lane interactive, any x-lane honored). Batch keys default to the harvest lane and may not claim the protected interactive lane.

Functions§

authenticate_with
The full auth law, pure over its inputs (unit-testable without env): keyring key match -> that key’s tenant (or Disabled -> 403) single static key match-> tenant “default” (the back-compat daily driver) nothing configured -> open, tenant “default” anything else -> Unknown -> 401 The keyring and the single key COMPOSE: setting MEMRA_API_KEYS does not break MEMRA_API_KEY callers (the owner’s serve scripts keep working unchanged).
constant_time_secret_eq
Compare secrets without length- or prefix-dependent early exit. Hashing first gives the comparison a fixed 32-byte shape even when callers supply different-length values.
gen_key
Generate a key for tenant, print the plaintext ONCE, append the hash entry to the keys file (created if missing). Returns the plaintext (for tests).
global
The global keystore, if MEMRA_API_KEYS configured one.
init_from_env
Called once from main() before serving. Exits the process on a bad config.
install_key
Install an already-generated key into a ring. This is the fleet fan-out primitive: one control-plane key can be installed byte-identically on every serving origin without making any serving host the authority for the others. Replaying the exact same entry is idempotent; a prefix collision with different material or policy fails closed.
meter_key
The per-tenant METERING key for a PC-ISO namespace (lane/cache-metering): the tenant half of scope_namespace — keyring deployments aggregate one row per tenant across all its end-user salts; no-keyring namespaces (the raw salt) pass through unchanged (“” = the default single-tenant namespace). Unforgeable for the same reason scope_namespace is: NS_SEP is excluded from tenant ids, so a salt can never move its tokens into another tenant’s row.
revoke_key
Disable every key whose prefix starts with handle (or whose sha256 matches the handle’s hash, if a full plaintext key was pasted). Exactly one match required — ambiguity is an error, not a mass revoke. Rewrites the file (comments not preserved).
run_cli
CLI dispatch: handles --gen-key / --revoke-key if present, returning the exit code; None = no key-management args, boot the server normally.
scope_namespace
PC-ISO namespace scoping: with a keyring configured, a request’s cache namespace is t:<tenant>\x1f<salt> — a tenant’s keys share cache; different tenants never do; a client-controlled salt cannot cross the \x1f boundary (tenant ids exclude it). Without a keyring the raw salt passes through, byte-identical to PC-ISO behavior.
sha256_hex
SHA-256 of a plaintext key, lower-case hex — the only form a key is ever stored in.
tenant_is_valid