field note № 12 · secrets that reseed themselves

Reach the source, not the courier

The fleet's new primary machine got its secrets the way you'd hand a house key to a neighbour — copied across by hand, from one specific laptop, and only if someone remembered to. It worked every day. It would fail the one day it mattered.

The weakness

A Linux box had quietly become the primary runner for the whole fleet — dozens of unattended jobs, the machine that now does the real work. But its secret-bearing env files arrived by a manual scp from one Mac. Materialise them on the laptop, copy them over, done. Undocumented, invisible, and living in nobody's runbook — a copy step that survived only in the memory of the person who first ran it.

That put a specific laptop, and a human who recalled a command, in the restore path of the fleet's most load-bearing machine. Rebuild the box, or lose the Mac, and the primary runner couldn't be reconstituted without someone remembering how. The secrets already had a source of truth — Google Secret Manager, the backbone the whole fleet uses. The box simply couldn't reach it. So a copy was couriered across by hand, and the copy, not the source, became the thing the box depended on.

Why a manual copy is a coupling, not a convenience

1 · It only lives in a head. An undocumented scp is tribal knowledge. It works until the person who knows it is unavailable — and by construction, that's exactly when you need it.

2 · It couples two machines that shouldn't be coupled. The box's ability to exist depended on a particular Mac being alive, reachable, and holding a current copy. Two failure domains fused into one.

3 · It depends on the copy, not the source. The authoritative secrets sat in Secret Manager the whole time. The box trusted a hand-carried snapshot of them instead — one more thing to drift, go stale, or get half-copied.

The wrong fix (the one that's always tempting)

Two tempting fixes, and one lazy one. Put a real secrets agent on the box — 1Password. It died on a gate: service accounts need a Business plan the account doesn't have. Install the cloud SDK so the box can talk to Secret Manager the official way — a 150 MB toolchain, a package-manager fight on a locked-down host, and a virtualenv that rots on the next Python bump, all to make a dozen HTTPS GETs a few times a year. Or, laziest of all: just document the scp better.

A better-documented manual step is still a manual step. A heavier dependency is still a dependency that can rot. None of these delete the courier — they just dress it up. The copy is still in the path.

The reframe

Don't make the copy more reliable — delete the copy. Let the machine that needs the secrets reach the source of truth itself, with nothing between them but a scoped, read-only key. And do it with tools already on the box, so the reach adds no new thing that can rot.

A secret you can only restore by hand is a secret you've already half-lost.

The fix — the self-seeding box

The box now renders its own env files directly from Secret Manager over the plain REST API, run by hand on rebuild or rotation. One command replaces the remembered copy. Five things make it safe to leave in place:

Guardrail — keep the bootstrap outside its own reach

There's exactly one seed secret: the service-account key on the box. It's stored back in Secret Manager too, so a rebuild can retrieve it — but it's deliberately excluded from the box's own access set, so the box key can never read the copy of itself. No self-referential loop. A rebuild pulls that one key on the Mac and hand-seeds it once; everything else the box fetches for itself.

The proof

13 secrets
the box can read — scoped per-secret. A leaked key reads these thirteen and never a shop KEK, DNS token, or GitHub PAT.
0 SDKs
added. python3 stdlib + openssl, both already on the box. No gcloud, no google-auth, no venv to rot on a Python bump.
$0.24 / mo
the entire cost — four Secret Manager versions. No new store, no plan upgrade, no courier.
18 / 18
variables byte-identical to live in the shadow render, checked by hash before the cutover flipped.

The cutover was shadow-first. Render to a staging directory, compare every variable to the live value by hash — never printing a secret — and confirm all eighteen are byte-identical before flipping anything. Then cut over, and let two real jobs run green on the freshly-seeded env, one of them making a live upstream API call with a key the box had just fetched for itself. The copy was proven identical to the source before the source was trusted.

Make the source reachable by the thing that needs it — with no human in the path.

The principle, generalised

A manual copy step is a coupling wearing the disguise of a convenience. It works every day until the day you actually need it, and the person who knew it is gone. The durable fix is rarely a more reliable courier — it's giving the destination a direct, scoped path to the source, and paying down, not adding to, the pile of things that can rot. The box went from a pet fed by hand to a machine that reconstitutes itself from the source of truth with one command.

  1. Delete the copy, don't harden it. A better-documented manual scp is still a human in the restore path.
  2. Reach the source of truth directly. The secrets already lived in one backbone; the fix was letting the box read it, not relaying a snapshot.
  3. Add no dependency you'll have to maintain. Stdlib plus a binary already present beats a 150 MB SDK and a venv that rots. Every dependency refused is a failure you'll never debug.
  4. Scope the key to its blast radius. Per-secret access, so a leaked key reads the box's thirteen and nothing else.
  5. Fetch all before you write any. Half-seeded is worse than unseeded — die before the first write, so a no-op never stamps green.
  6. Keep the bootstrap outside its own reach. The one seed key is stored, but never readable by the thing it bootstraps.
  7. Prove the copy is identical before you trust it. Shadow-render, compare by hash, then cut over.

This is remove the coupling, not the component (№ 1) applied to secrets — the fragile thing was never the secrets, it was the hand-carried copy that coupled the box to one laptop. It's the mirror of local is a dependency (№ 5): a specific local Mac was the most invisible dependency the box had. And like a snapshot is a restore plan (№ 6), the win is a machine that's disposable — a dead box now reseeds itself from the source instead of waiting for someone to remember how.

antifragile.gf.cx · field note № 12 · published 2026-07-30 · distilled from live gf.cx practice (immich-box secret self-seeding via GCP Secret Manager REST) · source: kb.gf.cx/reference_immich_box_sm_rest_materializer_2026-07-30 · sibling to № 1 (remove the coupling), № 5 (local is a dependency), № 6 (a snapshot is a restore plan) · imports assets.gf.cx favicon + card primitives