How you you manage your web users, groups and file system permissions??

We encourage users to post events happening in the community to the community events group on https://www.drupal.org.
wipeout_dude's picture

Hi,

I am interested in a discussion on how you construct your users, groups and file system permissions to try and establish a best practice.. I know there are a few ways people suggest doing this..

Option 1
Webserver and PHP run as www-data..
User account and user group own files..
www-data user is a member of the user group..

Group permissions determine what's writeable by the webserver.. Files remain owned by the user and user group.. Files uploaded through the website are owned by www-data that can cause some issues..

Option 2
Webserver and PHP run as www-data..
User account and www-data group own files..

Group permissions determine what's writeable by the webserver.. Any newly added files have to be chowned to the right group or the setGID flag must be set.. Has some overhead to manage permissions.. Files uploaded through the website are owned by www-data that can cause some issues..

Option 3
Webserver runs as www-data and PHP run as user..
User account and user group own files..
www-data user is a member of the user group..

Solves the problem if files created by the web application and the need to chown the files but uses a lot of memory when running multiple sites that belong to different users because they each have to have their own php-fpm pool and APC cache allocation.. Also looses any advantage to multi-site/shared codebase efficency..

Obviously under Apache there are other things like MPM-ITK, SuEXEC, SU_PHP etc.. but nothing I have seen like that with nginx/php-fpm other than many fpm pools..

What do you?

Currently I am using option 2 and its painful.. Especially if I want to have multiple developers and don't want them messing with permissions and file ownership all the time.. I have used all these options at various points in time but haven't found the "best" way of doing it so if you have any suggestions I am all ears..

Comments

I use

perusio's picture

kind of option 2. I have a user that owns the site. This user is just a regular user. The files directory, i.e., where the site writes files has permission 775 owned by <site-user>.www-data. The only issue I have is whenever some module creates files, like CTools, for example and it's owned by www-data.www-data and I do a drush cc all and PHP cannot unlink (delete) the file. Of course that's something that find is very useful for:

find sites/default/files -typed -exec chown my-user.www-data {} \;

and similar for handling permissions.

Yes, these are the sorts of

wipeout_dude's picture

Yes, these are the sorts of issues I have as well.. Many commands I have to run as root and I have created some scripts to reset the permissions using find as you illustrated.. Difference is I have no files world readable so directory permissions of 770.. Its the issues I am trying to get away from..

There is another option of putting the user into the www-data group but this gives the user access to all sites files which may not be desirable.. This is how Aegir does it.. I guess if you don't give scp/sftp/ftp/ssh access to the files then this works fine.. Obviously you have to make sure the users cant execute PHP code anywhere..

Seems there isn't a "best" way of doing this..

I believe there is

perusio's picture

at least executable by fpm. Just use a decent config and enumerate all PHP allowed files. Then return a 404 for any other. The /etc/nginx directory is owned by root. So no one else one can touch it.

I have to admit I am starting

wipeout_dude's picture

I have to admit I am starting to come around to that way of thinking.. In a Drupal environment anyway.. Puts less reliance on file system permissions meaning a more relaxed and usable file system setup without sacrificing security.. Its effectively moving some access control to the web server instead of using the file system..

Wonder if there are any measurable performance advantages to that because the file system doesn't have to get involved in the access checking (although it obviously would anyway by design)..

Yes there

perusio's picture

is. On Nginx exact locations are handled instantaneously. The NGX_FIND_CONFIG_PHASE exits immediately upon finding an exact match. These are stored in a hash table (I believe is a rb-tree, but needs confirmation).

So having = /index.php is advantageous. Also the shorter the try_files directive is the better. Like stated before. There's no need to have rewrites of any kind in a regular Nginx drupal config. The more exact your config is the better. Also regexes are liable to introduce side effects.

@perusio Unless you want to

brianmercer's picture

@perusio
Unless you want to add your regular user to the www-data group, which I think is acceptable.

There's a good discussion of

brianmercer's picture

There's a good discussion of this here: http://drupal.org/node/244924

The way I see it the goals are this:

1. Make all files non world-viewable. I don't see any reason that any code or data files would need to world readable in either a single user or multiuser enviroment. Generally code COULD be world-readable since anything sensitive should be separate from the code, but there are files such as db dumps that shouldn't be world viewable.

2. Code files should not be writable by the web server. Your php-fpm process shouldn't be able to overwrite any drupal code, whether it's core or modules. That's a security risk. So all code should be owned by someone other than the user that runs the php-fpm process. So for our examples, the user will be brian (although I use a dedicated user www-admin, see below)

3. Code files need to be readable by the web server. So if we run php-fpm as user www-data then all code should have a group of www-data and be group readable. Respecting 1 and 2 above, then directories should be 750 and files should be 640. All code files should be brian:www-data.

3. Your public and private "files" directories need to be www-data writable. That applies whether your private directory is inside your public one or completely outside the web root. So files directories should be brian:www-data because the php-fpm doesn't need to delete that directory, but the directory should be 770 so that the php-fpm process can create files and directories inside it.

4. Your php-fpm generated files should be writable by the www-data user since they may need to be purged from the web site. As a practical matter, you need to expect anything under /sites/default/files to be www-data:www-data and 660. Examples would be css files which get purged from pressing the clear cache button and imagecache automatically purging old cached images.

Now that's all well and good. And that article has some commands to fix stuff that way. I use the numbers so I do:

  sudo chown -R brian:www-data target_directory
  sudo find target_directory -type d -exec chmod 750 {} \;
  sudo find target_directory -type f -exec chmod 640 {} \;

and that will change every file ownership and make no file world readable.

Then you need to fix the "files" directory with this:

  sudo chmod 770 files_directory
  sudo chown -R www-data:www-data files_directory/*

and that allows php-fpm to write in the files directory and then changes the ownership of every file in the files directory to www-data so that php-fpm can also purge those files as it likes.

Then you have the drush problem. You don't want to run drush as root because stray drush code could screw your whole system. You want to limit drush to only web related files. But, drush needs to be able to write code files for such things as updating modules. So the easiest thing is to run drush as the owner of the files. Then drush can move an old module to the backup_dir and replace it with the new version.

As perusio pointed out above, that means that drush user would not be able to write the files written by php-fpm as www-data:www-data. So for that you can add the drush user to the www-data group. By default, php-fpm is going to write its files as 664, group writable, so adding the drush user to the www-data group will allow things like "drush cc all" to purge your old css files and such.

As stated, it's often required that you go back and fix permissions. Your typical user, "brian" in this example, writes files by default as 644, world readable. So when you do a "drush dl imce" you get an imce directory that's brian:brian and 745 on directories and 644 on files. This doesn't break your site because the files are world-readable, but it's less than ideal. You'd rather that the imce directory be immediately brian:www-data and 750 on directories and 640 on files.

Another example of bad drush permissions is when you do a sql-dump the files are written as 664 if you're using brian as the drush user. Now hopefully they're in a private directory that is 750 at least so not world-readable since the world cannot traverse the parent directory, but it'd be better if the sensitive files themselves were not world-readable.

My solution for a single user environment is to create a www-admin user that writes files as www-admin:www-data and 750 and 640 by default. Instead of brian in the commands above, you'd substitute www-admin as the owner of all the code.

This is how I set up the new user:

useradd --home /var/lib/www-admin --create-home --skel NULL --gid www-data --system www-admin
echo "umask=007" >> /var/lib/www-admin/.profile
echo "alias drush='sudo -i -u www-admin drush'" >> /home/brian/.bash_aliases
groupadd --system www-admin
usermod -a --groups www-admin brian
echo "%www-admin ALL = (www-admin) NOPASSWD: ALL" >> /etc/sudoers.d/www-admin
chmod 440 /etc/sudoers.d/www-admin
source ~/.bashrc
cp -pr /brian/.ssh /var/lib/www-admin
chown -R www-admin:www-admin /var/lib/www-admin/.ssh

1. creates a new user that uses www-data as its group
2. puts a umask in its shell .profile so that it creates non-world-readable files and directories
3. creates a new www-admin group and adds your regular user to that group
4. allows that group to do things as the www-admin user without a password
5. creates an alias for the regular user so drush commands will be run as the special drush user
6. and then copies .ssh credentials to the new www-admin user so that the admin user can do fancy stuff with syncing various machines

Then when you do a "drush dl imce" you get a nice imce directory that is already www-admin:www-data and 750 and 640. Also when you do a sql-dump you get the same. Fewer permission-correcting scripts are necessary.

It also separates out the need to use root for any web admin. If you need to delete a directory you can do "sudo -u www-admin rm imce". If you need to muck around as the www-admin user you can do "sudo su www-admin". You can then leave your sudo to the root user password protected.

This doesn't solve the problems where you have multiple users.

Also it doesn't solve the problem noted in the article that if you run drush to create something, then the php-fpm cannot then delete that item. But that is a natural consequence of the security settings. You COULD let the php-fpm process delete files created by the drush user, but you don't want to. Until drush can do different permissions for different tasks, that can't be solved.

Now that's an interesting

wipeout_dude's picture

Now that's an interesting setup.. If I can get away from correcting permissions all the time that will be a big help..

Just so I understand this..

You have two groups, www-data and www-admin.. You have two users, www-admin and "brian".. www-admin user is in www-data group and "brian" is in www-admin group..

When the "brian" user runs drush is executes through the alias as the www-admin user and resulting files are owned by www-admin:www-data with permissions of 750 and 640..

If "brian" wants to work on the files (other than with drush) then it has to be done through sudo because he wouldn't be able to see the files..

As you said it doesn't work for multiple users because through sudo any other files could be accessed that www-admin has access to which would be all other users sites..

What is the advantage of the second group?
Why not just add "brian" to the www-data group so files are created brian:www-data??

You have it exactly

brianmercer's picture

You have it exactly right.

When you say that you have to work through sudo to change files, that's true, except if I'm going to be doing more than one or two things I change to a new shell as the www-admin user with "sudo su www-admin". For that purpose I would also want to change the www-admin user from dash to bash and copy over full .profile (with added umask) and .bashrc files.

The only reason for the www-admin group is to use in the sudoers file so that you can remove the need to enter a password for working with the web server files. You could also do without the group and add "brian ALL = (www-admin) NOPASSWD: ALL" to the sudoers file. Or just enter your password every 15 or 45 minutes or whatever the sudo timer is.

And yes, you could also just change the primary group of your user to www-data and change the umask of your primary user in your /home/brian/.profile file. That would also work. And for a single user system it's probably not a bad idea to set umask 007 on your user anyways.

I suppose my impulse in abstracting out the changes to a new user and group are that I like to leave most things at their default if I can help it, so that I don't create any unintended consequences. I can't think of any harm though. The extra user and group would definitely help if you had multiple users with full access to the site. Then you could just add them each to the www-admin group.

I like your setup because its

wipeout_dude's picture

I like your setup because its not one I have come across before.. Its not without issues though.. :)

For example if I wanted to copy in a new module/feature/file from my development desktop and used WinSCP I would have to login as www-admin because I couldn't use sudo when connecting via SCP/SFTP.. Or I would have to copy the files to the user directory and then ssh into the server and as www-admin copy in the files..

My setup isn't perfect either..

Typically I run my whole system with a umask of 027..

Change default umask to 027 by editing the /etc/login.defs and /etc/profile files..

For sftp jailed users added..
session optional pam_umask.so umask=0027
..to the /etc/pam.d/common-session file..

Then I set the SetGID of the directories..

find . -type d -exec chmod u=rwx,g=rx+s,o= {} \;

..so any files created by the user will be created with the www-data group inherited from the parent directory..

My user accounts primary group is its own and its not a member of www-data meaning the user won't have access to all other users files.. The issue is that files created by php are not accessible by the user because they are www-data:www-data and require root to change the permissions to user:www-data is needed.. This causes the drush problem.. Also with my setup drush seems to be able to create files that don't honour the SetGID and so files created with drush are user:user.. Al lot of this is the reason for this discussion and why your method is of interest..

Different clients would

brianmercer's picture

Different clients would introduce new issues, but that's a limitation of using a particular gui client. You can sudo rsync or scp from the command line.

My dev server is a mirror of my live server with identical users and permissions. I move things over from ssh using either rsync -avz, or scp -pr, or drush rsync so they retain their owners and permissions.

With ssh aliases, bash scripts, and bash aliases, anything I do often is reduced to a few short commands, and it's very convenient. My next step would be moving much of it to git. Someday.

I'm definitely open to any improvements.

Why not

perusio's picture

use a more stringent setuid wrapper. Like super or using sudo with a shell script that wraps the command for fixing the permissions. That's about the only thing that the user should be able to do. Giving it a free pass on all www-data files is not very advisable in security terms IMHO.

In my actual setup above, the

brianmercer's picture

In my actual setup above, the user is separated from www-data by sudo and doesn't have that free pass. I remove the need to use a password, so it's the same, but you could require the password if you wanted the separation.

The point is to remove the need to ever have root privileges to manage your web stuff, which is the greatest danger. You stated the problem yourself: you can't "drush cc css+js" to remove the www-data:www-data files like css and js. That means you can use "drush dl module" as user (and then fix the group, bleh), and then "sudo -u www-data drush cc css+js" as www-data to clear your cache? Or the worst option, use drush as root to clear your cache.

I don't have much experience with setuid/setgid/sticky bits, so someone will have to explain how those would work better than what I'm using.

Thanks.

Howto: maybe

perusio's picture
  1. Create a shell script that just fixes the permissions for a given site files dir.

  2. Add that user with that command to the super.tab file.

  3. Done.

This way that user will be able to fix the perms on the files dir when needed. And all else will follow. I don't suggest running drush as root. Not even installing drush globally. This way there's no group addition or extra user involved.

I don't have much experience

wipeout_dude's picture

I don't have much experience with setuid/setgid/sticky bits, so someone will have to explain how those would work better than what I'm using.

Its very simple.. It simply means that any files or directories created inherit the group ownership of the parent directory..

So if the directory was owned by user:www-data with SetGID set then if the user created a file in that directory it would be owned by user:www-data instead of user:user (assuming the user's primary group was the same as the username)..

For those who are considering

webel's picture

For those who are considering setting up a single user Apache+CentOS+suPHP+cPanel system you may wish to inspect my forum posting collating some reference links relevant to this topic; Support » Installing Drupal: SECURITY CONCERN: reference links: suitability for Drupal CMS of Apache+cPanel+suPHP on single user system (VPS or Dedicated)

Nginx

Group organizers

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds: