Secret Management
Zero-knowledge secrets, alongside your config.
You hold the encryption key. We hold the ciphertext. Encrypt a value with one CLI command, distribute it to every environment through the same delivery path as your flags, and decrypt it in your app with `Quonfig.get("stripe.api.key")`. Quonfig never sees the plaintext — not at rest, not in transit, not in the audit log.
Trust boundary
You own the key. We own the pipes.
Quonfig has zero knowledge of your encryption key. We just store and distribute the ciphertext alongside the rest of your config.
Quonfig owns
- •The CLI that encrypts locally before it ever hits the network
- •Distributing the encrypted blob to every environment, just like any other config
- •SDKs that decrypt in-process when your app calls
Quonfig.get()
You own
- •The encryption key itself — a single hex string per trust group
- •Sharing the key with the right developers and services (a password manager or one-time link works fine)
- •Setting
QUONFIG_SECRET_KEY_*env vars in dev and production
How it works
Three commands, two configs, one shared secret
Quonfig secrets are built on the same `provided` and `decryptWith` config primitives you already use. Nothing magic. Nothing custom.
1. Generate a hex key
`qfg generate-new-hex-key` produces a random hex string. Drop it into your local `.env` as QUONFIG_SECRET_KEY_DEFAULT and share it with your team via a password manager.
2. Declare the key config
`qfg create quonfig.secrets.encryption.key --env-var=QUONFIG_SECRET_KEY_DEFAULT --type string --confidential` — an empty vessel that resolves from your env, never stored on our side.
3. Encrypt and ship
`qfg create stripe.api.key --type string --value=sk_live_abc --secret` encrypts locally with the hex key and pushes only the ciphertext. Your app gets the plaintext back via `Quonfig.get(...)`.
Per-environment keys
Different keys for production, staging, and dev
Because the encryption key itself is just a `provided` config, you can resolve it to a different env var per environment. Production secrets stay isolated from your dev box.
Isolate production
`qfg set-default quonfig.secrets.encryption.key --environment=production --env-var=QUONFIG_SECRET_KEY_PRODUCTION --confidential`. Now production decrypts with a key your laptop never sees.
Rotate without an outage
Issue a new hex key, set it in the env, re-encrypt with `qfg create --secret` against the new key, then retire the old one. Each step is a config change with a real audit trail.
As many keys as you need
One key per trust group, two for prod-vs-everywhere-else, or many for fine-grained access — the model is the same. `quonfig.secrets.encryption.key` is just a default name, not a hard limit.
Why one platform
Same delivery path. Same SDKs. Same audit trail.
Secrets aren't a separate product. They use the same `Quonfig.get()` call, the same local-evaluation cache, the same git-backed history, and the same per-environment targeting as every other config.
One SDK call
Quonfig.get("stripe.api.key") returns the decrypted string. Your app code doesn't know or care that it was encrypted at rest.
Survives our outage
Encrypted secrets ride the same local-evaluation cache as every other backend SDK config. If we go down, your app keeps resolving the cached ciphertext.
Real audit trail
Every secret rotation is a git commit with author, timestamp, and diff. The audit log shows the ciphertext changed — no plaintext leaks into the history.
Works in CI offline
Make QUONFIG_SECRET_KEY_DEFAULT available to your CI process and tests resolve the same secrets, no network required.
Ready to stop juggling a separate secrets manager?
Encrypt locally, distribute through Quonfig, decrypt in your app. Zero plaintext touches our servers.