Vault
forze[vault] implements the secrets contract against HashiCorp Vault (KV v2).
It supplies a SecretsPort so the rest of Forze — especially the routed,
per-tenant clients — can resolve credentials by reference instead of holding
them in config.
Install¶
uv add 'forze[vault]'
Needs a Vault server with a KV v2 mount.
Wire it¶
Build a client with its config, register the deps module (which publishes a
SecretsPort), and wire the lifecycle step:
from forze.application.execution import DepsRegistry, LifecyclePlan
from forze_vault import VaultClient, VaultConfig, VaultDepsModule, vault_lifecycle_step
vault = VaultClient(config=VaultConfig(url="https://vault.example.com", token="…"))
deps = DepsRegistry.from_modules(VaultDepsModule(client=vault))
lifecycle = LifecyclePlan.from_steps(vault_lifecycle_step())
What it provides¶
| Contract | Implementation | Dep key |
|---|---|---|
Secrets (resolve_str, exists) |
VaultKvSecrets (KV v2) |
SecretsDepKey |
| Raw client | VaultClient |
VaultClientDepKey |
| Key management (envelope encryption) | VaultTransitKeyManagement (Transit) |
KeyManagementDepKey |
| Per-tenant KEK provisioning | VaultTransitTenantProvisioner (Transit) |
via TenantProvisionerPort |
| Token signing (RS256 / ES256) | VaultTransitSigner (Transit) |
via the identity authn signer |
Notes¶
- KV v2 only. The mount is set once on
VaultConfig.mount_point; aSecretRef.pathis mount-relative. - The client needs the lifecycle step —
VaultDepsModuleonly registers an already-constructed client; it doesn't initialize it. - This is what powers per-tenant secret routing (
secret_ref_for_tenant) for the routed Postgres/Mongo/HTTP/… clients — see Multi-tenancy. - Transit is a separate mount from KV.
VaultTransitKeyManagementis the KMS backend for envelope encryption (the KEK never leaves Vault),VaultTransitTenantProvisionercreates a tenant's Transit key on onboarding, andVaultTransitSignersigns JWTs (RS256/ES256) without the private key leaving Vault.