Learn Docker With My Newest Course

Dive into Docker takes you from "What is Docker?" to confidently applying Docker to your own projects. It's packed with best practices and examples. Start Learning Docker →

Allow 2+ Users to Be Able to Share a Linux Directory with 2775 vs 0775

allow-2-users-to-be-able-to-share-a-linux-directory-with-2775-vs-0775.jpg

This is handy if you have 2 different users deploying code to the same directory, such as a deploy user and CI user.

Quick Jump:

Prefer video? There’s a video version of this blog post on YouTube that goes into a bit more detail about certain topics listed below.

This could be used for a number of things but let’s focus on 1 concrete example.

# Going Over the Permission Problem

For example, let’s say you git push your code to your server and it ultimately gets checked out to /srv/mysite. This could be a static site or your web application, it doesn’t matter.

Now let’s say you sometimes deploy your code from your dev box by pushing your code as the deploy user but you also have CI set up which can push code to your server.

For security reasons it would be a good idea to use a heavily restricted ci user that can only git push code to your server and nothing more. This user wouldn’t even have an ability to run a shell like Bash, instead you can use git-shell which provides restricted git access.

It’s worth pointing out when you git push to your server, part of that process will run a git checkout in perhaps a git post receive hook. The details aren’t important for this post’s topic but it’s important to know that files will be created as the user who performed the git push.

That’s because when you git push your code, you’re SSH’ing into your server as that user. The post receive hook runs and that script runs all commands as that user, such as git checkout and whatever else you want to do.

That means /srv/mysite (the checkout directory) needs to be writeable by both users. You can do this without doing anything fancy with permissions by simply creating a common group such as sshusers or whatever you decide to name it and add both the deploy and ci users to that group.

You can create a new system group with groupadd --system sshusers. The --system flag ensures your group will be created with a group id less than 1000 or more specifically what’s defined in /etc/login.defs.

If you run chown deploy:sshusers /srv/mysite then your directory will allow both the deploy and ci users to be able to write to it. That would look like this:

drwxrwxr-x  2 deploy sshusers 4096 Sep 24 22:46 mysite

Then as the deploy user you could do touch /srv/mysite/test and you’ll end up with:

-rw-rw-r-- 1 deploy deploy        0 Sep 24 23:04 test

Then let’s say you git push your code as the ci user. You’ll end up with:

-rw-rw-r-- 1 ci ci        0 Sep 24 23:07 index.html

This technically works, but as the ci user you’ll get a permission error if you try to overwrite a file owned by deploy:deploy, such as if you were able to run touch /srv/mysite/test (assuming the user had permission to run the touch command, I’m only doing this for an example). That will produce touch: cannot touch 'test': Permission denied.

Basically what this means is if you git push as the deploy user you’ll get permission errors when git pushing as the ci user and vice versa. Neither user will be able to write to files owned by the other user.

That leads us to the problem. How can we have 2 different users be able to git push or more generally write to each others’ files in a shared directory?

# 0775 vs 2775 Permissions for a Directory

By default when you create a directory on Linux, unless you modified the default behavior then you’ll get 0775 as the permissions, as seen below:

$ stat /srv/mysite

  File: /srv/mysite
  Size: 4096            Blocks: 8          IO Block: 4096   directory
Device: fd00h/64768d    Inode: 134418      Links: 2
Access: (0775/drwxrwxr-x)  Uid: (    0/    root)   Gid: (  998/sshusers)
Access: 2022-09-24 23:04:55.682777452 +0000
Modify: 2022-09-24 23:04:53.682799318 +0000
Change: 2022-09-24 23:04:53.682799318 +0000
 Birth: 2022-09-24 22:46:03.543155216 +0000

The important line is Access: (0775/...) which is the 4th line of output.

If you don’t specify the 0 then it defaults to 0 which gives us the default behavior we all know. If a user creates a file in this directory then it will own the file at the user and group level.

Here’s a little chart of the possible values you can set:

0: setuid, setgid, sticky bits are unset
1: sticky bit is in place
2: setgid bit is in place
3: setgid and sticky bits are in place
4: setuid bit is in place
5: setuid and sticky bits are in place
6: setuid and setgid bits are on
7: setuid, setgid, sticky bits are activated

We can use 2775 which will set the setgid bit. Now if a user creates a file in this directory then it will own the file but the group will be set to whatever group owns the parent directory. That’ll solve our problem!

That means we can do this:

chmod 2775 /srv/mysite

And now we can see the new access permissions:

$ stat /srv/mysite

  File: /srv/mysite
  Size: 4096            Blocks: 8          IO Block: 4096   directory
Device: fd00h/64768d    Inode: 134418      Links: 2
Access: (2775/drwxrwsr-x)  Uid: ( 1000/    nick)   Gid: (  998/sshusers)
Access: 2022-09-24 23:04:55.682777452 +0000
Modify: 2022-09-24 23:04:53.682799318 +0000
Change: 2022-09-24 23:36:15.845483124 +0000
 Birth: 2022-09-24 22:46:03.543155216 +0000

Now as the deploy user you could do touch /srv/mysite/cool and you’ll end up with:

-rw-rw-r-- 1 deploy sshusers    0 Sep 24 23:38 cool

Notice how the group is set to sshusers. The ci user and any other users in the sshusers group will be able to write to this file without getting a permission denied error. Now we can safely deploy our code to our server as 2+ different users.

Victory!

# Demo Video

Note worthy topics

In the video I incorrectly said that setgid is a type of sticky bit, that’s not the case. Both setgid and sticky are their own types of bits.

Timestamps

  • 0:05 – A use case for wanting to do this
  • 2:07 – Creating a directory to demo things out
  • 3:10 – Getting a permission denied error as a different user
  • 3:59 – Making a common group that both users belong to
  • 5:06 – Now a different user can create files in the directory
  • 5:23 – We’re good to go right? Not quite
  • 6:31 – setgid to the rescue
  • 8:02 – Setting our directory to 2775
  • 9:04 – Everything works how we want it to

Do you use this pattern on any of your servers? Let me know below.

Never Miss a Tip, Trick or Tutorial

Like you, I'm super protective of my inbox, so don't worry about getting spammed. You can expect a few emails per year (at most), and you can 1-click unsubscribe at any time. See what else you'll get too.



Comments