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)#
- Delete the host’s entry from
hosts/default.nixand its directory/file underhosts/<system>/. Tag-driven discovery (builder/cache) drops the host from everynix.buildMachineslist automatically. - Remove the host’s SSH public keys from
modules/darwin/security/pubkeys/andmodules/nixos/security/pubkeys/(the NixOS side auto-globs the directory) and any explicitknownHostsentry inmodules/darwin/security/default.nix. - Remove the host from every
deploy.monitoredHostslist (grep the hostname — a dead entry generates offline alerts every health-check cycle). - 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(it discovers every tracked sops file by content, so it re-keyspki/db/*.sopsas well assecrets.yaml; today it aborts on three orphan-recipient files underpki/db/recovery_files/— see CA escrow), then verify your own key still decrypts:sops --decrypt secrets.yaml > /dev/null. If you hold apki/dbkey (onlytsunami-mokou/tsunami-shinobuper.sops.yaml), also verifysops --decrypt pki/db/FalseBlue-CA.xdb.sops > /dev/null; otherwise ask one of those two key holders to. Notepki/db/recovery_files/private_keys.yamlmatches both creation rules (^pki/dband the unanchoredsecrets.yaml$), so spot-check its recipients after any.sops.yamledit. - Never remove your own user keys — rekey rollback depends on them. - Remove the BorgWarehouse registry entry from
modules/nixos/borg/repo.json. - Docs: delete the machine page, fix inbound links, remove the node from the
manual topology (
modules/topology/default.nix), update.claude/hosts.md. - Verify:
nix flake check,just docs-build, grep for the hostname → empty, eval the remaining darwin/nixos configurations. - Redeploy hosts whose
buildMachines/knownHosts/monitoring changed.
2. Outside the repo#
- Tailscale admin console — remove the node; confirm its device and any auth keys are gone from the tailnet.
- 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.
- 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.
- Third-party management — if the machine was employer/MDM-managed, the MDM-side decommission belongs to that organization; note it in the log.
Host disabled but hardware retained#
Not every host that leaves hosts/default.nix is disposed of. The two
Catalina Mac minis are the live example (paused 2026-08-14; entries commented
out because nixpkgs 26.11 dropped x86_64-darwin). Rule:
- Paused (may return): keep the host’s age anchor and its per-host user key
in
.sops.yamland keep itsborgmatic/<host>secrets — the hardware is still in use and may be re-pinned. Mark the anchors with a comment in.sops.yaml(“paused“) and register the host in In-flight work. No log row: nothing was disposed of. - Retired (will not return): run steps 1–3 in full, including the sops revocation and a log row, even if the disk stays in a drawer — cryptographic erasure of the volume key is the sanitization floor.
Decide explicitly; “commented out and forgotten” is the state this section exists to prevent.
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 |