Vault
A Frappe-native, cluster-central secrets service. One site (the vault server) holds versioned master keys and does all crypto — AES-256-GCM envelope encryption, prefix policies (deny-by-default), a central access log. Every other site is a thin
- Author: ssiyad
- Repository: https://github.com/ssiyad/vault
- GitHub stars: 0
- Forks: 0
- License: MIT
- Category: Integrations
- Maintenance: Actively Maintained
Install Vault
bench get-app https://github.com/ssiyad/vault
Add the Frappe Gems badge to your README
Maintain Vault? Paste this into your README:
[](https://frappegems.com/gems/apps/ssiyad/vault)
About Vault
Vault
A Frappe-native, cluster-central secrets service. One site (the vault server) holds versioned master keys and does all crypto — AES-256-GCM envelope encryption, prefix policies (deny-by-default), a central access log. Every other site is a thin client that fetches secrets over HTTPS with a per-node token.
The same app is installed on every machine; a site's role comes from configuration. Client installs carry the server code inertly — the API and admin entry points refuse to serve (404) unless the site is flagged as the server.
Server setup (one site per cluster)
bench get-app vault && bench --site vault.example.com install-app vault
bench --site vault.example.com set-config vault_server 1
Export the master keys in the environment of every process serving the site (the KEKs never live in a file or the database — strict, no fallback):
export VAULT_KEKS='{"v1": ""}'
export VAULT_KEK_CURRENT=v1
Generate a key with:
python -c "import os, base64; print(base64.b64encode(os.urandom(32)).decode())"
Then, per client machine:
bench --site vault.example.com vault-issue-token— the token is printed once; deliver it to the node out of band (this is secret-zero). Or use the Issue Token button on the Vault Node form.- Create a Vault Policy for the node: key pattern (e.g.
siteb/*) + allowed actions. No matching policy means deny.
Client machine setup
bench get-app vault && bench --site siteb.example.com install-app vault
In the client site's site_config.json, set the connection and store each secret as a
vault/-prefixed reference value (not the secret itself):
"vault_url": "https://vault.example.com",
"vault_token": "svlt_...",
"stripe_key": "vault/siteb/stripe_key"
App code then reads secrets through the normal config accessor — no vault-specific API:
frappe.conf.get("stripe_key") # -> the decrypted secret, fetched from the vault
frappe.conf.get("some_plain_key") # -> plain values are returned untouched
Any config value beginning with vault/ is resolved on read: the prefix is stripped and
the remainder (siteb/stripe_key) is the vault key. Values without the prefix behave
exactly as stock Frappe. The client caches resolved values in memory only with a
short TTL (default 60s), so brief vault outages don't break request serving; past the TTL
it fails closed (raises rather than returning a stale or empty secret). Plaintext
never touches the client's disk, database or redis. Do not set vault_server or the
KEK variables on client machines.
> Note: web workers cache site_config.json for ~60s (frappe/config.py), so a newly
> added reference can take up to a minute to appear in running workers.
To move existing plaintext secrets out of a client's site_config.json:
bench --site siteb.example.com vault-migrate # dry run
bench --site siteb.example.com vault-migrate --commit # apply
--commit pushes each detected secret to the vault and rewrites its site_config.json
value in place to vault//, so existing frappe.conf.get(...) calls keep
working unchanged. Re-running is a no-op (already-referenced values are skipped).
Rotating the master key
Add the new version to VAULT_KEKS (keep the old one), set VAULT_KEK_CURRENT to it,
restart, then:
bench --site vault.example.com vault-rotate-kek v2
Only the small wrapped data keys are re-encrypted — stored ciphertext never moves.
The command is resumable; once no row references the old version, drop it from
VAULT_KEKS.
Notes
- Nodes authenticate with an
X-Vault-Tokenheader (notAuthorization, which Frappe reserves for User/OAuth sessions). Raw tokens are never stored — only a SHA-256 hash. Revoke a node by unchecking Enabled; the next request is denied and logged. - Every access — allowed or denied, API or UI reveal — lands in Vault Access Log.
- Avoid passing secret values as CLI arguments (
bench set-config my_key ...): bench logs command lines tologs/bench.log.
Related Integrations apps for Frappe & ERPNext
- Insights — Open Source Business Intelligence Tool
- Raven — Simple, open source team messaging platform
- Frappe Whatsapp — WhatsApp cloud integration for frappe
- Frappe Assistant Core — Infrastructure that connects LLMs to ERPNext. Frappe Assistant Core works with the Model Context Protocol (MCP) to expose ERPNext functionality to any compatible Language Model
- Biometric Attendance Sync Tool — A simple tool for syncing Biometric Attendance data with your ERPNext server
- Frappe React Sdk — React hooks for Frappe
- Frappe Js Sdk — TypeScript/JavaScript library for Frappe REST API
- Mcp — Frappe MCP allows Frappe apps to function as MCP servers