ADR-0003 · Push-based secret rotation and cloud secret-manager adapters (candidate)
Status: proposed (candidate), revision 0.1 (2026-05-15) · Full normative text
:::caution Planned API — Phase 3 candidate
This ADR is a tracking placeholder for the Phase 3 discussion.
No normative decisions are made here; the page documents the shape
of the open questions so context7 and operators know which names
are reserved across bindings. None of the types or hooks described
on this page exist in the v0.4 / v0.5 bindings yet. The candidate
becomes binding only when every open question has an accepted
answer and the status flips to accepted.
:::
The "candidate" status borrows the convention used by IETF Internet-Drafts: issues raised against the document are tracked here, addressed through revisions, and the ADR is promoted only when the design is stable enough to bind implementations.
Why a separate ADR
ADR-0002 landed Phase 2 of the secrets surface: a pull-based
SecretSource contract, EnvSecretSource and VaultSource
adapters, lazy SecretRef resolution, and Config.refresh_secrets()
for operator-driven rotation. Token-renewal background tasks and
push-based change notification were explicitly deferred.
The deferral rests on two arguments:
- No production data yet. Until at least one operator runs the Phase 2 surface against rotation cadences observed in real deployments, every choice (poll interval, notification fan-out, retry / back-off, multi-region replicas) is design by guesswork.
- Subscription model still settling. ADR-0001 §7 specifies a subscription contract but Phase 1 bindings return an inactive handle. Implementing real subscriptions for config changes lands before secret subscriptions to reuse the plumbing.
Scope (four loosely coupled areas)
Phase 3 covers four areas. Each can land independently (separate PRs against this ADR), but the design choices in one affect the others enough to keep them in a single document.
A. Push-based rotation channel
ADR-0002 §11 sketched an on_secret_change(scheme, path, callback)
extension to the existing Subscription handle from ADR-0001 §7.2.
The Phase 3 question set:
- What does the
SecretChangeEventpayload look like (path, scheme, source_id, new value vs notification-only)? - Which backends push? Vault Agent caching + lease watcher, AWS-SM EventBridge events, GCP Secret Manager Pub/Sub, K8s informer. Each has a different latency profile (Vault: seconds; AWS-SM: 10–60 s through EventBridge; Kubernetes: watch-based, sub-second).
- Fall-back to polling when push is unavailable.
- Coalescing semantics — rapid back-to-back rotations within a single TTL window should produce one operator-visible event, not N.
B. Cloud secret-manager adapters
_meta/secret_schemes.yaml reserves three Phase 3 schemes:
awssm→AwsSecretsManagerSource— JSON-typed secrets, versioning (AWSCURRENT/AWSPENDING/AWSPREVIOUS), rotation lambdas, IAM-based auth.gcpsm→GcpSecretManagerSource— versioned secrets, per-key IAM, multi-region replicas, resource-name addressing (projects/<p>/secrets/<n>/versions/<v>).k8ssecret→K8sSecretSource— in-clusterSecretobjects, namespace-scoped RBAC, watch-based change notification.
Each adapter mirrors VaultSource in shape (lazy resolve, JSON
envelope handling, #field projection, optional ?version= query),
but the auth model and the rotation-notification channel differ.
C. Token-renewal background hooks
Phase 2 deferred renewal entirely (see per-binding ADRs:
config-python/adr/0001-vault-source.md §4,
config-typescript/adr/0001-vault-source.md §4,
config-go/adr/0001-vault-source.md §4). Phase 3 introduces:
- An optional
start()/close()lifecycle onSecretSourcefor adapters that need background goroutines / asyncio tasks /setIntervaltimers. - A renewal cadence the adapter computes from upstream metadata (Vault token TTL, AWS-SM rotation schedule).
- Cancellation semantics —
Config.close()MUST stop renewal tasks cleanly; partial-shutdown leaks must surface as observable errors.
Observability: metrics / events for renewal_attempt,
renewal_failed, push_received, push_dropped,
polling_fallback_active, aligned with logger-spec's
secret_resolve_* family.
D. Composite and dynamic-secret patterns
Two derived patterns surface once §A-C exist:
CompositeSecretSource— fan-out to multiple backends under one scheme (e.g.vault-primary+vault-drwith automatic fail-over).- Dynamic secrets with leases (Vault
database/creds/...) — a lease lifecycle for short-TTL credentials that the application must release on shutdown.
Pre-conditions for acceptance
The ADR moves from proposed (candidate) to accepted when:
- Phase 2 has been running in at least one production deployment for a rotation period that exposes the TTL math (~30 days for typical Vault deployments).
- ADR-0001 §7 subscriptions have at least one Phase 1 binding shipping real (non-inactive) subscriptions — the plumbing is reused, not invented.
- Each of the four areas (§A push, §B adapters, §C renewal, §D composite) has a written-out decision answering every open question with a Q-numbered argument.
Related ADRs
- ADR-0001 — base spec, subscription model in §7.
- ADR-0002 — Phase 2 pull-based secret resolution. §11 sketches the push extension this ADR will formalise.
Normative source
The full candidate text — open questions Q1–Q9, pre-conditions for
acceptance, the staged revision plan:
config-spec/adr/0003-push-rotation-and-cloud-secret-managers.md.