Chrooting for mortals
I recently set up a simple way for people to run their own chrooted services without being root. Non-geeks/sysadmins should probably stop reading now. Oh, and if you do count yourself as one of the above and don't know what a chroot is or when to use one, well... google for it (just now, this paper seems to be a good introduction).
So we want our users, not running as root, to be able to run chrooted services. It seems like a simple problem, doesn't it? But the chroot call is only available to the root user, so we need a simple way of allowing users to run the chroot call as root, and then depositing them safely back at their own uid so they can't break out of the chroot as root. There's no magic in this, but I'd not seen any examples of people doing anything equivalent, so I thought it was worth documenting.
Someone pointed out after reading this article that dchroot, a Debian developer tool, may be able to do the same thing, but I've not looked at it, so I can't comment on how suitable it is for what I'm doing.
The nice thing about this approach is that it achieves privilege separation for the user, without having to worry about SE Linux policies or separate per-user daemon accounts.
We need:
- a privileged execution helper (a SUID root program that will run specified commands as another user, based on tightly defined rules). I used userv in this case, although sudo would have done just as well. Configuring this sort of program can be offputting to start with, as they both have a very powerful but not entirely obvious configuration, but I got some simple examples from the userv-utils package. (misc/ndc-reload in particular).
- chrootuid. This is the tool that makes this approach possible, really.
Steps:
- Create an empty directory that will be your chroot, and have it owned by your mortal. Note that this configuration (the user-owned chroot) is only secure because we aren't running anything inside the chroot as the root user, because we change user with the chrootuid program (which is stored outside the chroot). The more obvious way, to use su inside the chroot, exposes your root user to running trojanned commands supplied by your mortal (and the root user inside a chroot can break out of the chroot). Having a SUID-root binary inside the chroot also introduces another attack vector, of course.
- As your test user, populate the chroot with the files needed to run your daemon. For the statically linked network daemon I tested with, literally all I needed was /etc/resolv.conf, /etc/hosts, and the daemon and its configuration file.
- Configure sudo, userv or similar to run one of these two commands if
asked to do so by just your test user:
- chrootuid /some/chroot testuser daemon daemon-args. This will allow the user to just run the daemon inside the chroot. In this instance, you can use suppress-args in userv for absolute paranoia.
- chrootuid /some/chroot testuser. This way, the user can execute anything he likes inside the chroot, as his user. Which is best will be context-dependent. Note however that userv won't report errors in running chrootuid back to the user in its default configuration, but syslogs them, so if they just try to run that bare command nothing will happen, but an error will be reported in syslog that they should specify a program to run.
So with userv, the user would run a command like: userv root chroot-test in the first instance, and userv root chroot-test /bin/bash in the second (however the user should be made aware that leaving shells lying around in the chroot is a bad plan). Remember that the user can manipulate files in the chroot from outside the chroot, so in general there shouldn't be any need for this second version.
That's it, but for some final points:
- userv, sudo and chrootuid are all packaged for Debian, if that's your thing (chrootuid is not in woody but trivially rebuildable).
- As with any security-related advice, check that what I said makes sense, and that you have only allowed precisely what you expect to happen.
- I recommend reading the whole of the article I mentioned about setting up chroots, for other possible pitfalls.
- Remember (and tell your users) never to trust any data, especially binaries, that appear inside the chroot. They should especially never have a $PATH that includes the chroot.
- Have your chroots area on a separate partion, mounted nosuid and nodev if possible.
- Feedback is welcome to the address below.