Every file and process on Linux belongs to a user and a group. Good access control means people log in as themselves, receive only the privileges they need, and use sudo so that administrative actions are logged against a name.
Versions in use on this date. Ubuntu 18.04.2 LTS with sudo 1.8.21, and CentOS 7.6 with sudo 1.8.23. The adduser helper exists on Ubuntu; CentOS uses useradd, which works on both.
How access is decided
flowchart TB
U[User logs in with SSH key] --> ID[Identity from /etc/passwd<br/>UID and primary group]
ID --> G[Supplementary groups from /etc/group]
G --> F{File access check<br/>owner group other bits}
U --> SU[Runs sudo command]
SU --> SD{Match in /etc/sudoers or sudoers.d}
SD -->|allowed| RUN[Runs as root]
SD -->|denied| DEN[Denied and logged]
RUN --> LOG[Entry in auth.log or secure]
DEN --> LOG
Files behind the scenes
| File | Contents |
|---|---|
/etc/passwd |
Username, UID, GID, home, shell (readable by all) |
/etc/shadow |
Password hashes, readable by root only |
/etc/group |
Groups and members |
/etc/sudoers, /etc/sudoers.d/ |
Who may run what as whom |
Create users and groups
sudo adduser ravi # Ubuntu, interactive
sudo useradd -m -s /bin/bash ravi # both distros
sudo passwd ravi
sudo groupadd deploy
sudo usermod -aG deploy ravi # -a is essential: without it you REPLACE the groups
id ravi # uid, gid, groups
getent group deploy
The login takes effect for new sessions only; ask the user to log out and in again to pick up a new group.
sudo: give the least privilege that works
On Ubuntu, members of the sudo group have full rights; on CentOS it is wheel. For anything narrower, use drop-in files, never edit /etc/sudoers directly:
sudo visudo -f /etc/sudoers.d/deploy
# members of group deploy may restart one service without a password
%deploy ALL=(root) NOPASSWD: /bin/systemctl restart myapp, /bin/systemctl status myapp
visudo checks syntax before saving. A syntax error in sudoers can lock you out of administration, so keep a root session open while you test. Check with sudo -l -U ravi. Avoid ALL=(ALL) NOPASSWD: ALL except on short-lived lab machines, and avoid allowing editors or shells in sudo rules, because they let a user escape to a root shell.
Service accounts and locking
sudo useradd -r -s /usr/sbin/nologin myapp # system account, no login
sudo usermod -L ravi # lock the password
sudo chage -E 2019-12-31 contractor # account expires on a date
sudo passwd -l oldaccount
sudo deluser --remove-home leaver # Ubuntu; userdel -r on CentOS
Run each application as its own user, never as root, so a compromise of one service does not hand over the machine.
Auditing
last -n 10 # recent logins
sudo lastb | head # failed logins
sudo grep sudo /var/log/auth.log # Ubuntu; /var/log/secure on CentOS
awk -F: '$3 == 0 {print $1}' /etc/passwd # accounts with UID 0 (should be only root)
awk -F: '$2 == "" {print $1}' /etc/shadow # empty passwords (run as root)
Habits
- Disable direct root SSH login (covered in the SSH post) and use named accounts.
- Remove accounts when people leave, and review
sudoandwheelmembership every quarter. - Prefer groups over per-user rules, so access follows roles.