The problem
The goal is to automatically synchronize files between several hosts without
compromising the integrity of the separate machines. A nice tool for 2-way sync
is unison. To
sync files between different machines The Right Way (TM) is to tunnel the
unison protocol over ssh. This is well supported by unison.
To run sync automatically (e.g. via cron), you need to
create an SSH keypair
without passphrase, so unison can log into the other machine without human
interaction. This is where the problems start, since anyone who got access to
the private key (e.g. by compromising or stealing the machine the private key
was on) can log into the other host.
Now ssh has a nice way to restrict what you can do with a specific key, so you
can e.g. use the following in the remote hosts
~/.ssh/authorized_keys
:
command="/usr/bin/unison -server" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA8K2cd0yemw...
That way someone who has the private key can't execute arbitrary commands, but
just unison in server mode. However it's still possible to tell the unison
server to overwrite arbitrary files (which the user has write access to). This
is a major problem, since also files like ~/.bashrc
can be
overwritten, so the next time the user logs in, arbitrary commands will be
executed.
A possible solution
One solution is to simply create a new user on the remote host with a disabled
password, and let unison run as that user (via adding the appropriate line to
$HOME/.ssh/authorized_keys
, and telling the local unison to use
that username).
That's possible, but the .bashrc
trick still works, it's just less
likely that the code there is ever executed (root would have to use
su
to become that user).
For me this solution didn't work out since I wanted to sync my maildir, and it
was hard to ensure that file permissions were set in a way that both allowed me
to read my mail and allowed unison (running under user unison-sync) to sync the
files.
The Right Solution (TM)
All the problems vanish as soon as you run unison under the user you'd normally
use, but in a chroot. Now a full-blown chroot takes up a lot of space, and
there's once again the danger that someone might enter the chroot and run some
kind of shell (though the risk is even lower).
It's best to use a chroot which only contains the bare minimum of files
necessary to run unison -server
.
You get numerous advantages:
- No problems with file permissions
- No shell inside the chroot that would read startup files from
$HOME
.
- Hardly any space wasted. The whole chroot is about 4Mb in size
- Since the chroot is pretty much empty, many common exploits (well, shell codes) won't work
How to do it
greek0@orest:/home/chroots/unichroot$ cat ~/.ssh/authorized_keys
command="/usr/bin/dchroot -q -c unison -- /usr/bin/unison -server" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA8K2cd0.....
greek0@orest:/home/chroots/unichroot$ grep unison /etc/dchroot.conf
unison /home/chroots/unichroot
greek0@orest:/home/chroots/unichroot$ find . -maxdepth 3 | xargs ls -ld
drwxr-xr-x 2 root root 4096 2006-08-04 16:39 ./bin
-rwxr-xr-x 1 root root 576100 2006-08-04 15:06 ./bin/sash
lrwxrwxrwx 1 root root 4 2006-08-04 16:39 ./bin/zsh -> sash
drwxr-xr-x 3 root root 4096 2006-08-04 15:10 ./home
drwx------ 4 greek0 greek0 4096 2006-08-04 15:18 ./home/greek0
drwx------ 31 greek0 greek0 4096 2006-08-04 13:47 ./home/greek0/Maildir
drwx------ 2 greek0 greek0 4096 2006-08-04 15:47 ./home/greek0/.unison
drwxr-xr-x 2 root root 4096 2006-08-04 15:07 ./lib
-rwxr-xr-x 1 root root 88164 2006-08-04 14:58 ./lib/ld-linux.so.2
-rwxr-xr-x 1 root root 1151644 2006-08-04 14:56 ./lib/libc.so.6
-rw-r--r-- 1 root root 9592 2006-08-04 14:56 ./lib/libdl.so.2
-rw-r--r-- 1 root root 141040 2006-08-04 14:55 ./lib/libm.so.6
-rw-r--r-- 1 root root 9656 2006-08-04 14:55 ./lib/libutil.so.1
drwxr-xr-x 3 root root 4096 2006-08-04 14:53 ./usr
drwxr-xr-x 2 root root 4096 2006-08-04 14:55 ./usr/bin
lrwxrwxrwx 1 root root 14 2006-08-04 15:12 ./usr/bin/unison -> unison-2.13.16
-rwxr-xr-x 1 root root 955784 2006-08-04 14:54 ./usr/bin/unison-2.13.16
The zsh
symlink is there because I have /bin/zsh
as
my shell in /etc/passwd
, and dchroot also wants to use it in the
chroot (for launching unison).
/home/greek0/Maildir
is bind-mounted from outside the chroot,
bind-mounting is done at boot-time via /etc/fstab
.
The chroot was created manually, simply by copying the files from the host. You
obviously need /usr/bin/unison
plus all the libraries it depends
on. You can find those via readelf -d /usr/bin/unison | grep NEEDED
.
Additionally you need the dynamic linker /lib/ld-linux.so.2
(seen
from readelf -l /usr/bin/unison | grep INTERP -A 1
).
One thing to pay attention to is that most of the files copied from
/lib
are symlinks. Be sure to either use cp
without
arguments, or use cp -a
and copy the link targets too.