Pages

Tuesday, 24 July 2012

rsync as root with rrsync and sudo

Here's how to rsync something to a remote host as root without allowing root logins and with directory restriction. I did that because I wanted to sync /srv across servers.

In general it will use rsync over ssh, sudo, rrsync and a remote non-root user. I assume that rsync will run from srv1 to srv2.

rrsync


First you will need the rrsync (or rrsync.pl) script ad the server side that's part of the rsync package. In Debian you can find it at /usr/share/doc/rsync/scripts/rrsync.gz. This script acts as the server side and will restrict the destination directory (a'la chroot).

In short the server side will run "rrsync /srv". Then the client side will do something like this:

[code light="true"]
# rsync /srv remote:/
[/code]

and / will be relative to /srv that was defined as a parameter to rrsync.

You can put rrsync under /usr/local/bin.

User on srv2


At the destination server we will need a user that will be used for the ssh session. So go and create a user named 'syncer' on srv2. I'd avoid a username of 'rsync' as it may be used for other reasons at some point.

sudo on srv2


The user on srv2 should be able to run rrsync with sudo and with the -E parameter. -E is required in order to pass the checks of the rrsync script which checks for SSH_ORIGINAL_COMMAND in the environment. Feel free to make this even more strict to allow only this environment variable if you like.

Sample sudoers entry (e.g. to be put in /etc/sudoers.d/syncer):

[code light="true"]
syncer    ALL=SETENV:NOPASSWD:/usr/local/bin/rrsync /srv
[/code]

Obviously we need the user to be able to run this without requiring a password. SETENV will allow for the -E parameter to sudo.

SSH config


Next step is to allow root@srv1 to ssh as syncer@srv2 using public key. If you don't have a key pair generated for root@srv1 then go ahead and create it:

[code light="true"]
# ssh-keygen
[/code]

Then copy the contents of /root/.ssh/id_rsa.pub and paste them in syncer@srv2's authorized_keys file which is most probably at /home/srv2/syncer/.ssh/authorized_keys. Create the directory and the file if they don't exist.

To make rrsync work and make things safer you need to use the command=".." parameter and you should use the from=".." parameter. So your authorized_keys file will look something like this:

[code light="true" wraplines="true"]
from="srv1",command="sudo -E /usr/local/bin/rrsync /srv" ssh-rsa AAAA......siW root@srv1
[/code]

Don't forget to ssh at least once from srv1 to srv2 by hand in order to accept srv2's key and let ssh have it in in known_hosts.

Try it


Finally you are done and you can do the rsync:

[code light="true"]
# rsync --rsh=ssh -a --delete /srv syncer@srv2:/
[/code]

Monday, 23 July 2012

Venting machines and APIs

In our office we have a venting machine that offers free sodas. What the vending machine does is simple: Keep contents cool, wait for someone to request a soda and then serve it.

But then again this is just a fridge. Why have a machine over there to do what a fridge is doing all this time? It would be simpler to put the sodas in the fridge. Everyone could just pick up what he likes. Right? ... wrong...

One needs only to open one of the two fridges to see how this would end. At first things are put nicely and in place. But a couple of days later the contents of a publicly accessible fridge look really really bad. You may end up having open or spilled sodas in there, expired cans and even things that should never be in there. All of this can happen by a small minority of its users. And it can be either on purpose or not. At the end you may have to dig on a pile of cans and other left overs to find a coke zero which would make the mess even worse. Requiring so much time to find something could also cause queues. The whole thing would become unusable after a couple of months. Even if there was a fridge access policy clearly stated at the front door someone would ignore that at the end.

All of this justify a venting machine that keeps things in place, always looks shiny and serves people well. Everyone is happy and at the end it costs less since it doesn't need constant maintenance and doesn't brake because of bad usage.

This is the same thing as data access. In theory you may allow direct access to data but it will always end up in disaster. Your stored data may become a mess and may even be used to store other things. People will do things they way they see fit (and this guarantees that most of them will be wrong). Even worse, when people are in a hurry and want to do something quick and dirty they will not pay that much attention to access or storage rules.

The solution is exactly the same. Introduce an interface between the user and the contents. Either a venting machine that will return the contents of the fridge or an API that will return the desired data. Direct data access will only be granted to few people and will only be needed to fix random issues.

But it gets even better!

Our venting machine doesn't have predefined locations for different kinds of sodas. Any soda can be stored anywhere and the user just have to find the proper row and column to get it. For example, one needs to type C2 on a keypad to get a soda from row C, column 2. Of course this could be changed and sodas could be put in predefined places. Then a different venting machine could accept a request for 'Pepsi Max', locate it and serve it. There are pros and cons on this: It will be easier to get something, it will allow the machine to know when a kind of soda is finished, etc. It also adds a lot of complexity and makes adding more sodas of a kind harder since it will need to be reprogrammed.

Something similar happens with APIs: An API can either get a raw request and process it (e.g. insert these data to table) or get a higher level request (e.g. create a new user). The first requires less complexity and the second allows the API to perform clever tricks like keeping statistics, updating other tables, changing internal representation without changing the API, etc...

Obviously there's no 1-to-1 mapping but things are really similar: Using a venting machine to serve sodas or an API to serve data will result in nice and clean stored contents and will last longer. Oh.. and users will be happier.