Documentation
¶
Overview ¶
Package kmsbridge is notify's direct line to Hanzo KMS, and the ONE place in notify that resolves a secret. Every per-brand provider credential — Twilio, Plivo, SendGrid — is read here at send time.
Canonical KMS routes (luxfi/kms post-canonical-migration):
- GET/DELETE: /v1/kms/orgs/{org}/secrets/{path}/{name}
- POST: /v1/kms/orgs/{org}/secrets (body: {path, name, value})
Transport: KMS is an HTTP service (kms.hanzo.svc:80 in-cluster, https://kms.hanzo.ai externally). It exposes ONLY the HTTP secrets API above — it is NOT a base-collections endpoint, so it does not speak the base ZAP record protocol. notify itself runs on the ZAP service mesh (its base app exposes records over ZAP, and it reaches tasks over ZAP), and the fleet's secret-access convention is written as a `zap://` endpoint for uniformity. NormalizeEndpoint reconciles the two: a `zap://host[:port]` KMS endpoint is resolved to the KMS HTTP service (scheme http, the ZAP :9999 port dropped — KMS has no ZAP listener), so secret reads route correctly regardless of which scheme the deployment hands us. This is the single seam where the mesh-style config meets KMS's HTTP API.
Auth: IAM client_credentials grant at /v1/iam/oauth/access_token. The bearer is cached in-process until 60s before expiry. A static KMS_AUTH_TOKEN overrides the exchange — used by tests.
The base/plugins/platform.KMSClient surface is kept identical (GetSecret/SetSecret/DeleteSecret/InvalidateCache) so callers can swap the import path without rewriting call sites.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NormalizeEndpoint ¶ added in v1.6.17
NormalizeEndpoint turns any endpoint spelling the fleet uses into the concrete HTTP base URL the bridge dials. It is the single seam where a mesh-style `zap://` secret endpoint meets KMS's HTTP secrets API:
- "" → "" (IAM may be empty when StaticBearer set)
- "zap://kms.hanzo.svc:9999" → "http://kms.hanzo.svc" (scheme→http, ZAP port dropped)
- "zap://kms.hanzo.svc" → "http://kms.hanzo.svc"
- "http://kms.hanzo.svc" → unchanged
- "https://kms.hanzo.ai" → unchanged
- "kms.hanzo.svc" → "http://kms.hanzo.svc" (bare host defaults to http)
A trailing slash is always trimmed. KMS speaks no ZAP record protocol, so we never dial :9999 for secrets — keeping the bogus port would just hang every read.
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://.hanzo.svc.cluster.local:8443").
KMSEndpoint string
// IAMEndpoint is the IAM server URL (e.g.
// "http://.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).