Managing permissions on a shared Drupal hosting

You are viewing a wiki page. You are welcome to join the group and then edit it. Be bold!
public

I thought a bit about how to fix the problems regarding shared drupal hosting in the HM2 paradigm. I think I have a good solution and would like to have feedback on it before it gets implemented in full in HM2. But first things first...

The problem(s)

The way web hosting traditionally work is that all files are readable by the webserver and are thrown on the wire when the web client requests it. That's all fine and dandy when you're kernel.org and want your files out as much as possible, but when you start talking about Drupal, things get more complicated.

Read permissions

First, you don't want anyone to read your files. Not only the web client, but the other web applications shouldn't be able to read your (e.g.) settings.php file because that would mean they have read/write access to your database, which bypasses any access control you might have put on your nice Drupal website.

So basically, out of the box, LAMP hosting opens this can of worm

Write permissions

To support file uploads and other "fancy" things, the webserver needs to be able to write to some (and only some) parts of the filesystem. This is generally accomplished by allowing everyone (or just the webserver) write access to the files/ directory (wherever it is is mostly irrelevant here).

This creates an issue similar as the read permission issue: every other website can write to your files now.

Known solutions

Every shared hosting platform out there has their solution. I'll try to go around a few I know of.

open_basedir

open_basedir is a PHP configuration setting that restricts access to certain parts of the filesystem only. The "home directory" of the "user" is usually the only place where the scripts should have access to. All PHP function calls are then restricted to that directory.

The main issue with that approach is that it doesn't really work properly. Without safe_mode (see below), it's fairly trivial to workaround the basedir restrictions using system() calls, for example. Also, this approach assumes that all potential PHP extensions (curl, imap, etc...) respect this functionality, which is very often not the case.

This theorically resolves the read and write issues.

safe_mode

When safe_mode is on, PHP checks to see if the owner of the current script matches the owner of the file to be operated on by a file function or its directory. Some hosting providers set the gid or the uid of hosted files to keep seperate website to access each other's file. This can easily be worked around by using system calls, which is why safe_mode also comes with a safe_mode_exec_dir directive that restricts allowed executables to those in a directory.

Safe_mode has similar issues has the open_basedir directive in that it is wildly misimplemented through the PHP codebase and extensions. Relying on it for security is considered bad practice and the extension will be removed in PHP6.

This theorically resolves the read and write permission issues.

environment variables

In a controled environment like HM, it's possible to set environment variables from the Apache configuration that is read as root by apache and can therefore be hidden from the www-data user. Those variables are then read by a modified settings.php to setup the database connection.

That resolves the read issue, but not the write issue.

suexecphp or "real UNIX permissions"

This is, I hope, the "proper" solution to the problem. This implies using Apache's suexec support in conjunction with PHP's CGI mode (optionnally running with FastCGI for better performance) to make the webserver run as a "real user".

This is how I think it should be implemented:

  • each site has a "user" assigned to it (say "userA")
  • each hostmaster "client" is actually a "group" (say "groupA")
  • the PHP environment runs in a userA:groupA environment (as opposed to www-data:www-data)
  • the settings.php file is mode 600 (read/write only by the user: that takes care of the read problem)
  • uploaded files can be similarly protected from writes
  • the rest of the files in Drupal are owned by the hostmaster user and group, unless we want to give access to themes and modules to the "user"

I think this reliably resolves all of the issues documented here, at the cost of some issues:

  • performance cost: FastCGI is slower than mod_php, especially if it needs to have seperate users for seperate domains
  • additionnal complications in the Apache setup: a configuration file needs to be created for each virtual domain (which we already do anyways, but some hosting platforms don't need that)
  • a file manager gets hard to implement in an eventual control panel (that would run as the hostmaster user). The only solution I could find here was to use some web2FTP gateway: the file browser just becomes an FTP client. Note that in the context of the "general shared hosting solution", the files could be owned by a user that would be the same username as the group and would therefore be a different user than the apache user, enhancing security...

Note that this approach also has advantages from a generic shared hosting point of view. "users" have various privileges: FTP access, SSH access, Drupal site, email, all in a central database with ACLs to control which user has which accesses. "groups" become the "control panel user": the group itself is the login/password to the control panel and can create users, only within its own group of course.

Note finally that "suexec" is just one way to make sure that Apache runs as the proper user. There are other ways, namely mpm-itk which allows the use of mod_php...

It's a bit rough for now, but you probably get the idea. I'm interested in getting comments, feedbacks, flames, similar experiences, edit this page!

Comments? Questions?

From jwthompson2 (Sep 26, 2008 - 16:17 EST - UPDATED @ 16:27 EST):

I don't have any problems with PHP under FastCGI since I've used it with LightTPD and been very satisfied by its performance running PHP apps. I instinctively prefer mod_php because I don't have to modify anything within a typical CentOS install and tweaking Apache performance is well understood and documented. Tuning FastCGI can bee a bit more hairy in my experience but isn't a huge problem. In a shared hosting environment I would expect you would want to use dynamically spawned FastCGI instances that have a defined life span. I think using FastCGI might be the best solution although it isn't the most popular because of its added complexity. I've used FastCGI particularly with Ruby apps as an alternative to proxying and it is a very good solution. mod_fcgid would be my recommendation if you were to go down that road and I wonder if pairing it with APC or XCache could negate some of the performance concerns, although in my experience those differences are not always as substantial as you might expect. A potential benefit I also see is that you could conceivably use Apache's Worker MPM which would help reduce Apache memory overhead since you've isolated the PHP app via FastCGI and I'm always for being able to use the Worker MPM.