How to set up user accounts on your web server
September 2, 2012 , revised September 14, 2012 in DevopsI’ve spent a lot of time over the past several days trying to wrap my mind around server deployment and configuration.
One of the questions was that of setting up user accounts. I’ve finally gathered my current knowledge of this topic in this article (scroll to the bottom for a summary if you are illiterate).
Group ownership 101
Maybe it’s me, but the concept of group ownership is often neglected in system setups.
Let’s take a random file from my PC and do a ls -l
on it.
-rw-r--r-- 1 leonid staff 3972 Sep 1 17:08 Vagrantfile
Most people realise that Vagrantfile
is owned by user leonid
, which has read/write permissions on it.
But – check this out – Vagrantfile
is also owned by group staff
(which has read permissions on it.)
Generally speaking, staff
has no relation to leonid
. They are handled equally, except a group may consist of more than one user.
Key point here: if you want multiple users to have access to a file or directory, you create a group out of those users and chown the file or directory to that group.
Account isolation 101
User accounts are akin to ship bulkheads: when the security of one account is compromised, damage to the system must remain minimal.
The least tested, most error-prone and insecure part of a web server is the web application itself. Thus, the application must be isolated into a separate user account, which must have minimal permissions. It must definitely not have sudo
rights, for one instance. It must also not have access to other applications deployed to the same communal server.
By the way, most system services in a *nix system run under isolated users. And they are more secure than your app.
Authentication & authorisation 101
I will assume you use SSH to log into your server.
The easiest way to set up authentication is to populate authorized_keys
of your app user. Don’t do that.
Firstly, you won’t be able to have sudo rights (because app users must not have sudo rights).
Secondly, if you’re not the only human being to log in to the server, a one-for-all user account is akin to a public restroom: everyone is allegedly careful and tidy, but then who shat in the corner?
Key point: have a personal account for every human that can access the server.
Now you can give sudo rights to those who deserve them (presumably by adding them to the admin
group). You can point fingers. You can revoke access as easy as userdel fired_guy
. People can use their favorite shell, or upload private keys onto the server (being too lazy to set up ssh-agent
).
What user account should deploy the app?
The answer is very obvious: every user should deploy the app using his own personal account! There is no need to have a separate “deployer” user, or use the app user for deployment. There is no need to su app_user
before deploying the app.
This is because the application files must be owned by the group of people who can deploy the application, plus the app user. In shell speak,
groupadd app_users
usermod -aG app_users joe
usermod -aG app_users bill
usermod -aG app_users app_user
chown -R :app_users application
chmod -R g+rws application
Why does the app user have to be a part of the group? Because the files will be generally owned by the user who deployed them, not the app user.
As a bonus, you now know who deployed the broken release.
How do you do that in Capistrano?
Let’s illustrate this setup with a Capistrano config.
Firstly, you do not set :user in your deploy script. :user
only affects the SSH connection, and in our setup the human operating the machine decides what the user would be: if the username is not the same as the local username, he can set up the connection in the ssh_config.
Sidenote: neither :user nor :group are ever used in Capistrano to modify file ownership. :user is only used for deployment and :group is a bogus unused option. So don’t worry about not setting :user.
Secondly, you make sure deployed files belong to the app_users group and are writable by it. Capistrano makes the files group writable by default, so you only have to set their group right.
Meet setgid. setgid
is a flag that, when set on a directory, makes all nested directories inherit its group. How do you set it? Simple:
chmod g+s application
(As you might have noticed, I’ve already included +s
in the previous configuration snippet.)
Once you’ve set the setgid
flag on the root application directory, you’ll never have to worry about permissions again.
Summary
- create an “app user” for the application; this user will run all application processes.
- create separate user accounts for each individual; these accounts will be used to log in;
- create an app_users group for all deployers + the app user;
- assign ownership on the root application directory to the app_users group;
- set the setgid bit on the root application directory;
- deploy script should connect to the server with the “default” username provided by the local system.
Advantages
- great permission isolation;
- better audit;
- deployment script can have parts that use
sudo
(and will be run by privileged users) - such as provisioning;
Disadvantages
- requires configuration to let new guys deploy;
I welcome you to provide questions, comments and suggestions.
Liked the post? Treat me to a coffee