docs(install): revise for sops-provisioned identities (task 0012) #6

Merged
alexion merged 1 commits from task-0012-secrets-operations-docs into main 2026-07-20 10:06:58 -04:00
Owner

Task: .claude/tasks/0012-secrets-operations-docs.md

Summary

docs/install.md was built around a login password set by hand through nixos-enter after the install. That step no longer exists now that the password arrives as a decrypted secret, so the parts of the document describing it were wrong rather than merely incomplete. This is a revision rather than an appendix.

  • The LUKS passphrase is now named as the only secret entered by hand.
  • Identity provisioning moves ahead of first boot, with the reason stated: the password arrives only from a decrypted secret and there is no fallback credential — no interactive password, no unlocked root account, no authorized SSH key.
  • The closing follow-up section is gone, along with its description of deriving identities from SSH host keys.
  • Three procedures the document did not previously cover are added: provisioning an already-running host live, the editing workflow, and live-ISO recovery for a wrongly-provisioned machine.

The document is retitled "Installing and provisioning a host" and given a table of contents, since three of its four procedures are not installs.

Deviations

Redundancy between the install and recovery sections (the disko remount block, the re-key sequence) is deliberate rather than an oversight. An operator running the recovery procedure is locked out of the machine, so sending them to page back into the install steps mid-recovery costs more than maintaining two copies. The already-running-host procedure does cross-reference, because that reader has a working machine.

The recovery procedure is documented but unexercised — running it means deliberately locking out the only machine. Both branches follow from verified facts: nixos-install is idempotent and reuses the formatted disk, and the secrets file is baked into the closure at build time, which is why one branch needs a rebuild and the other does not.

Commands were verified against the running system rather than written from memory: sops updatekeys, age-keygen -y, and nixos-install --root/--flake/--no-root-password were each confirmed to exist, and the identity file's 0400 root:root at /var/lib/sops-nix/key.txt was read off the live machine.

Review

Risk

Overall: HIGH

  • Blast radius: Medium — one file, but it is the sole authority for install and secrets provisioning across every host.
  • Reversibility: High — the document reverts trivially, but the actions it directs do not, and the old passwd escape hatch is removed from the text.
  • Test coverage: High — no test can exercise a runbook; correctness rests on the prose matching the flake's actual wiring.
  • Sensitive domain: High — disk encryption, age key material, recipient lists, root-owned identity file modes.
  • Size & complexity: Medium — 244 added lines encoding an order-dependent flow with two distinct recovery branches.
  • Runtime criticality: High — the runtime is an operator formatting /dev/nvme0n1 on the only machine in the fleet.

Findings

All Standards and Spec findings were addressed in the diff. Four factual errors the Spec axis caught are worth recording, since each would have misled an operator:

  • The post-provisioning check read ls -l /run/secrets/, but neededForUsers puts the password hash in /run/secrets-for-users/ (confirmed by nix eval). The one secret whose failure causes the lockout the document exists to prevent was the one the reader was told not to look at.
  • The .sops.yaml example registered a new host against the shared rule but added no rule for the host's own file, which makes sops refuse it with no matching creation rules found.
  • Step 8's updatekeys omitted SOPS_AGE_KEY_FILE, so it would have looked in ~/.config/sops/age/keys.txt rather than the root-owned identity.
  • "Create its file now" did not say that a host enabling the SSH daemon needs ssh-host-<type>-key entries, without which the build fails at evaluation.

One follow-up is left open rather than fixed: task 0019 adds user SSH keys, which will make "no authorized SSH key" in the no-fallback paragraph stale. That paragraph is the place to revisit when it lands.

Task: `.claude/tasks/0012-secrets-operations-docs.md` ## Summary `docs/install.md` was built around a login password set by hand through `nixos-enter` after the install. That step no longer exists now that the password arrives as a decrypted secret, so the parts of the document describing it were wrong rather than merely incomplete. This is a revision rather than an appendix. - The **LUKS passphrase** is now named as the only secret entered by hand. - **Identity provisioning moves ahead of first boot**, with the reason stated: the password arrives only from a decrypted secret and there is no fallback credential — no interactive password, no unlocked root account, no authorized SSH key. - The closing follow-up section is gone, along with its description of deriving identities from SSH host keys. - Three procedures the document did not previously cover are added: provisioning an already-running host live, the editing workflow, and live-ISO recovery for a wrongly-provisioned machine. The document is retitled "Installing and provisioning a host" and given a table of contents, since three of its four procedures are not installs. ## Deviations Redundancy between the install and recovery sections (the disko remount block, the re-key sequence) is deliberate rather than an oversight. An operator running the recovery procedure is locked out of the machine, so sending them to page back into the install steps mid-recovery costs more than maintaining two copies. The already-running-host procedure does cross-reference, because that reader has a working machine. The recovery procedure is documented but unexercised — running it means deliberately locking out the only machine. Both branches follow from verified facts: `nixos-install` is idempotent and reuses the formatted disk, and the secrets file is baked into the closure at build time, which is why one branch needs a rebuild and the other does not. Commands were verified against the running system rather than written from memory: `sops updatekeys`, `age-keygen -y`, and `nixos-install --root/--flake/--no-root-password` were each confirmed to exist, and the identity file's `0400 root:root` at `/var/lib/sops-nix/key.txt` was read off the live machine. ## Review ### Risk **Overall: HIGH** - Blast radius: Medium — one file, but it is the sole authority for install and secrets provisioning across every host. - Reversibility: High — the document reverts trivially, but the actions it directs do not, and the old `passwd` escape hatch is removed from the text. - Test coverage: High — no test can exercise a runbook; correctness rests on the prose matching the flake's actual wiring. - Sensitive domain: High — disk encryption, age key material, recipient lists, root-owned identity file modes. - Size & complexity: Medium — 244 added lines encoding an order-dependent flow with two distinct recovery branches. - Runtime criticality: High — the runtime is an operator formatting `/dev/nvme0n1` on the only machine in the fleet. ### Findings All Standards and Spec findings were addressed in the diff. Four factual errors the Spec axis caught are worth recording, since each would have misled an operator: - The post-provisioning check read `ls -l /run/secrets/`, but `neededForUsers` puts the password hash in `/run/secrets-for-users/` (confirmed by `nix eval`). The one secret whose failure causes the lockout the document exists to prevent was the one the reader was told not to look at. - The `.sops.yaml` example registered a new host against the shared rule but added no rule for the host's own file, which makes `sops` refuse it with `no matching creation rules found`. - Step 8's `updatekeys` omitted `SOPS_AGE_KEY_FILE`, so it would have looked in `~/.config/sops/age/keys.txt` rather than the root-owned identity. - "Create its file now" did not say that a host enabling the SSH daemon needs `ssh-host-<type>-key` entries, without which the build fails at evaluation. One follow-up is left open rather than fixed: task 0019 adds user SSH keys, which will make "no authorized SSH key" in the no-fallback paragraph stale. That paragraph is the place to revisit when it lands.
alexion added 1 commit 2026-07-20 10:05:05 -04:00
The procedure was built around a login password set by hand through
nixos-enter, a step that no longer exists now that the password arrives
as a decrypted secret. Rather than patch around it, revise the document:
the LUKS passphrase is named as the only hand-entered secret, and identity
provisioning moves ahead of first boot, since there is no fallback
credential to get in with if decryption fails.

Cover the three procedures the install alone did not: provisioning a
running host live, the editing workflow and what it needs the admin
identity for, and recovery from the live ISO.
alexion merged commit dcc03155a2 into main 2026-07-20 10:06:58 -04:00
alexion deleted branch task-0012-secrets-operations-docs 2026-07-20 10:06:58 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: alexion/dotfiles#6