docs(runbooks): repair the two key-recovery instructions the re-key broke - #488
Merged
Merged
Conversation
…roke The second recipient landed in e638964 and silently invalidated two pieces of runbook text, both on the path of the one step #294 still has open. `grep -A3 creation_rules .sops.yaml` no longer prints a single key. .sops.yaml grew to four rules; the real recipients sit ~40 lines below the anchor and -A3 never reaches them, so the command returns a comment block. successor-handover.md put that in front of a reader who has lost the key, captioned "every key that can open the secrets", one sentence above "this is a phone call rather than a rotation" — so the output says rotate when the truth is phone the technical second. It is replaced by scripts/key-recipients.sh --list, which reads the recipients out of the ciphertext, needs no private key, and is pure grep for the reason its own header gives: bare metal, where python3 and PyYAML are not given. The .sops.yaml grep stays as the deliberate cross-check, framed as policy against fact, because the two disagreeing is the hand-edit failure that file warns about. back-up-the-age-key.md's expected output for make secrets-verify-backup was written for one recipient and six required keys. The script prints nine, no longer says "matches .sops.yaml" — section 3 matches against the ciphertext now, which is ADR-0024's whole point — and emits two lines plus a tail block that only exist once a file has more than one recipient. An operator proving the technical second's copy would have seen a different hash and a "one of two" framing the page never mentioned. Verified: both documented commands run here and agree with each other; make check-docs, lint.sh and markdownlint pass. Refs #294. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
7 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
Not the second recipient — that merged on 2026-09-09 in #412. This repairs the
two pieces of runbook text that re-key silently invalidated, both of which sit on
the path of the one step #294
still has open.
#294 stays open. Its last unticked box is "both keys independently verified
with
make secrets-verify-backup", and that needs the technical second'sremovable medium physically at the monitoring host.
recipient-state.promhasage1cutv5q…at0, never proved, withSecretsKeyBackupUnprovennaming it —ADR-0024's honest state, not a fault. This PR makes the text that operator will
read correct; it cannot tick the box.
grep -A3 creation_rules .sops.yamlreturns zero keys.sops.yamlgrew to four rules (lab, sensitive, soc, catch-all). The realrecipients are now ~40 lines below the anchor, and
-A3never reaches them — thecommand prints a comment block and nothing else. Reproduced on
main.successor-handover.mdput that in front of a reader who has lost the key,captioned
# every key that can open the secrets, one sentence above "If arecipient there is one somebody else holds, the secrets are recoverable and this
is a phone call rather than a rotation." A successor sees no
age1…, concludesthere is no second recipient, and chooses four SNMP rotations on hardware over a
phone call — in the emergency the page exists for, and defeating precisely the
outcome #294 was filed to produce.
Replaced with
./scripts/key-recipients.sh --list, which reads the recipientsout of the ciphertext, needs no private key, and is pure grep for the reason its
own header gives: "bare metal, where python3 and PyYAML are not yet a given."
The
.sops.yamlgrep is kept beside it as a deliberate cross-check — policyagainst fact — since the two disagreeing is the hand-edit failure
.sops.yaml'sown header warns about. The same broken command appeared inline in
back-up-the-age-key.mdand is fixed there too.The expected-output block was written for one recipient
back-up-the-age-key.md§2 shows whatmake secrets-verify-backupprints. Againstscripts/verify-key-backup.sh:-- recipient matches .sops.yaml: age1…-- recipient age1…(L188)-- this file has 2 recipient(s); this run proves one of them(L189)(6/6 keys), "all six keys"REQUIREDholds nine names (L231-241)>1recipient (L293-299)The first row is more than cosmetic: §3 matches the backup's public half against
the recipients read from the ciphertext, deliberately not
.sops.yaml, whichis ADR-0024's central point. Advertising the check as "matches
.sops.yaml"teaches the wrong model in the one document about key recovery. An operator
proving the technical second's copy would also have seen a different hash and a
"one of two" framing the page never mentioned.
Not touched
.sops.yaml/secrets/observability.sops.yaml— already correct and agreeing.secrets/README.md— reviewed on Add a second age recipient so decryption does not depend on one person #294 and needs nothing. The table at line 11is an inventory of files on this host; that file does hold one private key,
and the second recipient's private half is deliberately not here at all.
Verification
Links and the
#adding-a-second-recipientanchor checked by hand — there is nolink checker in CI.
🤖 Generated with Claude Code