Managing Users and Groups on Linux
Shared logins and chmod 777 are what you get when nobody thinks about user management, and I've inherited enough servers like that to be opinionated. The tools are old and boring (useradd, usermod, groupadd, chage), but used consistently they keep people, services and file access cleanly separated.
These are the commands I use day to day on CentOS 7 and Ubuntu 16.04/18.04, including the differences between the two families that trip people up. The main one: Debian and Ubuntu have the interactive adduser wrapper on top of useradd, while on CentOS adduser is just a symlink to useradd. You'll need root or sudo.
Regular users
The portable way, which behaves the same everywhere:
sudo useradd -m -s /bin/bash -c "Jane Doe" jdoe
sudo passwd jdoe
-m creates the home directory from /etc/skel, -s sets the shell, -c fills the comment (GECOS) field that finger and some mail systems read. Without -m on Ubuntu you get a user with no home directory, which is a common surprise. On Debian-based systems adduser jdoe does all of that interactively.
Check the result in /etc/passwd and confirm the UID is in the regular range (1000 and above on both families):
getent passwd jdoe
id jdoe
Service accounts
Accounts for daemons should have no password, no login shell, and a UID in the system range so they are not listed on login screens:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin --home-dir /var/lib/myapp myapp
On CentOS the shell is /sbin/nologin. If the service does need a home directory (for caches or a .ssh key), add -m and create the parent path first.
Groups
I grant file access to groups, never to individuals. Make a group for the people who deploy the web application and give it ownership of the tree:
sudo groupadd webdeploy
sudo usermod -aG webdeploy jdoe
sudo chgrp -R webdeploy /var/www/example.com
sudo chmod -R g+rwX /var/www/example.com
sudo chmod g+s /var/www/example.com
The -a in usermod -aG is essential; without it, -G replaces the user's supplementary groups instead of adding to them, which is how people accidentally remove themselves from sudo. The setgid bit on the directory makes new files inherit the group.
To remove someone from a group:
sudo gpasswd -d jdoe webdeploy
Group changes take effect at the next login; newgrp webdeploy in the current session is a workaround.
Sudo
On Ubuntu add the user to sudo; on CentOS add them to wheel:
sudo usermod -aG sudo jdoe # Ubuntu
sudo usermod -aG wheel jdoe # CentOS 7
For narrower grants, put a file in /etc/sudoers.d/ rather than editing /etc/sudoers. Always go through visudo -f so a syntax error cannot lock everyone out:
sudo visudo -f /etc/sudoers.d/webdeploy
%webdeploy ALL=(root) NOPASSWD: /bin/systemctl restart nginx, /bin/systemctl reload nginx
Expiry and locking
chage handles ageing without touching the shadow file by hand:
sudo chage -M 90 -W 14 jdoe # expire after 90 days, warn 14 days before
sudo chage -E "$(date -d '+90 days' +%F)" contractor # account expires on a fixed date (YYYY-MM-DD)
sudo chage -l jdoe # show current settings
To lock an account without deleting it, which is what you want when someone leaves and you may still need their files:
sudo usermod -L -e 1 jdoe
-L locks the password and -e 1 sets the expiry to the past, which also blocks SSH key login. usermod -U -e '' reverses it.
Removing an account
I lock first and delete later, after a month or so, once I'm sure nobody needs the files.
sudo userdel -r jdoe
-r removes the home directory and mail spool. Before that, find files the user owns elsewhere so they do not become orphaned UIDs:
sudo find / -xdev -user jdoe -not -path '/home/*' 2>/dev/null
Auditing
id jdoe
sudo -l -U jdoe
getent group webdeploy
sudo chage -l jdoe
sudo -l -U prints exactly what the user may run, which is the quickest way to audit a sudoers change. lastlog and last jdoe show whether an account has ever been used.
Odd errors
useradd: user 'jdoe' already existsbutgetent passwd jdoeshows nothing. The name is still in/etc/groupor/etc/subuid. Checkgrep jdoe /etc/group /etc/subuid /etc/subgidand clean up.- User added to a group but still gets
Permission denied. The session predates the change. Log out and back in, or usenewgrp. >>> /etc/sudoers.d/webdeploy: syntax error near line 1 <<<. Fix it withvisudo -f; sudo ignores the whole file while it is broken, and also ignores any file insudoers.dwhose name contains a dot or ends in~.This account is currently not available.onsu - myapp. Expected: the account hasnologinas its shell. Usesudo -u myapp -sorsu -s /bin/bash myappwhen you need a shell as a service user.
One account per person, one per service, groups for shared write access, sudo grants that name commands. That's the whole habit.