rsync over SSL

Description

The Right Way(tm) of doing rsync over SSL. Uses stunnel 4.x.

How to download

git clone http://dozzie.jarowit.net/code/rsync-ssl.git

How to build

TODO

How to use

TODO

How does it work?

Typical setup

 stunnel is used by most of how-tos out there on how to encapsulate rsync in SSL. This kind of setup is pretty simple: you need to start two stunnel daemons:

  1. On the rsync/SSL server side, stunnel accepts SSL connection, decrypts it and forwards to rsync --daemon, which is bound to 127.0.0.1 address.
  2. On the rsync/SSL client side, stunnel accepts raw protocol connection, encapsulates it with SSL and forwards to the daemon from the previous point.

On client side, your rsync connects to localhost:<stunnel-port>. This approach is ugly, troublesome, can lead to security issues and it doesn't scale.

Ugliness

Three daemons while my hunch says one is enough. Isn't it ugly? And imagine that you need to maintain all of them!

Troublesomeness

Your rsync can't connect to the server. Which connection is broken? To client stunnel daemon? To server stunnel? To rsync daemon?

Security

Imagine that you have authentication/authorization based on client SSL certificates. It's great unless an untrusted user can connect to client stunnel daemon, and he can connect if he has an account on client machine. Or unless he can connect to rsync daemon, which is the case when he has an account on server machine.

Sure, you can limit who can connect to which ports using owner netfilter module, but this makes complicated setup just more complicated. Do you really want this?

Scalability

You have a client daemon to connect to one server. Now you want to use another SSL enabled rsync server. And another. And another three. Pop! And suddenly you're maintaining on client machine daemons for each rsync server you use. Now try to remember which server is assigned to which port. And what if you just need to use the server once? You still need to setup a new stunnel daemon.

Correct setup

First of all, let's get rid of client stunnel.

stunnel can work in inetd-mode. This means, instead of listening on some TCP port for plain-text connections it can take STDIN/STDOUT. Now think of how rsync works over SSH: /usr/bin/rsync spawns ssh user@somehost, which executes /usr/bin/rsync on the remote side, and then local rsync talks to ssh's STDIN/STDOUT.

Hey! That's exactly what inetd-mode is! Can we use /usr/bin/stunnel instead of /usr/bin/ssh? Of course we can. This is what rsync has the --rsh option for.

Now we want to dispense with one daemon on the server side.

stunnel in server mode, instead of connecting to some TCP port can spawn an external program (config options exec and execargs). Very much like inetd. On the other side, rsync can work under inetd. Combining these two, you get stunnel spawning rsync. Single daemon instead of two, and nobody can connect to rsync daemon unless connects to stunnel first.

As a bonus you'll get automatic reloading of any changes in rsyncd.conf that doesn't kill currently established connections. Looks like a win-win to me.