Unix account security: users, passwords, sudo and SSH keys
Most attacks on Unix systems go through an account: a guessed password, a stolen key or a forgotten user who left years ago. These steps make accounts much harder to abuse.
One account per person
Never share accounts. With shared logins you cannot tell who did what, and you cannot remove one person's access without changing everyone's password. Create a personal account for each user with useradd and give them only the groups they need.
sudo useradd -m -s /bin/bash -c "Maria Petrova" maria
sudo passwd maria
sudo chage -d 0 maria # force a new password at first login
Use sudo instead of the root password
With sudo, administrators run privileged commands with their own password and every command is logged. Nobody needs to know the root password, which you can keep in a sealed envelope or a password safe for emergencies.
# Debian and Ubuntu use the "sudo" group, RHEL, Fedora and the BSDs use "wheel"
sudo usermod -aG sudo maria
# give a group limited rights in a separate file, always edited with visudo
sudo visudo -f /etc/sudoers.d/webteam
%webteam ALL=(root) /usr/bin/systemctl reload nginx, /usr/bin/journalctl -u nginx
Avoid NOPASSWD rules for people, and never allow editors, shells, less or find through sudo: each of them can start a root shell.
Check the account database
# only root may have user ID 0
awk -F: '$3 == 0 {print $1}' /etc/passwd
# accounts with empty password fields
sudo awk -F: '$2 == "" {print $1}' /etc/shadow
# human accounts (UID 1000 and up on Linux)
getent passwd | awk -F: '$3 >= 1000 && $3 < 60000 {print $1, $7}'
# when each user last logged in (lastlog2 replaces lastlog on newer distributions)
lastlog2 2>/dev/null || lastlog
# password ageing for one user
sudo chage -l maria
# check passwd and shadow for errors
sudo pwck -r
System accounts such as www-data or postgres should have the shell /usr/sbin/nologin and a locked password (! or * in /etc/shadow).
Password policy
Advice on passwords changed a lot in the last ten years. NIST Special Publication 800-63B, which many organisations follow, recommends:
- Long passwords: at least 15 characters when a password is the only factor. Passphrases of several words are easy to remember and hard to guess.
- Checking new passwords against lists of breached and common passwords.
- No forced composition rules (one capital, one digit, one symbol) and no forced changes every 90 days. Change a password when there is a reason, such as a suspected leak.
- Limiting failed attempts.
On Linux these rules are set in PAM. Minimum length and dictionary checks come from pam_pwquality (/etc/security/pwquality.conf), lockout after failed attempts from pam_faillock (/etc/security/faillock.conf):
# /etc/security/pwquality.conf
minlen = 15
dictcheck = 1
usercheck = 1
# /etc/security/faillock.conf
deny = 5
unlock_time = 900
# show and reset failed attempts for a user
sudo faillock --user maria
sudo faillock --user maria --reset
On RHEL and Fedora enable faillock with sudo authselect enable-feature with-faillock. On Debian and Ubuntu there is no ready-made pam-auth-update profile for pam_faillock: add it to /etc/pam.d/common-auth and common-account by hand, following man pam_faillock. Editing PAM files is easy to get wrong, so keep a root session open while you test.
Multi-factor login
A second factor stops most password attacks. Options for Unix systems:
- SSH keys stored on a hardware token (FIDO2 security keys) with
ssh-keygen -t ed25519-sk. The private key cannot be copied off the token. - Time-based one-time codes (TOTP) with the
libpam-google-authenticatormodule, combined with keys in SSH usingAuthenticationMethods publickey,keyboard-interactive. This needsKbdInteractiveAuthentication yesandUsePAM yesin sshd, which overrides thenoin the security guide's example. - Central identity through FreeIPA, Active Directory (SSSD) or an SSO provider, so that MFA and account removal are handled in one place.
SSH keys
Keys are stronger than passwords, but they need care too.
- Use Ed25519 keys and protect them with a passphrase. Load them into
ssh-agentso you type it once per session. - Review
~/.ssh/authorized_keyson every server. Each line should belong to a person or system you can name. Put a comment at the end of each key saying whose it is. - Restrict keys used by scripts:
from="10.0.0.5",command="/usr/local/bin/backup",restrict ssh-ed25519 AAAA... - For many servers, consider SSH certificates signed by your own CA instead of copying keys everywhere.
# every authorised key on the system, with the account it opens
sudo find / -xdev -name authorized_keys -path '*/.ssh/*' -exec sh -c 'echo "== $1"; cat "$1"' _ {} \;
When someone leaves
Remove access on their last day, not when someone remembers.
sudo usermod -L -e 1 maria # lock the password and expire the account
sudo rm /home/maria/.ssh/authorized_keys
sudo crontab -l -u maria # check for scheduled jobs before deleting
sudo pkill -KILL -u maria # end running sessions
# later, after handing over their files:
sudo userdel -r maria
Also remove them from sudoers files, VPN, the management network, shared password safes and any service accounts whose passwords they knew, and rotate those passwords.
Root's own environment
- Root's
PATHmust not contain.or any directory writable by other users. Otherwise a program calledlsin/tmpcould run as root. - Root's home directory (
/root) should be mode700. - Limit where root can log in from: no direct SSH login (see the SSH section of the security guide), and on the console only.