Don't offer to generate a root SSH key when one already works for the host

_backup_ensure_root_ssh_key() only ever checked for /root/.ssh/id_ed25519
or id_rsa by exact filename. Root can already SSH to the DR-spare/mirror
host just fine in practice (proven by this same script's own DR-spare sync
succeeding), just via a key with some other name — so the function had no
way to see that and always fell through to offering a copy-from-user-home
or brand-new ssh-keygen, both unnecessary.

Now takes the target host as an optional argument. When given, it tests
root's SSH access to that host as-is first and resolves the actual key via
`ssh -G <host>` (which expands ~/.ssh/config the same way the SFTP-dest
resolution earlier in this file already does) before falling back to the
copy/generate prompts. Both call sites (DR-spare, SFTP mirror) now pass
their respective host.

Verified against a mock ssh: an already-working non-default-named key gets
detected and reused with no prompts, and the original copy/generate
fallback still triggers correctly when SSH genuinely doesn't work yet.
This commit is contained in:
Claude
2026-08-14 20:09:03 +00:00
parent f6e5bb4ea3
commit 9edd821349
+27 -2
View File
@@ -216,9 +216,21 @@ register_service backup backup "Encrypted backup of all Docker services (full re
# has none. Prefers reusing that existing keypair over minting a fresh
# one, since the existing one may already be trusted where it's needed;
# ssh-copy-id-ing a brand new key is the fallback, not the first move.
#
# Takes an optional target host as $1. Confirmed live: root can already
# `ssh main` successfully — proven by this same script's own DR-spare sync
# succeeding — while root has neither /root/.ssh/id_ed25519 nor id_rsa. The
# working key just has some other filename (e.g. a ~/.ssh/config alias
# pointing at it). Without checking this first, the function would offer to
# generate/copy a redundant key instead of reusing the one that's already
# trusted where it's needed. When a host is given, this tests root's SSH
# access to it as-is and resolves the actual key ssh would use via `ssh -G`
# before falling back to the copy/generate prompts.
#
# Sets _ROOT_SSH_KEYFILE (out-param, not local) to the resulting keyfile
# path, empty if none is available/created.
_backup_ensure_root_ssh_key() {
local _target_host="${1:-}"
_ROOT_SSH_KEYFILE=""
if [ -f /root/.ssh/id_ed25519 ]; then
_ROOT_SSH_KEYFILE=/root/.ssh/id_ed25519; return 0
@@ -227,6 +239,19 @@ _backup_ensure_root_ssh_key() {
_ROOT_SSH_KEYFILE=/root/.ssh/id_rsa; return 0
fi
if [ -n "$_target_host" ] && ssh -o BatchMode=yes -o ConnectTimeout=5 "$_target_host" true 2>/dev/null; then
local _resolved_key
_resolved_key="$(ssh -G "$_target_host" 2>/dev/null | awk '/^identityfile /{print $2; exit}')"
_resolved_key="${_resolved_key/#\~/\/root}"
if [ -n "$_resolved_key" ] && [ -f "$_resolved_key" ]; then
log_success " root already has working SSH access to $_target_host via $_resolved_key — reusing it, not generating a new one."
_ROOT_SSH_KEYFILE="$_resolved_key"
return 0
fi
log_warning " root can already SSH to $_target_host, but its actual identity file (agent-based auth?)"
log_warning " can't be resolved to a file kopia can use directly — falling back below."
fi
local _user_key=""
[ -f "$ACTUAL_HOME/.ssh/id_ed25519" ] && _user_key="$ACTUAL_HOME/.ssh/id_ed25519"
[ -z "$_user_key" ] && [ -f "$ACTUAL_HOME/.ssh/id_rsa" ] && _user_key="$ACTUAL_HOME/.ssh/id_rsa"
@@ -604,7 +629,7 @@ install_backup() {
esac
fi
_backup_ensure_root_ssh_key
_backup_ensure_root_ssh_key "$DR_SYNC_HOST"
local _COPY_KEY=""
prompt_yn " Run ssh-copy-id to $DR_SYNC_HOST now? (asks for its login password interactively) (y/n):" "y" _COPY_KEY
@@ -865,7 +890,7 @@ install_backup() {
# sync-to sftp doesn't shell out to the system ssh client, so it
# needs an explicit key/known_hosts file rather than picking up
# whatever plain `ssh` already trusts automatically.
_backup_ensure_root_ssh_key
_backup_ensure_root_ssh_key "$_SFTP_DEST"
local _SFTP_KEYFILE="$_ROOT_SSH_KEYFILE"
if [ -z "$_SFTP_KEYFILE" ]; then