Skip to main content

max / alloy

Settle how the age identity gopass needs reaches a machine It is placed by hand, and a fresh install does not provision it. The task left this open on the grounds that a fresh install is when doing it by hand is most annoying and alloy setup already owns first-boot enrollment, so the shape would be one screen. Provisioning turns out to mean two different operations and only one is coherent. The identity already exists: reusing the one the sops migration requires is why gopass beat rbw in the first place. So generating a fresh one at install decrypts nothing already owned, and adding each machine's pubkey as a recipient grows a list that never shrinks as machines retire, which is key sprawl on a different axis from the one the pick was made to avoid. That leaves ingest, and ingest has no channel at first boot. The store arrives over the tailnet, tailnet enrollment is itself a row on that screen, and carrying the identity through the same screen collapses the separation the scheme rests on. The two enrollments already there are also a different kind of object: both authenticate a device against a service that can revoke it, where an age identity is a bearer secret with no service and no audit. A third row beside them would imply a property it does not have. The manual half was filed against a manual/recovery.md that does not exist; recovery is split across chapters 3 and 14. Written as both halves instead. Chapter 10 names where the identity lives and points at gopass config as the authority over the page. Chapter 14 gains the entry separating the two secrets that get wanted at the same moment, since the eight-word phrase unlocks the disk and the identity decrypts the store and neither substitutes for the other. The console noticing an absent identity and saying so is GO alloy 9664b160, which is what makes STACK.md's "what the console does instead" true. GO alloy c113feec.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-01 22:46 UTC
Signed with PGP, not checked
Commit: a56a8a8e20e55b39a56f6bce22982270d45dbe3e
Parent: fb82b2e
3 files changed, +28 insertions, -1 deletion
M docs/STACK.md +3 -1
@@ -217,7 +217,9 @@
217 217 - **No zero-ceremony multi-machine editing.** Pull before, push after. That friction is real and is the thing Syncthing did better.
218 218 - **No usable phone access.** Credentials needed away from a machine (registrar, bank, Apple Developer) either live somewhere else or are deliberately not covered.
219 219
220 - Open: whether a fresh install provisions the age identity or leaves it manual. A fresh install is exactly when doing it by hand is most annoying, and `alloy setup` already owns first-boot enrollment for tailnet and Syncthing ([CONTINUITY.md](CONTINUITY.md)), so the shape would be one screen rather than a subsystem. Undecided, and it belongs with the user manual's recovery section whenever that lands, since an age identity and a disk-encryption recovery phrase are both things you need when a machine is gone.
220 + **The identity is placed by hand, and a fresh install does not provision it.** Settled 2026-08-01. Two things could be meant by provisioning and only one of them is coherent. The identity already exists, since reusing the one the sops migration requires is why gopass won here, so generating a fresh one at install decrypts nothing you own and grows a recipient list that never shrinks as machines are retired. That leaves ingest, and ingest has no channel at first boot: the store arrives over the tailnet, tailnet enrollment is itself a row on the `alloy setup` screen, and carrying the identity through that same screen collapses the separation the whole scheme rests on. The two enrollments already there are also a different kind of object. Both authenticate a device against a service that can revoke it, where an age identity is a bearer secret with no service, no revocation and no audit, so a third row beside them would imply a property it does not have.
221 +
222 + What the console does instead is notice when the identity is absent and say so, in the shown-and-not-settable idiom the locale row above uses. That covers the part of a fresh install that actually hurts, which is not typing a key but failing to learn you needed one until gopass refuses to decrypt. [Chapter 10](manual/10-the-shell.md) is where the identity lives; [chapter 14](manual/14-troubleshooting.md) is the case where the machine is gone and the age identity and the disk-encryption recovery phrase are both wanted at once.
221 223
222 224 ## Shell
223 225
@@ -77,3 +77,11 @@
77 77 Alloy provisions neither with any content. `gopass init` sets up a store when
78 78 you want one, and the age identity that decrypts it should never live in the
79 79 repository it decrypts or travel with it.
80 +
81 + That identity lives on the machine, under `~/.config/gopass/age/`. Run `gopass
82 + config` to see the paths your install is actually using rather than trusting
83 + this page. It matters because it is the one part of the store that is not in
84 + git: clone the repository onto a new machine and you have every password in
85 + ciphertext and no way to read any of it. Copy the identity across yourself, by
86 + hand, over a channel that is not the one carrying the store. Chapter 14 covers
87 + the case where the machine is already gone.
@@ -177,6 +177,23 @@
177 177
178 178 Without either one, the data is gone. That is what encryption means.
179 179
180 + ### I have my password store but nothing will decrypt
181 +
182 + Two separate secrets get needed at the same moment, when a machine is lost, and
183 + they are easy to conflate. The eight-word recovery phrase above unlocks the
184 + **disk**. The age identity under `~/.config/gopass/age/` decrypts the **password
185 + store**. Neither one substitutes for the other, and neither is in the git
186 + repository holding the store, by design.
187 +
188 + So a clone of the store on a new machine is ciphertext until you put the
189 + identity back. If you still have the old disk, copy it off. If you kept a copy
190 + somewhere off the machine, restore that. If neither, the store is gone the same
191 + way an encrypted disk with no phrase is gone.
192 +
193 + Worth doing before you need it: keep the identity somewhere that is not the
194 + machine and not the store's remote. Chapter 10 covers where it lives and why it
195 + never travels with the ciphertext.
196 +
180 197 ### The new image is worse than the old one
181 198
182 199 rpm-ostree rollback