If you have a web-server (e.g. nginx) often you use a fast-cgi server or another application-http-server for dynamic content. That means in both cases you have a nice process separation between the web-server process and the fast-cgi (or application-http-server process - in the following called slave).

The web-server is configured such that fast-cgi goes over a socket or http request are proxied.

Creating different users for the slave and the web-server you can protect filesystem locations, if there is a security problem in the slave process.

But how do I jail the slave process even more under Linux?

(Such that it cannot access the net, send mails etc.)

I can think of following routes:

  • SELinux
  • Linux system namespaces ('containers', cgroups)

What is the most convenient way on a current distribution like e.g. Debian? How to do it in practice? Any configuration examples?


Under Ubuntu, another way of jailing is apparmor!

It is a path based mandatory access control (MAC) Linux Security Module (LSM). In Ubuntu 10.04 it is enabled by default for selected services.

The documentation is quite fragmented. The Ubuntu documentation could be ... better. Even the upstream documentation does not give a good introduction. The reference page states:

WARNING: this document is in a very early stage of creation it is not in any shape yet to be used as a reference manual

However, getting started is relatively easy. An AppAmor profile matches a executable path, e.g. /var/www/slave/slave. The default rule of a profile is deny (which is great), if nothing else matches. Profile deny-rules match always before allow-rules. An empty profile denies everything.

Profiles for different binaries are stored under /etc/apparmor.d. apparmor_status displays what profiles are active, what are in enforce-mode (good), or only in complain mode (only log messages are printed).

Creating a new profile for /var/www/slave/slave is just:

aa-genprof /var/www/slave/slave

Start in another terminal /var/www/slave/slave and do a typical use case. After it is finished press s and f in the previous terminal.

Now /etc/apparmor.d contains a profile file var.www.slave.slave. If the slave does some forking the profile is only very sparse - all the accesses of the childs are ignored.

Anyway, the profile is now active in enforce mode and you can just iteratively trigger actions in the slave and watch tail -f /var/log/messages for violations. In another terminal you edit the profile file and execute aa-enforce var.www.slave.slave after each change. The log displays then:

audit(1308348253.465:3586):  operation="profile_replace" pid=25186 name="/var/www/slave/slave"

A violation looks like:

operation="open" pid=24583 parent=24061 profile="/var/www/slave/slave" 
  requested_mask="::r" denied_mask="::r" fsuid=10004 ouid=10000 name="/var/www/slave/config"

A profile rule like:

/var/www/slave/config r,

would allow the access in the future.

This is all pretty straight forward.

AppAmor supports coarse grained network rules, e.g.

network inet stream,

Without this rule no internet access is possible (including localhost), i.e. with that rule you can use iptables for finer-grained rules (e.g. based on slave uid).

Another documentation fragment contains something about sub profiles for php scripts.

The var.www.slave.slave profile skeleton looks like:

#include <tunables/global>

/var/www/gapapp/gap.wt {

  #include <abstractions/base>

  network inet stream,

  /var/www/slave/config r,
  /var/www/slave/exehelper/foo ix,
  /var/www/slave/db/* rw,


With such a profile the slave is not able anymore to call utilities like mail or sendmail.


There is another way to jail it down: iptables using the owner match extension!

With iptables it is possible to block outgoing (OUTPUT) network traffic by all processes of the slave-user. This is very easy to setup, i.e. it is convenient.

That means that with this easy setup you can jail your slave-process from filesystem locations and the network.

$ iptables -N slave_chain
$ iptables -A slave_chain -m owner --uid-owner 10004 -p tcp --dport 1:1024 -j REJECT
$ iptables -A slave_chain -m owner --uid-owner 10004 -p tcp -d -j ACCEPT
$ iptables -A slave_chain -m owner --uid-owner 10004 -j REJECT
$ iptables -A OUTPUT -j slave_chain

Where 10004 is the uid of the slave user. The slave needs only to reply to proxied webserver requests. Everything else is rejected, e.g. a connection attempt to the MTA at localhost port 25 for sending SPAM.

Note that the slave could send mail via commands likes mail or sendmail, if they are available, i.e. further jailing of fs locations (e.g. chroot/cgroups) is necessary or one has to configure the MTA to dis-allow outgoing mail by the slave-user.

  • If the slave could send mail by calling mail, it could also send mail by including the code in the mail binary. The matching is done by UID. You still do need to chroot to prevent the CGI from accessing files and invoking setxid programs, and make sure you don't have any setuid binary in the chroot. – Gilles Jun 17 '11 at 20:21
  • @Gilles, yes, e.g. on a system with exim, mail calls sendmail, which is a link to sbin/exim4 which is setuid. – maxschlepzig Jun 17 '11 at 22:15

Cgroups are a way for jailing. Since 2007, the cgroups subsystems even contains so called network namespaces.

Current distributions ship Linux containers userspace tools, a collections of command line tools (lxc-*) and example configuration files. They also include a network namespace example.

Unfortunately, Ubuntu 10.04 (LTS) breaks network namespaces with a recent kernel update.

All in all, the documentation about lxc is not that verbose, you have to dig through some example config files.

It is not clear what the best practice is to setup root-less containers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.