Subumbra is a split-trust secret broker. Your apps talk to Subumbra; Subumbra talks to OpenAI, GitHub, npm, and more. Real API keys, SSH keys, and registry tokens never sit in plaintext on the machines you operate — and even a compromised app never sees them.
subumbra-keys
stores ciphertext and wrapped DEKs only — useless without the private key, which lives in Cloudflare.Tested providers
Built-in adapters
What it brokers
The same split-trust vault, session lockdown, policies, and audit trail apply whether the secret signs an SSH challenge, publishes a package, or calls an LLM.
npm publish and installs so your
registry token never lands in .npmrc,
a .env, or a CI secret. Tarballs are
inspected before publish — scope checks, size caps, and secret-pattern
scanning, all fail-closed.
How it works
A one-shot ./bootstrap.sh encrypts provider
material and deploys enforcement to Cloudflare. After that, subumbra-keys on your side only stores ciphertext
envelopes and wrapped DEKs — never usable upstream secrets at rest.
manifest.yaml and edit providers, routing, and
consumer IDs. For CI or unattended runs, copy .env.bootstrap.example to .env.bootstrap and add Cloudflare credentials
plus the same secret_ref values referenced
in the manifest.Run ./bootstrap.sh on the host. Think
of it as the one “setup” button: it starts the bootstrap container, deploys or updates the Worker in
Cloudflare, encrypts your provider keys into the local store, and tells you when to bring the stack up —
without leaving a trail of plaintext secrets in the repo as part of that run.
If you use interactive mode, you answer prompts for Cloudflare credentials and each provider secret; those answers stay in process memory for the session and are not written back into the project as cleartext.
If you already copied .env.bootstrap.example
to .env.bootstrap and filled it in, the
same script runs headlessly, then securely shreds that file after a successful pass so it does not linger on
disk.
When the script exits cleanly, your .env
contains the consumer tokens the stack expects, encrypted material is on the volume, and the core containers
can start normally.
Update your apps wherever they read provider settings — .env files, YAML or JSON config, admin UIs,
or secrets in your orchestrator. Where you used to paste the real vendor key and call the provider directly,
aim traffic at Subumbra and put the narrow consumer token in the credential field instead. The key_id from your manifest still goes in the URL
path right after /t/ (below, anthropic_prod is only an example).
.env for the real provider secret.
Sessions & approvals
Think of a time-lock safe: after bootstrap, nothing is released until you open a bounded session — and the riskiest actions can additionally wait for a human tap.
A stolen consumer token is useless while the vault is locked. Open a session for exactly the consumers and keys you need, with a TTL and optional request or signing quotas. Close it early, or let it expire.
system_locked. API, SSH, and npm paths all fail closed.--session end does.For the actions that really matter — an npm release, an SSH deploy signature, a sensitive API path — Janus holds the request and pushes an approval card to your browser or phone. Nothing decrypts until you say so.
/proxy calls, SSH signatures, and npm publishes — reads pass through untouched.Features
:8090/t. No app code changes
— swap the base URL and use a narrow consumer token instead of a real key.--session start --ttl 8h opens a
time-boxed window for chosen consumers and keys; everything else stays
system_locked.manifest.yaml; bootstrap publishes
structured entries to Cloudflare KV so the Worker validates every upstream target fail-closed.subumbra-verify-deploy detects
drift so a silently replaced Worker doesn't go unnoticed.Security model
Split trust means ciphertext and wrapped DEKs on your infrastructure are useless without the matching RSA private key held in a Cloudflare Durable Object. A complete break requires defeating both sides — plus your manifest-defined adapter and policy controls at the Worker boundary. Cloudflare and your deploy credentials remain explicit trust boundaries.
subumbra:v3:<key_id>:<policy_hash>,
binding ciphertext to the policy in effect at encryption time and blocking transplant or stale-policy replay.system_locked.allow.consumers
binds each consumer token to specific records; policy can scope methods, paths, hosts, and capability class so a
compromised chat app cannot silently pivot to unrelated APIs.subumbra-proxy
requests envelopes from subumbra-keys with
per-request HMAC integrity and freshness controls so replayed or forged fetches fail closed.Who it's for
./bootstrap.sh walks you through it interactively; secrets stay in RAM during setup and never land in the repo.Self-hosted, open source, deployable in minutes. API keys, SSH keys, and npm tokens — locked by default, released one request at a time, never in plaintext on your servers after bootstrap.