Archived
feat(provision): Phase 2 — migrate SSH host keys to clan vars
Replaces the gitignored host-keys/ directory with clan vars as the authoritative storage for SSH host keys. Keys are now generated as sops-binary-encrypted clan var files (admin-key only) and checked into vars/per-machine/<target>/openssh/, eliminating the plaintext private key that previously had to live outside the repo. Changes: - modules/clan/ssh-host-key.nix: clan vars generator for the ed25519 SSH host key pair (neededFor="activation" — not mapped to sops.secrets, delivered via tarball baking for LXC or --pre-format-files for VMs) - flake.nix: add clanCore module + required settings to every mkTarget; deduplicate bundled disko/sops-nix via follows; all 27 hosts eval clean - flake.lock: updated to reflect the new follows constraints - scripts/lib/clan-vars.sh: new helper library with clan_ssh_key_exists / clan_ssh_pubkey_path / clan_decrypt_ssh_key / clan_generate_ssh_key for use by the provisioning and sync scripts - scripts/secrets/sync-host-keys.sh: queue_host_sync() now checks clan vars first; generates via clan_generate_ssh_key if no key exists; derives age fingerprint from clan pub key for .sops.yaml registration - scripts/proxmox/create-proxmox-resource.sh: key management simplified (sync-host-keys.sh now generates the key if missing, so the inline prepare-host-key.sh call is gone); sync_remote_host_keys() decrypts the clan key into a temp dir and scps just the two files to the node when a clan key exists, falling back to the old host-keys/ scp for any remaining legacy entries Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B2EJ4qTsM5KUqhS5c3GAwx
This commit is contained in:
@@ -39,6 +39,8 @@ source "${repo_root}/scripts/lib/ssh-host-keys.sh"
|
||||
source "${repo_root}/scripts/lib/sops-age.sh"
|
||||
# shellcheck source=../lib/confirm.sh
|
||||
source "${repo_root}/scripts/lib/confirm.sh"
|
||||
# shellcheck source=../lib/clan-vars.sh
|
||||
source "${repo_root}/scripts/lib/clan-vars.sh"
|
||||
|
||||
mkdir -p "$keydir"
|
||||
|
||||
@@ -146,13 +148,15 @@ dry_run=0
|
||||
queue_host_sync() {
|
||||
local host="$1"
|
||||
local keyfile="${keydir}/${host}_ssh_host_ed25519_key"
|
||||
local has_local_key=0 has_anchor=0
|
||||
local has_local_key=0 has_clan_key=0 has_anchor=0
|
||||
[[ -f "$keyfile" ]] && has_local_key=1
|
||||
clan_ssh_key_exists "$host" "$repo_root" && has_clan_key=1
|
||||
grep -qE "^ - &${host} age1" "$sops_yaml" && has_anchor=1
|
||||
|
||||
if [[ "$has_local_key" -eq 0 && "$has_anchor" -eq 1 ]]; then
|
||||
if [[ "$has_local_key" -eq 0 && "$has_clan_key" -eq 0 && "$has_anchor" -eq 1 ]]; then
|
||||
echo "SKIP ${host}: .sops.yaml already has an &${host} anchor, but"
|
||||
echo " host-keys/${host}_ssh_host_ed25519_key is missing locally."
|
||||
echo " neither host-keys/${host}_ssh_host_ed25519_key nor"
|
||||
echo " vars/per-machine/${host}/openssh/ exist locally."
|
||||
echo " Not generating a replacement -- it wouldn't match whatever's"
|
||||
echo " already registered (and possibly deployed). Remove the"
|
||||
echo " &${host} line from .sops.yaml first if you really want a"
|
||||
@@ -160,21 +164,26 @@ queue_host_sync() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "$has_local_key" -eq 0 ]]; then
|
||||
if [[ "$has_local_key" -eq 0 && "$has_clan_key" -eq 0 ]]; then
|
||||
if [[ "$dry_run" -eq 1 ]]; then
|
||||
echo "[dry-run] ${host}: would generate host key"
|
||||
echo "[dry-run] ${host}: would generate host key via clan vars"
|
||||
else
|
||||
echo "==> ${host}: generating host key"
|
||||
generate_host_ed25519_key "$host" "$keyfile"
|
||||
echo "==> ${host}: generating host key via clan vars"
|
||||
clan_generate_ssh_key "$host" "$repo_root"
|
||||
has_clan_key=1
|
||||
fi
|
||||
elif [[ "$has_clan_key" -eq 1 ]]; then
|
||||
echo "==> ${host}: clan-managed SSH host key already present"
|
||||
else
|
||||
echo "==> ${host}: host key already present"
|
||||
echo "==> ${host}: host key already present (host-keys/)"
|
||||
fi
|
||||
|
||||
if [[ "$has_anchor" -eq 0 ]]; then
|
||||
local age_pub
|
||||
if [[ "$dry_run" -eq 1 ]]; then
|
||||
age_pub="dry-run-placeholder-not-a-real-key"
|
||||
elif [[ "$has_clan_key" -eq 1 ]]; then
|
||||
age_pub="$(ssh_pubkey_to_age "$(clan_ssh_pubkey_path "$host" "$repo_root")")"
|
||||
else
|
||||
age_pub="$(ssh_pubkey_to_age "${keyfile}.pub")"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user