(feature) Add host key scanning for SSH credentials
Add a host detail action that scans the target SSH host key with ssh-keyscan and stores it on the selected SSH credential. Merge scanned known_hosts entries without duplicates and let the existing runtime config pass them through as UserKnownHostsFile for unattended rsync over SSH. Extend host checks to warn when the selected credential has no known_hosts entries, making host key verification failures actionable from Django.
This commit is contained in:
@@ -30,7 +30,7 @@ from .models import BackupRun, GlobalConfig, HostConfig, ScheduleConfig, Snapsho
|
||||
from .retention import run_sql_retention_apply, run_sql_retention_plan
|
||||
from .self_check import collect_self_checks, summarize_self_checks
|
||||
from .snapshot_discovery import discover_snapshots, inspect_snapshot_discovery
|
||||
from .ssh_keys import SshKeyError, delete_generated_key_files, generate_ssh_key
|
||||
from .ssh_keys import SshKeyError, delete_generated_key_files, generate_ssh_key, merge_known_hosts, scan_known_host
|
||||
|
||||
|
||||
@staff_member_required
|
||||
@@ -289,6 +289,28 @@ def prepare_host_directories(request, host: str):
|
||||
return redirect("host_detail", host=host_config.host)
|
||||
|
||||
|
||||
@staff_member_required
|
||||
@require_POST
|
||||
def scan_host_known_key(request, host: str):
|
||||
host_config = get_object_or_404(HostConfig, host=host)
|
||||
global_config = GlobalConfig.objects.filter(name="default").first()
|
||||
credential = host_config.ssh_credential or (global_config.default_ssh_credential if global_config else None)
|
||||
if credential is None:
|
||||
messages.error(request, f"No SSH credential is selected for {host_config.host}.")
|
||||
return redirect("host_detail", host=host_config.host)
|
||||
|
||||
port = host_config.ssh_port or (global_config.ssh_port if global_config else 22)
|
||||
try:
|
||||
scanned = scan_known_host(host_config.address, port=int(port or 22))
|
||||
except SshKeyError as exc:
|
||||
messages.error(request, f"Could not scan SSH host key for {host_config.host}: {exc}")
|
||||
else:
|
||||
credential.known_hosts = merge_known_hosts(credential.known_hosts, scanned)
|
||||
credential.save(update_fields=["known_hosts", "updated_at"])
|
||||
messages.success(request, f"Stored SSH host key for {host_config.host} on credential {credential.name}.")
|
||||
return redirect("host_detail", host=host_config.host)
|
||||
|
||||
|
||||
@staff_member_required
|
||||
@require_POST
|
||||
def queue_manual_backup(request, host: str):
|
||||
|
||||
Reference in New Issue
Block a user