The secrets layer your agents never see in plaintext.
FunctionFly Vault gives you two encryption modes — zero-knowledge (the server stores ciphertext + IV + salt + tag, never the key material) and server-side (MKEK per-tenant with KMS/HSM root-of-trust) — plus a Vault Capability Fabric that brokers scoped grants to functions and agents instead of handing out raw credentials. Dynamic AWS IAM and GitHub PATs spin up on demand. Every plan includes the vault.
What you get
A vault built for AI agents that handle hundreds of credentials — not a credential manager with an API on top.
Two encryption modes
Zero-knowledge for tenant-owned secrets (PBKDF2 key derivation in the browser, server stores ciphertext only) or server-side for AI-provider keys the platform must inject into LLM calls. Choose per-secret; mix freely in the same vault.
Vault Capability Fabric
Functions and agents never receive raw vault credentials. The broker issues short-lived, policy-scoped grants (auto-approve, pending review, or deny) and resolves plaintext only at dispatch into a runtime env (FF_SECRET_<NAME>) — never into model context.
Dynamic credentials
Spin up scoped AWS IAM roles and GitHub PATs on demand with automatic rotation. The orchestrator issues short-lived credentials to functions — never the long-lived secret. Per-tenant caps, daily rotation, sweep of stale issues.
MFA-gated access
TOTP, passkeys, backup codes, SAML SSO, SCIM provisioning. Sensitive operations require fresh MFA even for already-authenticated sessions. Reveal (L3) is single-use and never auto-approved.
Per-tenant namespaces + expiration
Hierarchical, lowercase, slash-separated namespaces. Per-secret expiration, rotation schedules, and per-tenant quota. Audit trail for every read, write, decrypt, rotate, and capability grant.
Kill-switch + revocation
A typed "revoke-all" emergency kill-switch requires an Idempotency-Key and an explicit type-to-confirm phrase. Live capability rows flip to revoked and the next dispatch fails closed. Per-tenant audit feed surfaces revoke-all events on Prometheus.
Two encryption modes, one API
Same /v1/vault/secrets surface — the server stores ciphertext either way. The difference is who holds the key.
ZK — the server cannot decrypt
AES-256-GCM with client-derived keys. The server stores ciphertext + IV + PBKDF2 salt + GCM tag and never holds key material. You can prove compliance without being able to decrypt tenant data.
- PBKDF2 key derivation in the dashboard (web/dashboard/src/utils/vault-crypto.ts)
- Key versions: legacy 100K iters (v1) and OWASP-style 600K iters (v2) — server stores the version, client picks the iteration count
- Per-secret 12-byte IV + 16-byte salt + 16-byte auth tag, all base64-encoded
- AI provider connections and dynamic credentials are server-side only; ZK is for tenant-owned secrets
Server-side — broker decrypts at dispatch
AES-256-GCM with per-tenant keys derived from a Master Key Encryption Key (MKEK) hierarchy. KMS or HSM root-of-trust. Required for any secret the platform must inject into a runtime (AI providers, capability broker, dynamic creds).
- MKEK hierarchy: SERVER_MASTER_KEY → tenant KEK → per-secret DEK, wrapped at rest
- KMS and HSM provider support (AWS KMS, dedicated HSM) — see internal/storage/vault/mkek_*.go
- Per-tenant KEK re-wrapping on rotation; data-key cache invalidates atomically
- Capability broker resolves plaintext through the existing SecretDecryptor seam at dispatch — never persists the cleartext
How a function gets a credential
Five steps. The plaintext only exists inside the runtime env, scoped to that one dispatch.
Encrypt + store
Client encrypts the secret (ZK or server-side) and POSTs the ciphertext envelope to /v1/vault/secrets. Server stores ciphertext + metadata + namespace — never the key material.
Publish requires[]
Function declares what it needs at publish time: { secret: "stripe.production", operations: ["payments.create"], network: ["api.stripe.com"] }. Lands on registry_functions.secret_requirements (JSONB).
Broker evaluates policy
At wake, the Vault Capability Fabric checks policies (subject glob × secret glob × operations ⊆ × TTL ≤ max_ttl). Auto-approves to active, queues pending, or denies. Bare "*" patterns are rejected at policy insert.
Grant issued
vault_capabilities row becomes the source of truth. An Ed25519 receipt is signed (audit artifact, not a bearer token). Live status is the Postgres row — signing-key rotation does not invalidate existing grants.
Dispatch injects env
At function dispatch the SecretDecryptor seam re-validates the row (revoked/expired/pending never resolve) and the broker resolves plaintext into FF_SECRET_<NAME> env vars. Plaintext never reaches model context.
Pick the tier that fits the workload
Every plan ships with vault features included — limits scale, capabilities do not.
Side-project vault
25 secrets + 100 dynamic credentials with expiration and namespaces. ZK-mode by default. Zero-knowledge end-to-end.
Production team
500 secrets + 5,000 dynamic credentials. Same primitives as Free, with headroom for CI/CD integrations and per-environment namespaces.
MFA + audit export
5,000 secrets + 50,000 dynamic creds. Adds MFA enforcement, IP allowlist, break-glass emergency access, audit export to S3/GCS for compliance review.
RBAC + escrow + SIEM
1M secrets + 1M dynamic creds. Adds key escrow, RBAC for vault admin delegation, secret shares across multiple operators, and SIEM webhook delivery for every audit event.
SSO + HA
1M secrets + 1M dynamic creds with SAML/SSO, multi-region HA status, and everything Enterprise ships. Designed for agents that hold credentials on behalf of customers.
Stop pasting API keys into env files
Every plan ships with vault features included. Free tier starts at 25 secrets and 100 dynamic credentials.