diff --git a/CLAUDE.md b/CLAUDE.md index fc160bd..b0113f0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -27,12 +27,13 @@ machines when deployed. template for a *real* host — every other host uses sops-nix (`hashedPasswordFile`, see "Security Notes" in `README.md`). Flag any *new* secret-like string you encounter instead of committing it. -- `host-keys/` is gitignored — locally-generated *private* SSH host keys - for the auto-installer and non-LXC hosts (see `docs/auto-installer.md`). - Never commit its contents; if `git status` ever shows it as trackable, - something is wrong. Deployed LXC hosts use clan vars - (`vars/per-machine//openssh/`, committed and sops-encrypted) - instead — those ARE tracked by git and belong in the repo. +- `host-keys/` is gitignored — used only by the auto-installer's own + environment for pre-seeding non-LXC host keys before first boot (see + `docs/auto-installer.md`). Never commit its contents; if `git status` + ever shows it as trackable, something is wrong. All deployed hosts use + clan vars (`vars/per-machine//openssh/`, committed and + sops-encrypted) for their SSH host keys — those ARE tracked by git and + belong in the repo. ### Two Proxmox nodes: `pve1.sweet.home` (production) and `pve-test.sweet.home` (sandbox) @@ -206,11 +207,11 @@ instead of copying it. - `scripts/secrets/sync-host-keys.sh` — generates/registers SSH host keys and their `.sops.yaml`/`secrets/*.yaml` recipients for flake targets, idempotently (`--all`, ``, `--remove`, `--regenerate-all-keys`, - all with `--dry-run`). For lxc-* targets it stores keys as clan vars - (`vars/per-machine//openssh/`, committed and sops-encrypted); - for other targets it uses the gitignored `host-keys/` directory. The - primary tool for provisioning a new host's secrets access — see - "Creating a new machine" in `docs/auto-installer.md`. + all with `--dry-run`). Stores keys as clan vars + (`vars/per-machine//openssh/`, committed and sops-encrypted) for + all flake targets. The primary tool for provisioning a new host's + secrets access — see "Creating a new machine" in + `docs/auto-installer.md`. - `scripts/secrets/prepare-host-key.sh` — narrower predecessor: generates a key by an arbitrary name without touching `.sops.yaml`. Still useful to pre-generate a key before its flake target exists yet, since diff --git a/README.md b/README.md index 8e4bad2..388534a 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ nix eval --json .#nixosConfigurations --apply builtins.attrNames | jq -r '.[]' | `modules/common/` | Shared NixOS config, Home Manager, aliases imported by every host | | `modules/nix-cache/` | Binary cache and remote builder client/server modules | | `modules/installer/` | Auto-installer environment (ISO, also served as PXE netboot) — see `docs/auto-installer.md` | -| `host-keys/` | Gitignored, locally-generated SSH host keys for the auto-installer (non-LXC hosts) — see `docs/auto-installer.md`. LXC hosts use clan vars (`vars/per-machine//openssh/`) instead | +| `host-keys/` | Gitignored; only used by the auto-installer environment for pre-seeding SSH host keys before first boot — see `docs/auto-installer.md`. All deployed hosts use clan vars (`vars/per-machine//openssh/`) instead | | `vars/per-machine/` | Clan vars: committed, sops-encrypted SSH host keys for deployed LXC hosts; read by `create-proxmox-resource.sh` at deploy time | | `docs/` | Operational notes for cache, builders, lock updates, boot services, the auto-installer, and Proxmox image builds | | `scripts/` | Codex setup, validation, host-key, release-bump, and Proxmox resource helpers | @@ -163,8 +163,9 @@ sops-nix-everywhere: it has a hardcoded login password instead (no stable per-boot host key for sops-nix to derive from on ephemeral media) — see "Host keys" in `docs/auto-installer.md` for why, and how the private keys it *does* pre-seed for target hosts stay out of git via the gitignored -`host-keys/` directory. Deployed LXC hosts instead use clan vars -(`vars/per-machine//openssh/`, committed and sops-encrypted). +`host-keys/` directory. All deployed hosts use clan vars +(`vars/per-machine//openssh/`, committed and sops-encrypted) for +their SSH host keys. This repository's git *history* still contains secrets committed before this migration (see `remove-sensetive-info-refactor.md`) — those are being diff --git a/scripts/secrets/sync-host-keys.sh b/scripts/secrets/sync-host-keys.sh index e089e7e..e50ab36 100755 --- a/scripts/secrets/sync-host-keys.sh +++ b/scripts/secrets/sync-host-keys.sh @@ -135,10 +135,17 @@ discover_targets() { } locally_managed_hosts() { - for f in "$keydir"/*_ssh_host_ed25519_key.pub; do - [[ -e "$f" ]] || continue - basename "$f" _ssh_host_ed25519_key.pub - done + { + for f in "$keydir"/*_ssh_host_ed25519_key.pub; do + [[ -e "$f" ]] || continue + basename "$f" _ssh_host_ed25519_key.pub + done + local d + for d in "${repo_root}/vars/per-machine"/*/openssh/ssh_host_ed25519_key/secret; do + [[ -f "$d" ]] || continue + basename "$(dirname "$(dirname "$(dirname "$d")")")" + done + } | sort -u } add_keys_json="[]" @@ -317,7 +324,9 @@ cmd_remove() { for host in "${hosts[@]}"; do local registered="not registered in .sops.yaml" grep -qE "^ - &${host} age1" "$sops_yaml" && registered="registered in .sops.yaml" - printf ' %d) %s (%s)\n' "$i" "$host" "$registered" + local where="host-keys/" + clan_ssh_key_exists "$host" "$repo_root" && where="clan-vars" + printf ' %d) %s [%s, %s]\n' "$i" "$host" "$where" "$registered" i=$((i + 1)) done @@ -334,7 +343,7 @@ cmd_remove() { local target="${hosts[$((choice - 1))]}" if [[ "$dry_run" -ne 1 ]]; then - read -rp "Really remove '${target}'? Its host-keys/ files will be deleted and it will lose access to every secrets file it can currently decrypt. (y/N): " confirm + read -rp "Really remove '${target}'? Its key files will be deleted and it will lose access to every secrets file it can currently decrypt. (y/N): " confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then echo "Cancelled." return @@ -347,11 +356,13 @@ cmd_remove() { apply_edit_plan "$plan" if [[ "$dry_run" -eq 1 ]]; then - echo "[dry-run] would delete host-keys/${target}_ssh_host_ed25519_key(.pub)." + echo "[dry-run] would delete host-keys/${target}_ssh_host_ed25519_key(.pub) if present." + echo "[dry-run] would delete vars/per-machine/${target}/openssh/ if present." echo "[dry-run] Nothing was changed. Re-run without --dry-run to apply this." else rm -f "${keydir}/${target}_ssh_host_ed25519_key" "${keydir}/${target}_ssh_host_ed25519_key.pub" - echo "Removed host-keys/${target}_ssh_host_ed25519_key(.pub)." + rm -rf "${repo_root}/vars/per-machine/${target}/openssh" + echo "Removed key for ${target} (host-keys/ and/or vars/per-machine/ as applicable)." echo echo "Review the diff, then commit and push." fi @@ -390,8 +401,8 @@ cmd_regenerate_all() { apply_edit_plan "$plan" if [[ "$dry_run" -eq 1 ]]; then - echo "[dry-run] would delete ${#hosts[@]} host-keys/ file pair(s)." - echo "[dry-run] would then generate fresh replacements for the same hosts" + echo "[dry-run] would delete ${#hosts[@]} key pair(s) from host-keys/ and/or vars/per-machine/." + echo "[dry-run] would then generate fresh clan vars replacements for the same hosts" echo "[dry-run] (not simulated further here -- run without --dry-run, or" echo "[dry-run] preview a specific target with: $0 --dry-run)." echo @@ -403,8 +414,9 @@ cmd_regenerate_all() { local host for host in "${hosts[@]}"; do rm -f "${keydir}/${host}_ssh_host_ed25519_key" "${keydir}/${host}_ssh_host_ed25519_key.pub" + rm -rf "${repo_root}/vars/per-machine/${host}/openssh" done - echo "Removed ${#hosts[@]} host-keys/ file pair(s)." + echo "Removed ${#hosts[@]} key pair(s)." echo echo "Regenerating fresh keys for every current flake target..."