SELinux

Securing the Buildbot

One of the services I’m setting up on newartisans.com is Buildbot, so that every time changes get checked in the Ledger source tree, they’ll be automatically built and tested on every platform I have access to. Automatically. Without any intervention on my part whatsoever.

In terms of ease of use and assuring that things get done, Buildbot is a dream. In terms of system security, it’s a bit more of a nightmare.

Buildbot is a Python script that runs as a standalone daemon, listening for connections from the slaves in its network. Well, in terms of security I can never really trust a Python script. If anyone was able to subvert the code over the public TCP port, they could tell the script to do just about anything. It might not have much in the way of privilege, but at the very least it could read a whole lot of files on the system.

To run Buildbot securely means doing four things:

  1. Freeze the Buildbot Python script in a single static binary, with no references at all to the system while running.

  2. Run the server in a chroot jail, with access only to its own configuration files, its logs, and the state directories it uses to keep track of how the slaves are doing.

  3. Run the server as the nobody user in the nobody group, so that it has the least permission possible.

  4. Write an SELinux policy so that the daemon can only read and write exactly the files it needs to, and so it has permission to open a single TCP port and to send and receive traffic on that port.

With the environment set, a subverted daemon should just be a nuisance. The attacker could start instructing all of the slaves to keep building continuously, hoping to starve their system resources. And this can be alleviated by restricting builds to once daily. I’ll write more about the SELinux policy once it’s written.

|

Writing SELinux policies

I started the adventure of writing an SELinux security policy from scratch today. This is on CentOS 5, which uses the new policy modules approach rather than the older scheme involved a huge number of policies and a Makefile.`

It took hours of searching on the Net to find out that there’s really nothing out there to teach you how to start a new policy from nothing. I found one “step-by-step” guide, but it involved using a GUI tool that I don’t have. Every other article on writing policy is about using audit2allow to make existing policies more permissive.

The missing piece turned out to be the package selinux-policy-devel, which installs a tree of macro files in /usr/share/selinux/devel. Going into there, I found a complete example policy! So I copied these example files and started configuring them for Trac, the Python daemon I want to lock down. After that, I just had to run make, and insert the new policy using “semodule -i trac.pp”. And now it looks like I’m in for a few days of tweaking, as I narrow down exactly what Trac does and doesn’t need to be able to do.

|
© 2008 John Wiegley