Vault backend
Sagewai's Sealed Identity layer can store profiles in HashiCorp Vault instead of the built-in encrypted JSON file. Sagewai becomes a Vault consumer; Vault keeps its own audit, leasing, and rotation.
When to choose Vault
- You already run Vault and don't want a second credential store.
- Multi-host worker fleets need a consistent profile view.
- You want Vault's lease, audit, and rotation primitives instead of Sagewai's.
If none of these apply, the Builtin backend is fine.
Setup
-
Install the optional dependency:
pip install sagewai[vault] -
Add the Vault block to
~/.sagewai/admin-state.json:{ "sealed": { "vault": { "enabled": true, "addr": "https://vault.your-org.internal:8200", "namespace": null, "auth_method": "approle", "auth_config": { "role_id": "00000000-0000-0000-0000-000000000000", "secret_id_env": "VAULT_APPROLE_SECRET_ID" }, "mount": "kv", "tls_verify": true, "audit_request_id_capture": true } } } -
Set the auth secret in your worker environment:
export VAULT_APPROLE_SECRET_ID=... -
Restart the admin server. The status page at
/sealed/statuswill show a Vault card.
Auth methods
Token
Simplest. Set auth_method: "token" and either:
auth_config.token: literal token (NOT recommended — written to admin-state).auth_config.token_env: env-var name (recommended).
AppRole
Long-lived role_id + short-lived secret_id. Set auth_method: "approle":
auth_config.role_id: literal.auth_config.secret_id_env: env-var name. Sagewai never reads the secret_id from admin-state.
Kubernetes service account
For workers running inside a Kubernetes cluster. Set auth_method: "kubernetes":
auth_config.role: Vault role configured for the SA.auth_config.token_path: path to the projected SA token (defaults to the standard injected location).
URI scheme
Profile refs use vault://:
vault://kv/sagewai/acme-prod— explicit mount + pathvault://secret/team-billing/staging— different mount
To make Vault the default for bare IDs, set sealed.default_scheme: "vault" in admin-state.
Migration from Builtin
Manual one-time copy:
sagewai admin sealed profiles get acme-prod --full \
| jq '{name, description, owner, tags, env, secrets, allowed_workflows}' \
| jq -c \
| xargs -I {} vault kv put kv/sagewai/acme-prod {}
Then update cascade refs from acme-prod (builtin) to vault://kv/sagewai/acme-prod.
Troubleshooting
- 403 Forbidden on read. AppRole secret_id expired (24h default in Vault). Renew via your Vault rotation primitive.
- Connection refused. Check
addrmatches what Vault is listening on. macOS: bind Vault to0.0.0.0, not127.0.0.1. - Namespace not found. Vault Enterprise only — verify
namespacematches an existing namespace. - Profiles list empty. Check the configured
mountandpath_prefix. Vault returns empty when no items exist at the prefix.
Audit cross-walk
Each secret.decrypted event records details.vault_request_id. Pivot to Vault's audit log to see the matching request — useful for compliance reviews. Disable via sealed.vault.audit_request_id_capture: false if you want minimal coupling.