Passwordless secure rsync backups over ssh
(Updated: )
I mirror my backups remotely on a server with as few privileges as possible, while ensuring the confidentiality of my backup. I build on David Obdržálek’s (A), Guy Rutenberg’s (A) and Shakko’s (A) guides.
Setup ¶
I have a TimeMachine backup to my server which I want to mirror remotely. On the remote server I want to ensure the account has as few credentials as possible (because I offer the reciprocal service to a friend). This is achieved in 2 layers:
- Restrict ssh access via
authorized_keys
. chroot
user in backup directory
I achieved this as follows:
- First we create a backup user without password (thereby preventing
bruteforece ssh login).
NEWUSER="user" sudo useradd --home-dir /home/${NEWUSER} --shell /usr/bin/sh ${NEWUSER}
- Prepare the target directory to receive backups, in this case
through a zfs pool.
BACKUPPOOL=pool0/backup${NEWUSER} BACKUPDIR=/pool0/backup${NEWUSER} sudo zfs create ${BACKUPPOOL} sudo zfs set quota=1500G ${BACKUPPOOL} sudo mkdir -p ${BACKUPDIR}
- Next we chroot SSH access
for this user. N.B./TODO I didn’t get the ssh config to work in the separate
.conf
file so in reality I appended this to/etc/ssh/sshd_config
.cat << EOF | sudo tee /etc/ssh/sshd_config.d/backup${NEWUSER}.conf Match User ${NEWUSER} ChrootDirectory /pool0/backup${NEWUSER} EOF # test new config and restart sudo /usr/sbin/sshd -t sudo service sshd restart
- Prepare chroot jail. Note that we recreate an empty homedir here which the
shell will
cd
to upon login.sudo mkdir etc log backup sudo mkdir -p home/${NEWUSER} sudo chown --recursive ${NEWUSER}:${NEWUSER} ./*
- Populate with minimal binaries and libraries (or download the script and
execute yourself line by line). Alternatively you can setup a ‘minimal’ Ubuntu
environment at ~500MB using
debootstrap
andschroot
, see e.g. this guidebash <(curl -s "http://web.archive.org/web/20201129094849/https://tools.deltazero.cz/server/setup.chroot.for.rsync.sh")
- Copy rrsync & perl + libraries to chroot as well to use dynamic automated rsync remote command. Alternatively you can use a hard-coded server-side rsync command like
/usr/bin/rsync --server -vvlogDtprze.iLsf . /backup
, but I prefer the versatility of therrsync
script. The drawback is that you need perl + libs in your chroot, eating up 100x more space than if you use a hard-coded command.cd ${BACKUPDIR} copies=$((ldd `which perl`) | awk '/\// { print ($3 ? $3 : $1) }' | sort | uniq) copies+=" $(which rrsync) $(which perl)" for f in $copies; do d=$(dirname ${f}) [[ ! -d ".$d" ]] && sudo mkdir -p ".$d" [[ ! -f ".$f" ]] && sudo cp -v "$f" ".$f" done sudo mkdir -p ${BACKUPDIR}/usr/share sudo cp -r /usr/share/perl ${BACKUPDIR}/usr/share # sudo cp -r /usr/share/perl5 /pool0/backup${NEWUSER}/usr/share # optional - I did not need this sudo mkdir -p ${BACKUPDIR}/usr/lib/x86_64-linux-gnu sudo cp -r /usr/lib/x86_64-linux-gnu/perl ${BACKUPDIR}/usr/lib/x86_64-linux-gnu # sudo cp -r /usr/lib/x86_64-linux-gnu/perl5 /pool0/backup${NEWUSER}/usr/lib/x86_64-linux-gnu # optional - I did not need this
- Finally lock the chroot directory as required by sshd
sudo chown root:root ${BACKUPDIR} sudo chmod 755 ${BACKUPDIR}
- Make passwordless ssh key using RSA key type. While elliptic curves are nice,
their primary benefit (smaller keys)
is irrelevant for my use case. Also, RSA is slightly more resistant
to quantum computing attacks, and there are no widely adoptied post-quantum schemes yet. We use a paranoid large key
totally overkill for our situation.
ssh-keygen -b 4096 -t rsa -f ~/.ssh/id_rsa_backup
- Copy ssh key to home directory outside chroot jail, give reduced
permissions (use
restrict
instead of iterating (and potentially forgetting) all options) and only allowrsync
.scp ~/.ssh/id_rsa_backup.pub admin@remoteserver.tld: ssh admin@remoteserver.tld sudo mkdir -p /home/${NEWUSER}/.ssh/ sudo chown ${NEWUSER}:${NEWUSER} --recursive /home/${NEWUSER}/.ssh echo -n "restrict,command=\"/usr/bin/rrsync /backup/\"" | sudo tee --append /home/${NEWUSER}/.ssh/authorized_keys cat ~/id_rsa_backup.pub | sudo tee --append /home/${NEWUSER}/.ssh/authorized_keys
- Done. Do magic
rsync -e "ssh -i ~/.ssh/id_rsa_backup" --checksum --hard-links --xattrs --archive --human-readable --verbose --info=progress2 /src/ ${NEWUSER}@remoteserver.tld:target/
- Error “protocol version mismatch – is your shell clean?”
- Ensure output of
ssh user@remoteserver.tld /bin/true
is nothing - Ensure the directory rsync points to works
- Try something without the
command=
prefix inauthorized_keys
- Ensure output of
Alternatives ¶
Some other methods to set up a limited access rsync server:
- Use a restricted shell, see e.g. this guide - I opted for a stronger chroot jail instead.
- Use only restricted rsync (
rrsync
), see e.g. this guide - I opted for a stronger additional chroot jail instead