Skip to content

0026. Keep a single secret zero in the OS keychain; generate all other secrets

  • Status: Accepted
  • Date: 2026-09-26

Context

Every secret needs protection, and the protection itself needs a key: the chain ends in one initial secret, the secret zero. The platform already has several secrets (state encryption passphrase, object-store credentials, later tool admin passwords). None may be committed, and hand-managed secrets conflict with "everything is a provisioned state". Background: Secret zero.

Options

Option Pros Cons
Every secret created by hand and stored in the keychain Simple to understand Manual work per secret; rotation is tedious and error-prone
One secret zero in the keychain; everything else generated by OpenTofu and kept in encrypted state One manual secret; rotation is tofu apply -replace; no secrets in code State encryption becomes critical (it is, see 0025)
Secrets manager from day one Enterprise pattern Needs infrastructure that does not exist yet (Phase 2)

Decision

  • The state encryption passphrase is the only hand-managed secret. It lives in the OS keychain and is passed to OpenTofu by the task wrapper at run time.
  • Other secrets (e.g. S3 credentials) are generated by OpenTofu (random_password), stored in encrypted state and passed between stacks by the task wrapper, never written to disk in plain text.
  • One passphrase serves all stacks locally; separate keys per environment are a known simplification, reversible via OpenTofu key rotation (fallback).

Consequences

  • Losing the passphrase makes all state unreadable: it must be backed up in a password manager.
  • Phase 2 moves secret zero and generated secrets to OpenBao; the chain stays the same.
  • Keychain support depends on the host OS; the task wrapper also accepts the passphrase from an environment variable so other hosts and CI can supply it.