Decommissioning a Host#

The operational procedure behind SCF AST-09 — Secure Disposal, Destruction or Re-Use of Equipment (see modules/compliance/controls/AST-09.nix). Every host that leaves the fleet goes through this runbook, and every run appends a row to the decommission log. The removal commit’s SHA plus the log row are the disposal evidence.

Procedure#

1. Repo removal (one atomic PR)#

  1. Delete the host’s entry from hosts/default.nix and its directory/file under hosts/<system>/. Tag-driven discovery (builder/cache) drops the host from every nix.buildMachines list automatically.
  2. Remove the host’s SSH public keys from modules/darwin/security/pubkeys/ and modules/nixos/security/pubkeys/ (the NixOS side auto-globs the directory) and any explicit knownHosts entry in modules/darwin/security/default.nix.
  3. Remove the host from every deploy.monitoredHosts list (grep the hostname — a dead entry generates offline alerts every health-check cycle).
  4. Sops key revocation (only if the host had its own age anchor): - Delete the host anchor and recipient references from .sops.yaml, plus any user key that existed only for this host. - Remove the host’s secrets (e.g. sops unset secrets.yaml '["borgmatic"]["<hostname>"]'). - Re-key everything: just sops-updatekeys, then verify your own key still decrypts: sops --decrypt secrets.yaml > /dev/null. - Never remove your own user keys — rekey rollback depends on them.
  5. Remove the BorgWarehouse registry entry from modules/nixos/borg/repo.json.
  6. Docs: delete the machine page, fix inbound links, remove the node from the manual topology (modules/topology/default.nix), update .claude/hosts.md.
  7. Verify: nix flake check, just docs-build, grep for the hostname → empty, eval the remaining darwin/nixos configurations.
  8. Redeploy hosts whose buildMachines/knownHosts/monitoring changed.

2. Outside the repo#

  1. Tailscale admin console — remove the node; confirm its device and any auth keys are gone from the tailnet.
  2. BorgWarehouse (voile) — freeze the host’s repository (no new backups arrive anyway once the client is wiped), note the purge date (90-day retention), and delete the repo when it arrives. Deleting the repo also revokes its per-repo SSH public key.
  3. Media sanitization — full-disk erase before the hardware leaves organizational control. All fleet disks are full-disk encrypted (LUKS2 / FileVault): destroying the volume key is cryptographic erasure, which is the sanitization floor even if a full wipe is interrupted. Record the wipe method and date in the log.
  4. Third-party management — if the machine was employer/MDM-managed, the MDM-side decommission belongs to that organization; note it in the log.

3. Log it#

Append a row to the table below in the same PR (or the follow-up PR that completes the outside-the-repo steps).

Decommission log#

Date Asset Hardware Keys / credentials Backups Git SHA
2026-07-07 work-laptop (MBP 13” M1, A2338) Wiped; employer owns the Jamf/MDM-side decommission No sops anchor or repo SSH pubkeys ever existed; Tailscale node MacBook-Pro-0432 removed via admin console Borg repo 5e0c4351 frozen; 90-day retention, purge ≈ 2026-10-05 e4c9a9cd
2026-07-07 bedford-media-macmini (Intel Mac mini, Catalina) Wiped (FDE volume-key destruction = cryptographic erasure) Host age anchor removed; key is byte-identical to office mini’s, which retains it — residual risk accepted (disk wiped, no rotation). tsunami-media user key revoked via rekey (secrets.yaml 19→18 recipients). SSH pubkey + knownHosts entries removed. Tailscale node removal via admin console Borg repo 78538ed3 frozen; 90-day retention, purge ≈ 2026-10-05 a31c5d0c