Documentation
¶
Overview ¶
Package kmsbridge is notify's direct line to Hanzo KMS.
Why this exists separately from `github.com/hanzoai/base/plugins/platform` (which also exposes a KMSClient): notify pins `github.com/hanzoai/base v1.3.0`, whose platform.KMSClient still targets the legacy Infisical URL shape (`/api/v1/secrets/{orgId}/{secretPath}`). The canonical Hanzo KMS daemon serves at `/v1/kms/orgs/{org}/secrets/{path}/{name}`, and IAM serves machine tokens at `/v1/iam/oauth/access_token`. Bumping base across the 2400+ commits between v1.3.0 and main would carry an unbounded blast radius for one bug, so this package is the surgical fix: a tiny, self-contained HTTP client that hits the canonical routes directly.
Public API (Client.GetSecret / SetSecret / DeleteSecret / InvalidateCache) is intentionally identical to `github.com/hanzoai/base/plugins/platform.KMSClient` so callers can swap the import path and otherwise leave the call sites alone.
Auth: IAM client_credentials grant against IAM_CLIENT_ID + IAM_CLIENT_SECRET (envs). The bearer is cached in-process until 60s before expiry. A static KMS_AUTH_TOKEN overrides the exchange — used by tests.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is the bridge type. Safe for concurrent use. One per process is enough; the cache amortizes the IAM token exchange and the secret reads across goroutines.
func New ¶
New returns a configured bridge. Returns an error if KMSEndpoint is blank or, when StaticBearer is empty, if any IAM field is missing — those are programmer errors caught at boot rather than at first send.
func (*Client) DeleteSecret ¶
DeleteSecret removes a secret. 404 from KMS is treated as success (idempotent delete) per the platform.KMSClient contract.
func (*Client) GetSecret ¶
GetSecret fetches one secret value for (orgId, secretPath). secretPath looks like "brand/hanzo/plivo/auth-id" — the last segment is the secret name and everything before it is the directory.
The 1-minute cache amortizes hot-path repeats (e.g. Plivo creds on every SMS). On a fresh process the first read pays the full IAM token exchange + KMS round trip; subsequent reads inside the TTL are a map lookup.
func (*Client) InvalidateCache ¶
InvalidateCache drops every cached entry under the given org. Called after a write so the next read goes back to KMS.
type Config ¶
type Config struct {
// KMSEndpoint is the KMS server URL (e.g.
// "http://kms.hanzo.svc.cluster.local:8443").
KMSEndpoint string
// IAMEndpoint is the IAM server URL (e.g.
// "http://iam.hanzo.svc.cluster.local:8000"). The bridge
// POSTs `IAMEndpoint + "/v1/iam/oauth/access_token"` to exchange
// client_credentials for a bearer.
IAMEndpoint string
// ClientID is the IAM application client_id used for the
// client_credentials grant.
ClientID string
// ClientSecret is the IAM application client_secret.
ClientSecret string
// StaticBearer, when non-empty, suppresses the IAM exchange and is
// sent verbatim on every KMS request. Reserved for tests.
StaticBearer string
// HTTPClient is an optional override; nil → 15s-timeout default.
HTTPClient *http.Client
}
Config captures the (env-derived) inputs the bridge needs to mint tokens against IAM and call KMS. All fields are required except HTTPClient (which defaults to a 15s-timeout http.Client) and StaticBearer (an opaque override that bypasses the IAM exchange — set it from KMS_AUTH_TOKEN when tests want a fixed bearer).