Documentation
¶
Overview ¶
Package kmskeyring binds store.RootSource to Hanzo KMS.
Each org's 32-byte KEK is held in KMS under one fixed secret name, scoped per org. The KEK is the ONLY key material in KMS; the per-DB data keys are random age identities wrapped under it by store.Keyring and stored as sidecars next to the DBs (envelope encryption). Rotating an org KEK in KMS therefore never rewrites a DB — see store.Keyring.Rotate.
Wiring ¶
kmskeyring depends only on the minimal SecretStore contract so the store substrate stays orthogonal to any specific KMS transport. Production wires the canonical Base→KMS facade (plugins/platform.KMSClient) with a trivial adapter:
type kmsAdapter struct{ c *platform.KMSClient }
func (a kmsAdapter) Get(_ context.Context, org, name string) (string, error) {
v, err := a.c.GetSecret(org, name)
if isNotFound(err) { return "", kmskeyring.ErrNotFound }
return v, err
}
func (a kmsAdapter) Put(_ context.Context, org, name, val string) error {
return a.c.SetSecret(org, name, val)
}
src, _ := kmskeyring.New(kmsAdapter{c: kmsClient})
keyring, _ := store.NewKeyring(src, objectStore)
mtStore, _ := store.New(store.Options{ObjectStore: objectStore, Keys: keyring})
Index ¶
Constants ¶
const KEKSecretName = "base/store-kek"
KEKSecretName is the fixed KMS secret leaf holding an org's store KEK. One KEK per org; the secret's org scoping is the SecretStore's responsibility.
Variables ¶
var ErrNotFound = errors.New("kmskeyring: secret not found")
ErrNotFound signals an absent secret. Adapters MUST map their backend's not-found to this (via errors.Is) so OrgRoot can create-on-first-use.
Functions ¶
This section is empty.
Types ¶
type SecretStore ¶
type SecretStore interface {
Get(ctx context.Context, orgID, name string) (string, error)
Put(ctx context.Context, orgID, name, value string) error
}
SecretStore is the minimal, per-org KMS surface kmskeyring needs. Implementations are goroutine-safe. Get returns ErrNotFound (errors.Is) when the named secret is absent for the org.
type Source ¶
type Source struct {
// contains filtered or unexported fields
}
Source implements store.RootSource over a SecretStore.
func New ¶
func New(kms SecretStore) (*Source, error)
New builds a Source over kms, using the canonical KEK secret name.
func (*Source) OrgRoot ¶
OrgRoot returns the org's 32-byte KEK, creating and persisting a fresh random KEK in KMS on first use, and returning a fresh copy each call (the caller may zero it).
Create-on-first-use is a convenience for the lazy path; the correct production posture is to PROVISION the KEK once at org-creation time under a single writer (or via a KMS compare-and-set Put) so two pods can never race two different KEKs into existence. On a create race with a last-writer-wins backend, both pods converge by re-reading the authoritative value here.