Tim's blah blah blah

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 (medium.com) (A) (archive.org), Guy Rutenberg’s (guyrutenberg.com) (A) (archive.org) and Shakko’s (schakko.de) (A) (archive.org) 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:

I achieved this as follows:

  1. 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}
    
  2. 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}
    
  3. Next we chroot SSH access (archlinux.org) 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
    
  4. 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} ./*
    
  5. 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 and schroot, see e.g. this guide (linoxide.com)
    bash <(curl -s "http://web.archive.org/web/20201129094849/https://tools.deltazero.cz/server/setup.chroot.for.rsync.sh")
    
  6. Copy rrsync & perl + libraries to chroot (cyberciti.biz) as well to use dynamic automated rsync remote command (stackexchange.com). 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 the rrsync 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
    
  7. Finally lock the chroot directory as required by sshd (serverfault.com)
    sudo chown root:root ${BACKUPDIR}
    sudo chmod 755 ${BACKUPDIR}
    
  8. Make passwordless ssh key using RSA key type. While elliptic curves are nice, their primary benefit (smaller keys) (wikipedia.org) is irrelevant for my use case. Also, RSA is slightly more resistant (wikipedia.org) to quantum computing attacks, and there are no widely adoptied post-quantum schemes (wikipedia.org) yet. We use a paranoid large key totally overkill for our situation.
    ssh-keygen -b 4096 -t rsa -f ~/.ssh/id_rsa_backup
    
  9. Copy ssh key to home directory outside chroot jail, give reduced permissions (use restrict instead of iterating (and potentially forgetting) all options) and only allow rsync.
    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
    
  10. 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/
    
  11. Error “protocol version mismatch – is your shell clean?”
    1. Ensure output of ssh user@remoteserver.tld /bin/true is nothing
    2. Ensure the directory rsync points to works
    3. Try something without the command= prefix in authorized_keys

Alternatives

Some other methods to set up a limited access rsync server:

  1. Use a restricted shell (org.ua), see e.g. this guide (cyberciti.biz) - I opted for a stronger chroot jail instead.
  2. Use only restricted rsync (rrsync) (samba.org), see e.g. this guide (schwertly.com) - I opted for a stronger additional chroot jail instead

#Linux #Security #Server