Skip to content
Zever
Home

Crypto and secrets

Encrypt and sign data with one key service, and read named credentials from env or Vault.

2 min readEdit on GitHub

crypto encrypts and signs payloads and fields at rest or in transit; secrets looks up named credentials (API keys, connection strings). They resolve independently; passwords are not encrypted (Password hashing).

config.Default() ships a deterministic dev key so tests run real encryption; that key is public, so anything encrypted under it is recoverable. The local adapter accepts it only when explicitly allowed — set allow_dev_key: true (development only) or run with ZEVER_ENV=dev|test|development. Any other environment must set a real key.

Terminal window
CRYPTO_ADAPTER=local
CRYPTO_KEY=MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDE=
CRYPTO_ALLOW_DEV_KEY=true
SECRETS_ADAPTER=env
SECRETS_PREFIX=ZEVER
Terminal window
CRYPTO_KEY=prod-base64-key-here
export ZEVER_STRIPE_KEY=sk_test_example
main.go
cr, err := c.Crypto() // key missing, malformed, or dev key without allow
sec, err := c.Secrets() // prefix invalid

sign_key (optional) must decode to 64 bytes. STRIPE_KEY resolves to the exported ZEVER_STRIPE_KEY; without env, config.Default() still resolves but uses the dev key (allowed only via allow_dev_key or a dev ZEVER_ENV). See the crypto and secrets reference.

crypto: local (default, AES-256-GCM) or kms (envelope encryption via key_id, key_ids, region, endpoint, use_envelope; needs a real client through NewWithClient). secrets: env (default, <PREFIX>_<NAME>, prefix defaults to ZEVER) or vault (KV v2, Secrets). key_ids holds prior IDs so rotation decrypts old values while new writes use key_id.

  1. Generate a CSPRNG key and inject it through env.
  2. Dual-read: decrypt old, re-encrypt new, persist.
  3. Track old-key rows to zero.
  4. Remove the old key and verify decrypts.

Name the encrypted fields and their key generation in one place, such as the migration runbook.

  • Real key from a CSPRNG, in env or a mounted file, kept in a secret manager.
  • allow_dev_key unset (or false) and ZEVER_ENV not dev/test/development — otherwise Open fails with DevKeyError.
  • Resolve and audit both crypto and secrets.
  • Never log raw option maps; use cfg.RedactedServices() or config.Redact. Errors name services and fields, never values.
Production resolves but old rows decrypt to garbage

Rows encrypted under a different key, often the dev key. Re-encrypt them during migration.

Secrets lookup misses

The env name lacks the prefix or its boundary underscore (STRIPE_KEY vs ZEVER_STRIPE_KEY).

Open rejects the secrets prefix

Empty, or contains a slash, .., or spaces. Use a plain prefix such as ZEVER.

Open rejects the dev key with DevKeyError

The deterministic public key was supplied without an explicit allow. Set a real crypto.options.key, or set allow_dev_key: true / ZEVER_ENV=dev|test|development for local development.

Key material appears in logs

Some path logs raw options. Route all display through cfg.RedactedServices() or config.Redact.

Secrets · Authentication · Configuration