Skip to main content
Doppler holds secret-zero, and nothing else that another tier can hold instead.

Its job in the four-tier model

Doppler is T3, the bootstrap cloud tier of the four-tier secrets model. Its role has narrowed to one job with a small exception attached:
  • Secret-zero for T2. Doppler holds the material that bootstraps the OpenBao runtime manager: its static seal key (for auto-unseal), the AppRole role_id/secret_id pairs an agent presents to authenticate, and the GitHub App key material the token engine exchanges. This is why T3 is kept small and tightly scoped.
  • Values an external service consumes directly. A hosted service that reads a credential on its own (a remote CI runner, a vendor integration) cannot go through T2 to get it. That explicit, listed set stays here. Nothing joins it by default.
Everything else lives in T2, where credentials are self-hosted, short-lived, and readable with zero interactive prompts. Or it is minted on demand by an engine and never stored at all.

What goes in Doppler

  • Secret-zero: the runtime manager’s address, its static seal key, and the bounded AppRole pairs that let a consumer authenticate.
  • The App key material and installation identifiers the GitHub token engine exchanges for short-lived tokens.
  • The listed set of credentials an external service reads directly: hosted CI licensing and vendor-integration keys, kept in their own project.

What does not go in Doppler

  • Anything a consumer can read from the runtime manager instead. Self-hosted app-service credentials (database passwords, vector-store keys, and the like) live in OpenBao (T2).
  • Anything an engine can mint: GitHub tokens, AWS sessions, SSH certificates. They are issued per call and never stored (see GitHub access).
  • SSH keys for git auth (lives in Bitwarden + ssh-agent).
  • Recovery codes, account passwords, age-key escrow (Bitwarden).
  • Anything an AI tool must never read (Bitwarden vault).
A value that lands here by habit rather than by one of the two preceding reasons is drift. It is migrated out. The migration counts as finished only when a live consumer has been proven against the central store and this copy is deleted.

Project / config layout

Three Doppler projects, three delivery modes: each lands in a different consumer.

Runtime fetch via GitHub Actions

For Tier 2 secrets that must never sit in GitHub Actions stores:
That DOPPLER_TOKEN service token is itself a Tier 1 secret distributed by secrets-sync to the two _infra_repos: ansible-proxmox-apps and tofu-runs-on.

OpenTofu boundary

Doppler is not in the active OpenTofu plan or apply path. Terrakube uses native OpenBao identities, dynamic provider credentials, and ephemeral values. Do not copy an IaC credential from Doppler into a Terrakube workspace variable.

Anti-patterns and best practices

  • Do not export DOPPLER_TOKEN in a shell profile. Use doppler login interactive auth or a per-user service token configured once. A token persisted in the shell environment is reachable by every later command.
  • Do not store the same value in two places. One source of truth per secret, and for anything but secret-zero that source is the runtime manager.
  • Rotate the service tokens at 90 days. The rotation runbook lives in secrets-sync.
  • Audit log: enable Doppler’s per-project audit log; review on every key rotation.

See also

  • Tools comparison: the four-tier model and where T3 sits.
  • OpenBao: the T2 runtime manager Doppler bootstraps.
  • secrets-sync: Tier 1 distribution.
  • IaC tooling: the Terrakube and OpenBao execution path.
  • BWS: alternative for AI-specific OAuth tokens where Doppler is not yet wired up.
  • docs.dryvist.com: dryvist-internal project / config names.