Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ADR-0009: Manage Runtime Secrets Outside Nix Source

Status: accepted

Context

Dubnium needs private material for several different lifetimes:

  • local source payloads for installing this private repository
  • host-local identities for services such as Tailscale
  • runtime tokens for workloads such as vLLM model downloads
  • user-runtime tokens for tools such as Codex and GitHub CLIs after install
  • large private or mutable artifacts such as model weights

These are not the same class of data. Treating all of them as Nix source would either leak secrets into Git, copy secret bytes into the Nix store, or make activation depend on external state that belongs to the operator.

Existing Dubnium policy already keeps the repository source-only and keeps vLLM model weights in runtime cache state. Installer bootstrap should use local source payloads, such as a git archive tarball or copied working tree, rather than GitHub credentials in the live installer.

Decision

Use sops-nix with age recipients as the preferred provider for runtime service secrets.

Commit only encrypted SOPS documents and non-secret policy. Decrypt secrets at activation into runtime paths under /run/secrets or into sops-nix generated environment files. Services consume those paths; Nix modules declare the consumer contract, not the secret value.

Keep install source bootstrap separate from runtime secrets. Install media should use a local source payload prepared before booting the target machine. Do not require GitHub credentials during install.

Allow user-runtime secrets after install. Tools such as Codex may need an OPENAI_API_KEY, and user workflows may later need a GITHUB_TOKEN. Those tokens belong to the user runtime, not installer bootstrap, and should be decrypted by Home Manager or another user-scoped secret mechanism at session or process launch time.

Keep host enrollment identities separate from ordinary workload tokens. Tailscale remains manually enrolled for v1. If unattended enrollment is added later, it must use a short-lived auth key passed once during enrollment rather than a long-lived key committed to source.

Keep model weights out of Git, out of SOPS, and out of the Nix store. The Dubnium model store under /var/lib/dubnium/models remains mutable runtime state, not secret state.

Consequences

  • The repository can contain secret wiring without containing secret values.
  • Host rebuilds can declare which services need secrets without exposing those secrets in derivations or module options.
  • Operators must manage age identities and encrypted SOPS files during bring-up.
  • Secret rotation is done by updating encrypted SOPS data and rebuilding or restarting affected services.
  • Source bootstrap, enrollment, runtime tokens, and model artifacts keep separate handling rules instead of sharing one overloaded mechanism.

Escalation Criteria

Reconsider this policy if:

  • Dubnium gains a dedicated external secret manager
  • unattended installation needs to handle many machines at once
  • secret rotation needs central audit or approval workflows
  • Kubernetes-hosted workloads become the primary secret consumers