Teaching SELinux to play nicely with
the Web Encrypton Extension

SELinux the Show Stopper

To be honest, I don't like SELinux very much. I think there's too little benefit in running SELinux in enforcing mode for the time you spend to ensure that the system actually does what it is supposed to do in a reliable way. More often than not SELinux works like the show stopper and silently refuses to grant access to legitimate processes.

It's no surprise that SELinux acts this way, because it is designed to have the final word on a process using the operating system's resources. Its code is located in the kernel and determines the final fate of any action with respect to its compliance with a pre-defined policy.

In an attempt to prevent the web server to serve files that are stored in user's home directories, the default policy does not permit the web server to access these files. That's fine under normal circumstances, but sometimes there are good reasons to change this. And you'd think that the web server configuration is a perfect place to lay down the rules by which a web server works.

But at this point SELinux kicks in and forces the web server to ask whether or not the action it is about to perform is permitted by the SELinux policy. If there is a conflict, the web server action will simply fail without notice. Everyone using the web server will see that something doesn't work, but cannot figure out what's wrong.

Living in a Different Context

To cut a long story short, SELinux attaches a "context tag" to everything in the operating system, creating a hugely complex net of relations for processes that would rather permit to store secret keys in the web server root directory than protecting them outside the web server tree. In effect SELinux (in default configuration) reduces security instead of increasing it. Secret keys have to be put in a safe place, the web server cannot access by default. And the root tree clearly is not the right place for keys. There cannot be a discussion about this.

What we have to do, is tell SELinux, to let the web server use a file where we consider it to be safely stored and to use the encryption program gpg to modify these files. Sounds simple enough? Well, SELinux is designed to throw all kinds of spanners into the works, you'll see.

Once we set up the key directory "/home/gpg" SELinux attaches a context called "home_root_t" the type used for files in the superuser's home directory. And even after we have changed the ownership and permissions exclusively to the web server user (UID 48 = apache on RedHat like systems) the type still remains "home_root_t". So it's no wonder that the web server process that expects all files to be of the type "httpd_sys_content_t" is confused and freaks out when SELinux shows its red card at the kernel level.

Wrestling with SELinux - Part One

It is not my intention to provide the definitive tutorial about SELinux, I'd rather try to arm you with some basic knowledge how to tackle problems that are caused by SELinux.

The good news, however, is that you can find out if SELinux is acting the show stopper quite easily, as you can switch it off intentionally. You need not fear something nasty will happen as a result, immediately. With the commands

setenforce permissive
sestatus

you can switch off enforcing mode and continue to catch violations of the policy, which are recorded in the audit daemon's log file. As a result you'll see that your current mode is permissive:

SELinux status: enabled
SELinuxfs mount: /selinux
Current mode: permissive
Mode from config file: enforcing
Policy version: 24
Policy from config file: targeted

If you're lucky your web application now works like a charm, and the "only thing" you have to figure out is how to tell SELinux not to get in your way once you have switched back into enforcing mode again.

Ask SELinux To Do You A Favour

Fortunately, there is a way to appease SELinux, to let some actions go through and to be a little bit more co-operative (in enforcing mode). There are a number of booleans that can be set to true or false to enable certain tasks, so the default policy can be tweaked a bit. Try the following commands and see what has changed.

setsebool httpd_can_sendmail on
setsebool httpd_read_user_content on
setsebool httpd_use_gpg on
chcon --type=httpd_sys_content_t /home/gpg
getsebool -a | grep httpd

With the first three commands you'll enable additional functionality of the web server, i.e sending email, using files outside the root directory and using gpg are now allowed by the modified policy. The fourth command sets the right context to the directory "home/gpg" and the last one shows all 201 boolean settings, many of which are self-explaining.

If you think your job is done, think again, you're wrestling with SELinux!

When switched to enforcing mode SELinux will still prevent you from creating new keys in the directory "/home/gpg". While the default "/home/gpg" is a fine place for secret keys, I admid that you may run into less trouble if you transfer this directory to "/var/www/gpg", because then it will both be outside the web server root tree and it will inherit the proper type "httpd_sys_content_t", not a bad idea.

Bringing in the Big Guns

As you could see it coming, to gain final victory over SELinux here, we need to create a custom SELinux module that defines all our wishes for a nice co-existence of the Web Encryption Extension with SELinux. Not an easy task, I can tell.

For now I'll save yourself the trouble of a full explanation and simply walk you through the process of building a custom module for SELinux. Here is the recipe.

Step 1
After a fresh reboot, put SELinux in permissive mode, so that the default policy is loaded and all violations are logged to the audit daemon's log file.
Step 2
Make sure that the audit daemon's log file (usually found in "/var/log/audit/audit.log") is empty (echo -n > /var/log/audit/audit.log). Now perform all the task you wish to have blessed by SELinux, upload keys, create key pairs, delete secret keys and so on. But make sure that no other tasks are performed on the server at the time you do that, because if there is a chance of someone doing something nasty right now, his actions will go into the module, too. OK, I'll bite my lips not to say something obvious here.
Step 3
By now the audit daemons log file has filled up with all the warnings about which actions violate the current policy, we are about to extend. Change into the directory, where you will store your keys.

Now it's time to build a policy module that reflects all changes to the current policy in a form SELinux can understand. Please run the following commands and have a look at the file "wee.te" that is being created as a result:

audit2allow -l -a -M wee
semodule -i wee.pp
semodule -l

If you're not happy with the result, you can remove your custom module from the system with

semodule -r wee.pp

You will notice, that a new module "wee 1.0" is an active part of the SELinux policy along with some other 267 modules that define the current policy. Maybe your Linux system shows more or less modules, but you'll see that your new module works, it even shows up (as wee.pp) in the directory "/etc/selinux/targeted/modules/active/modules". Congratulations!

You might get a little dizzy when you inspect the file wee.te and find the 315 lines of rules that have just been added to the current SELinux policy. But if you have a convincing reason to use SELinux in enforcing mode and something like this works for you, well, I'm the last one to tell you to disable SELinux.

For now.