Archived
Fix nix-cache remote-builder trust: stale host key + wrong sshKey path
Check NixOS configurations / eval-hosts (pull_request) Failing after 11m12s
Check NixOS configurations / eval-hosts (pull_request) Failing after 11m12s
variables.nix's nixCacheHostKey no longer matched nix-cache's actual SSH host key (confirmed via ssh-keyscan against the live container), so every declaratively-configured client's programs.ssh.knownHosts trusted the wrong key -- distributed builds would fail host-key verification. Also, modules/nix-cache/remote-builder-client.nix hardcoded sshKey to /root/.ssh/nixremote, but the `server` host only has its own default /root/.ssh/id_ed25519 installed (confirmed live via qm guest-agent) -- that file was never even present, so the build machine config pointed at nothing. Standardize on each client's own default identity, matching the per-host-key pattern vars.remoteBuilderAuthorizedKeys already uses instead of a shared/differently-named keypair, and add scripts/secrets/sync-nix-cache-host-key.sh (wired into codex-maintenance.sh's --check) so the host-key drift doesn't silently recur next time nix-cache is rebuilt or recreated. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V7yVH71vGrDVzovh9UaMu8
This commit is contained in:
Executable
+110
@@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env bash
|
||||
# Detects and fixes drift between the ed25519 SSH host key nix-cache is
|
||||
# actually serving right now and vars.nixCacheHostKey (variables.nix) --
|
||||
# the value modules/nix-cache/remote-builder-client.nix bakes into every
|
||||
# client's declarative programs.ssh.knownHosts, and
|
||||
# scripts/proxmox/configure-nix-cache-client.sh hardcodes as its own
|
||||
# default for non-NixOS clients.
|
||||
#
|
||||
# This value has no automatic source of truth: nix-cache's host key is
|
||||
# generated once (first boot / container recreate) and never touches this
|
||||
# repo again unless someone remembers to update it by hand afterwards. It
|
||||
# drifted silently once already -- confirmed live: variables.nix recorded
|
||||
# a key that no longer matched what nix-cache actually presented, which
|
||||
# would fail every real client's SSH host-key verification for
|
||||
# distributed builds without ever producing an obvious error pointing
|
||||
# back here (a client just sees "Host key verification failed" against
|
||||
# *some* key, with no hint that the trusted value itself was stale).
|
||||
#
|
||||
# codex-maintenance.sh runs this in --check mode on every invocation so
|
||||
# that drift surfaces as a warning instead of a future debugging session.
|
||||
#
|
||||
# Usage:
|
||||
# scripts/secrets/sync-nix-cache-host-key.sh [--check] [--dry-run] [--host <name>]
|
||||
#
|
||||
# --check Only report drift (exit 1 if found, 2 if nix-cache is
|
||||
# unreachable); never writes. For CI/maintenance use.
|
||||
# --dry-run Show what would change; never writes.
|
||||
# --host Override the hostname to scan (default: variables.nix's
|
||||
# nixCacheHost / env.sh's NIX_CACHE_HOST).
|
||||
set -euo pipefail
|
||||
|
||||
repo_root="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
variables_nix="${repo_root}/variables.nix"
|
||||
client_script="${repo_root}/scripts/proxmox/configure-nix-cache-client.sh"
|
||||
|
||||
# shellcheck source=../env.sh
|
||||
source "${repo_root}/scripts/env.sh"
|
||||
|
||||
check_only=0
|
||||
dry_run=0
|
||||
host="${NIX_CACHE_HOST}"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--check) check_only=1; shift ;;
|
||||
--dry-run) dry_run=1; shift ;;
|
||||
--host)
|
||||
host="${2:?--host requires a hostname}"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
sed -n '2,23p' "$0"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: unknown argument: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
current_value="$(grep -oE 'nixCacheHostKey = "[^"]+"' "$variables_nix" | sed -E 's/nixCacheHostKey = "(.*)"/\1/')"
|
||||
if [[ -z "$current_value" ]]; then
|
||||
echo "ERROR: couldn't find nixCacheHostKey in $variables_nix" >&2
|
||||
exit 1
|
||||
fi
|
||||
current_type_blob="$(awk '{print $1, $2}' <<<"$current_value")"
|
||||
current_label="$(awk '{print $3}' <<<"$current_value")"
|
||||
|
||||
echo "Scanning ${host} for its current ed25519 SSH host key..."
|
||||
nix_extra_opts
|
||||
scanned="$(nix-shell "${NIX_OPTS[@]}" -p openssh --run "ssh-keyscan -t ed25519 -T 5 '${host}'" 2>/dev/null | grep -v '^#' | head -1 || true)"
|
||||
if [[ -z "$scanned" ]]; then
|
||||
echo "ERROR: couldn't reach ${host} (or got no ed25519 host key back) via ssh-keyscan." >&2
|
||||
exit 2
|
||||
fi
|
||||
scanned_type_blob="$(awk '{print $2, $3}' <<<"$scanned")"
|
||||
|
||||
if [[ "$current_type_blob" == "$scanned_type_blob" ]]; then
|
||||
echo "Up to date: ${host}'s host key matches variables.nix's nixCacheHostKey."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "DRIFT DETECTED:"
|
||||
echo " variables.nix has: $current_type_blob"
|
||||
echo " ${host} is now: $scanned_type_blob"
|
||||
|
||||
if [[ "$check_only" -eq 1 ]]; then
|
||||
echo
|
||||
echo "Run 'scripts/secrets/sync-nix-cache-host-key.sh' (no flags) to fix." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
new_value="${scanned_type_blob} ${current_label}"
|
||||
|
||||
if [[ "$dry_run" -eq 1 ]]; then
|
||||
echo "(--dry-run: would update variables.nix and ${client_script##*/} to:)"
|
||||
echo " $new_value"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
sed -i "s|nixCacheHostKey = \"[^\"]*\"|nixCacheHostKey = \"${new_value}\"|" "$variables_nix"
|
||||
sed -i "s|NIX_CACHE_HOST_KEY:=[^}]*}|NIX_CACHE_HOST_KEY:=${new_value}}|" "$client_script"
|
||||
|
||||
echo "Updated variables.nix and ${client_script##*/} to:"
|
||||
echo " $new_value"
|
||||
echo
|
||||
echo "This only takes effect on already-deployed NixOS clients after their"
|
||||
echo "next rebuild (programs.ssh.knownHosts is declarative). Review with"
|
||||
echo "'git diff', then run 'bash scripts/codex-maintenance.sh' before committing."
|
||||
Reference in New Issue
Block a user