diff --git a/README.md b/README.md index 3d123a8..8b9a39a 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,8 @@ Each local snapshot is named `move-YYYYMMDD-HHMMSS`. - The destination host needs ZFS utilities and the destination pool must exist. - The SSH account on the destination must be able to execute `sudo -n zfs` without a password prompt. +- SSH must use a private key or SSH agent. Password authentication is disabled + by the script so a migration cannot pause and prompt once per dataset. - SSH connectivity and host-key verification must already work. The script is intended for one-shot full snapshot transfers. It does not use @@ -55,6 +57,32 @@ bash zfs-move-over-ssh.sh \ tank admin@new-server backup/tank ``` +## SSH Setup + +Create a dedicated key on the source server if one does not already exist: + +```bash +ssh-keygen -t ed25519 -f ~/.ssh/zfs-migration -C zfs-migration +``` + +Install its public key for the remote account. This one command may ask for the +remote account password during setup; the migration itself will not: + +```bash +ssh-copy-id -i ~/.ssh/zfs-migration.pub admin@new-server +``` + +Verify that authentication and remote ZFS access work without either password: + +```bash +ssh -i ~/.ssh/zfs-migration -o BatchMode=yes admin@new-server \ + 'sudo -n zfs list' +``` + +If this command fails, configure the remote account's `sudoers` entry for the +necessary `zfs` commands with `NOPASSWD` before running the migration. Do not +put a password in the script or on its command line. + Options: | Option | Description | diff --git a/zfs-move-over-ssh.sh b/zfs-move-over-ssh.sh index e31bdc2..e042c11 100644 --- a/zfs-move-over-ssh.sh +++ b/zfs-move-over-ssh.sh @@ -17,13 +17,14 @@ Arguments: Options: -n, --dry-run Print the ZFS and SSH commands without running them. - -i, --identity-file FILE SSH private key to use. + -i, --identity-file FILE SSH private key to use. -p, --ssh-port PORT SSH port to use. --destroy-source-snapshots Destroy each local migration snapshot after its successful receive. -h, --help Show this help. -The remote SSH account must be able to run `sudo -n zfs receive` without a -password prompt. This script does not destroy source filesystems or data. +SSH must use key or agent authentication; password prompts are disabled. The +remote SSH account must be able to run `sudo -n zfs receive` without a password +prompt. This script does not destroy source filesystems or data. EOF } @@ -34,7 +35,7 @@ die() { DRY_RUN=false DESTROY_SOURCE_SNAPSHOTS=false -SSH_OPTIONS=() +SSH_OPTIONS=(-o BatchMode=yes) while (($#)); do case "$1" in @@ -89,7 +90,7 @@ zpool list -H -o name "$SOURCE_POOL" >/dev/null || die "source pool does not exi if ! $DRY_RUN; then ssh "${SSH_OPTIONS[@]}" "$REMOTE_HOST" 'sudo -n zfs list -H -o name -t filesystem >/dev/null' \ - || die "cannot run 'sudo -n zfs' on $REMOTE_HOST" + || die "cannot connect with non-interactive SSH or run 'sudo -n zfs' on $REMOTE_HOST" fi map_destination() {