3

We run web servers where we have the following situation:

  1. The www-data user runs the web server and must have read+write access to the files
  2. The deploy user deploys all the code
  3. The bob and alice users might login via ssh and change configurations locally

All users must have read+write access on /var/www/mysite. We currently accomplish this by owning the group of /var/www/site to www-data. Then we set the write + setgid bit on the group to make sure all subdirectories are having the same rights.

Now, this is all running fine for some time, but we have issues with the following scenarios:

  1. We use bower to install packages with bower install. The user who ran bower install the first time owns the public/bower_components directory and no setgid bit is set
  2. We use gulp to minify javascripts from public/scripts/src to public/scripts/dist and the first user who ran gulp build owns the files

In both situations, a find path/to/dir -type d -exec chmod g+ws {} \; does mitigate the problem, but is it possible to fix this issue in the first place? We have set the setgid bit on the /var/www/mysite directory, so why does bower install not follow this permission set?

If not, is there a better way to fix this problem? We have thought to set the bits in the deployment automation process, but if a user forgets the setgid bit we think the automated deployment could get stuck as well.

Cristian Ciupitu
  • 6,226
  • 2
  • 41
  • 55
Jurian Sluiman
  • 291
  • 6
  • 17

3 Answers3

7

Posix ACLs are the only clear-cut elegant way to do this, this is how I deal with shared read/write resource conflicts particularly on web-based systems. Here is a running example.

In my example I have a directory called /var/www/html/share. In addition I have the users alice, bob, deploy and bower

First, I have created a group called html and then added the users to this group.

groupadd html
for i in alice bob deploy bower; do usermod -a -G html $user; done

Now, I have then added a file ACL against this html group onto that folder.

setfacl -m g:html:rwx /var/www/html/share
setfacl -d -m g:html:rwx /var/www/html/share

The second command is important, it causes inheritance to occur.

Now, we can test out the behaviour of this.

# for user in alice bob bower deploy; do \
    sudo -u $user touch "/var/www/html/share/file_${user}" \
done

[root@localhost html]# ls -l /var/www/html/share/
total 0
-rw-rw-r--+ 1 alice  alice  0 May 13 23:08 file_alice
-rw-rw-r--+ 1 bob    bob    0 May 13 23:08 file_bob
-rw-rw-r--+ 1 bower  bower  0 May 13 23:08 file_bower
-rw-rw-r--+ 1 deploy deploy 0 May 13 23:08 file_deploy
[root@localhost html]# 

At first glance, it looks as though the file ownerships are all just simple, and will not allow one user to interact with anothers. However, we can inspect the ACL using getfacl which shows more infomation.

# getfacl file_Al
getfacl: file_Al: No such file or directory
[root@localhost share]# getfacl file_alice 
# file: file_alice
# owner: alice
# group: alice
user::rw-
group::r-x          #effective:r--
group:html:rwx          #effective:rw-
mask::rw-
other::r--

You can see that the html group has control over these files.

Note: the standard unix GROUP permission denotes the mask against the permissions. As it is rw for files it is also effectively rw for the ACL, despite the actual permission granted being rwx.

Lets test other users can modify/delete these files.

# sudo -u alice /bin/bash
[alice@localhost share]$ pwd
/var/www/html/share
[alice@localhost share]$ echo "hello world" >>file_alice
[alice@localhost share]$ echo "hello world" >>file_bob
[alice@localhost share]$ echo "hello world" >>file_deploy
[alice@localhost share]$ echo "hello world" >>file_bower
[alice@localhost share]$ ll
total 16
-rw-rw-r--+ 1 alice  alice  12 May 13 23:15 file_alice
-rw-rw-r--+ 1 bob    bob    12 May 13 23:15 file_bob
-rw-rw-r--+ 1 bower  bower  12 May 13 23:15 file_bower
-rw-rw-r--+ 1 deploy deploy 12 May 13 23:15 file_deploy
[alice@localhost share]$ rm file_deploy

Finally, the tricky bit. What happens when alice makes a directory?

[alice@localhost share]$ mkdir dir_alice;
[alice@localhost share]$ ls -l 
total 12
drwxrwxr-x+ 1 alice alice  0 May 13 23:16 dir_alice
-rw-rw-r--+ 1 alice alice 12 May 13 23:15 file_alice
-rw-rw-r--+ 1 bob   bob   12 May 13 23:15 file_bob
-rw-rw-r--+ 1 bower bower 12 May 13 23:15 file_bower
[alice@localhost share]$ getfacl dir_alice
# file: dir_alice
# owner: alice
# group: alice
user::rwx
group::r-x
group:html:rwx
mask::rwx
other::r-x
default:user::rwx
default:group::r-x
default:group:html:rwx
default:mask::rwx
default:other::r-x

Because we passed -d to setfacl it instructs new directories to also inherit (and apply that inheritance to further subdirectories). So, now as user deploy we can add and edit existing files inside of that new subdirectory.

[alice@localhost share]$ touch dir_alice/file_indir_alice
[alice@localhost share]$ exit
exit
# sudo -u deploy /bin/bash
[deploy@localhost share]$ cd /var/www/html/share/dir_alice/
[deploy@localhost dir_alice]$ touch file_indir_deploy
[deploy@localhost dir_alice]$ rm file_indir_alice 
[deploy@localhost dir_alice]$ 
Matthew Ife
  • 22,927
  • 2
  • 54
  • 71
1

You have mixed up semantics of sticky and setgid.

The sticky bit on a directory is used when multiple users are allowed to create files and directories in that directory, but they are only allowed to change those, which they created themselves, they are not allowed to mess with those contents created by other users. The /tmp directory is the typical use case for this.

The sticky bit is not inherited by subdirectories. There is no need for it to be inherited in order to satisfy its intended purpose. The subdirectories created in a sticky directory are supposed to be off-limits by default for everybody except the creator.

The setgid bit on a directory indicates that files and directories created inside that directory inherit group from the directory, instead of getting the current group of the user creating it. The setgid bit is inherited by new directories created inside the setgid directory.

The setgid bit could achieve part of the goal you are trying to achieve. It would achieve the part where the entire hierarchy of directories and files will have the same group (unless explicitly overridden).

It does however not guarantee that everything in there will be writable by the group. That can be achieved through umask setting.

The umask indicates a set of bits, which are not to be set on newly created files and directories. Typical values for umask are 0002, 0007, 0022, 0027, 0077. In your case you want those directories to be writable for the group, which means you want either 0002 which means what is created will be readable to everybody outside the group or 0007 which means what is created is inaccessible to everybody outside the group.

You need to ensure the umask is set at some point before creating new files or directories. The umask is inherited by child processes. Beware of files created outside that specific directory, since the umask is applied elsewhere as well, so anything created elsewhere will still be writable by the group, even if that is a different group from what is used on the /var/www hierarchy.

kasperd
  • 29,894
  • 16
  • 72
  • 122
0

You could try making it harder to reset the permissions of the root directory by making it append only with chattr:

chattr +a /var/www/mysite
Cristian Ciupitu
  • 6,226
  • 2
  • 41
  • 55