Linux: How to rsync incrementally to a remote where root logins per ssh are not permitted

Introduction

Today I learned something new again!

I have been struggling with both cpio and rsync when I need to copy files from one system to another and preserve ownerships and permissions, as I thought I had to connect to the remote host as root@destination, which in most of my environments is not allowed. Using “tar” is easy, since you can send the content per stdoud and do “sudo tar cvpf - . | ssh myUser@destination “cd /path/to/dest; sudo tar xpf -” to run tar as root the other side of the pipe.

This can be done using different approaches (these examples are not incremental) using tar and cpio:

  • cd /path/to/source ; sudo tar cvpf - . | ssh myUser@destination "cd /path/do/dest ; sudo tar xpf -"
  • find /path/to/source -type f | cpio -o | ssh myUser@destination "sudo cpio -itv"

But, then I often want to migrate applications (where dockerized applications has made it even easier than ever before) with lots of data. Preparing a bulk copy in beforehand helps keeping the downtime to something manageable. Migrating a Graylog server would normally take hour of downtime of the applicaiton if all data had to be copied after the application has been stopped. With an incremental copy, you do this once for the full copy of all data, then frequently run it again before the migration event. Each incremental copy then usually takes minutes instead of hours (your milage may vary).

Solution

Since root can read anything in a filesystem, we can exploit a sort of weakness in how ssh-agent forwarding works. When connecting to a host using “ssh -A”, you bring your local ssh agent with you. On the host you are connected to, ssh will use a socket in the path set up in the “SSH_AUTH_SOCK” to communicate with your ssh agent on your local host.

The following happily tells root to use my forwarded agent, and the new learning for to day was that rsync has the --rsync-path parameter that I was not aware of before.

  • TL/DR: This is now my new favorite way to copy files incrementally from one system to another using rsync, where myUser is a user with sudo permissions without password on the destination host:
sudo --preserve-env=SSH_AUTH_SOCK rsync -avzP --delete /mnt/graylog/ myUser@destination:/mnt/graylog/ --rsync-path="sudo rsync"