byok

package
v0.7.1 Latest Latest
Warning

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

Go to latest
Published: Aug 9, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package byok is the gateway's bring-your-own-key store: customer provider API keys in GCP Secret Manager, one secret per (org, user, provider), named byok--<org>--<user>--<provider>. The gateway's runtime service account is the ONLY principal with access to the byok-- namespace (IAM-conditioned at deploy). Supabase holds display metadata only — never key material — so this package is the single place raw customer keys exist at rest.

Hygiene rules enforced here: key material never appears in errors or logs, and callers get at most (key, version) — nothing else to leak.

Index

Constants

This section is empty.

Variables

View Source
var ErrDisabled = fmt.Errorf("byok store not configured")

ErrDisabled is returned by a nil store — BYOK not configured in this environment.

View Source
var ErrNotFound = fmt.Errorf("no key stored")

ErrNotFound is returned when no key exists for (org, user, provider).

Functions

func Validate

func Validate(ctx context.Context, provider, key string) error

Validate test-calls the provider with the key. nil = the key authenticated. The error message is user-facing and NEVER contains the key.

Types

type Resolver

type Resolver struct {
	// contains filtered or unexported fields
}

Resolver implements provider.ByokKeys over the Secret Manager store with short TTL caches, so the hot path costs zero Secret Manager calls for repeat turns:

key cache   5 min  (positive; version-tagged so rotation reconstructs clients)
miss cache  60 s   (presence gate said yes but the secret is gone — metadata drift)
invalid     60 s   (a vendor auth-rejected the key: fail FAST with the same
                    actionable error instead of re-burning a vendor call per
                    turn; after the TTL the real key is tried again in case
                    the user fixed it)

Cross-instance coherence is TTL-bounded (each Cloud Run instance has its own caches); the local instance's Invalidate makes the user's own PUT/DELETE take effect immediately where they did it.

func NewResolver

func NewResolver(store *Store) *Resolver

NewResolver wraps the store; a nil store yields a nil resolver (BYOK off).

func (*Resolver) Invalidate

func (r *Resolver) Invalidate(org, user, vendor string)

Invalidate clears all local cache state for (org, user, vendor) — called by the PUT/DELETE handlers so the user's own instance reflects the change immediately. Other instances converge within the TTLs.

func (*Resolver) Key

func (r *Resolver) Key(ctx context.Context, org, user, vendor string) (string, string, error)

Key returns the user's live key for vendor. provider.ErrKeyInvalid = the key was recently auth-rejected (fast-fail); ErrNotFound = presence-gate drift (secret missing).

func (*Resolver) MarkInvalid

func (r *Resolver) MarkInvalid(org, user, vendor string)

MarkInvalid records a vendor auth rejection: subsequent turns fail fast for invalidTTL with the same actionable message.

type SMClient

SMClient is the narrow slice of the Secret Manager client the store uses — an interface so tests run against a fake instead of GCP.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store reads/writes customer provider keys in Secret Manager.

func NewStore

func NewStore(ctx context.Context) (*Store, error)

NewStore builds the store with ambient Cloud Run credentials. Returns (nil, nil) when GOOGLE_CLOUD_PROJECT is unset (local dev without GCP) — a nil *Store is "BYOK disabled" and every method fails cleanly.

func NewStoreWithClient

func NewStoreWithClient(c SMClient, project string) *Store

NewStoreWithClient wires an explicit client — the test seam.

func (*Store) AccessLatest

func (s *Store) AccessLatest(ctx context.Context, org, user, provider string) (key, version string, err error)

AccessLatest returns the live key + its version id for (org, user, provider). ErrNotFound when the user has no key for that provider.

func (*Store) Delete

func (s *Store) Delete(ctx context.Context, org, user, provider string) error

Delete removes the secret entirely. A missing secret is success (idempotent — deletes may race between www and the CLI).

func (*Store) Put

func (s *Store) Put(ctx context.Context, org, user, provider, key string) (string, error)

Put stores (or replaces) the key for (org, user, provider), returning the new version id. Prior versions are destroyed — exactly one live version per secret, no residue of rotated-away keys.

Jump to

Keyboard shortcuts

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