Linux User and Group Management
At a glance#
- Purpose: Create, modify, disable and remove Linux user accounts and groups, and grant administrative access correctly.
- Applies to: RHEL-family and Debian/Ubuntu systems.
- Risk: Medium — removing the wrong account or sudo entry can lock administrators out.
- Time: 10 minutes per account; 30 minutes for an offboarding.
Overview#
Account management is routine until someone leaves, at which point doing it badly leaves live credentials on production servers. This article covers the full lifecycle: create, grant, audit, disable, remove.
Two principles worth stating:
- Never share accounts. Every person gets their own login. Shared accounts destroy accountability in the audit log.
- Disable before deleting. Deleting an account immediately orphans its files and breaks anything running as it. Disable first, confirm nothing broke, delete later.
Understanding the files#
| File | Contents |
|---|---|
/etc/passwd | Username, UID, GID, home directory, shell. World-readable. |
/etc/shadow | Password hashes and ageing. Root-only. |
/etc/group | Group names and members. |
/etc/sudoers and /etc/sudoers.d/ | Who may run what as root. |
UID conventions matter when auditing:
| UID range | Meaning |
|---|---|
| 0 | root |
| 1–999 | System and service accounts |
| 1000+ | Real people |
Creating accounts#
1. Create the user#
# Debian / Ubuntu - interactive, creates home and group
sudo adduser jsmith
# RHEL family, or non-interactive anywhere
sudo useradd -m -s /bin/bash -c "Jane Smith" jsmith
sudo passwd jsmith| Flag | Meaning |
|---|---|
-m | Create the home directory |
-s | Login shell |
-c | Comment field, used for the full name |
-G | Supplementary groups |
-e | Account expiry date |
Note:useraddwithout-mcreates an account with no home directory. The user can log in but lands in/with no dotfiles, and SSH key authentication fails because there is nowhere for~/.sshto live.
2. Force a password change at first login#
sudo chage -d 0 jsmith3. Set an expiry date for temporary access#
Contractors and vendors should never have open-ended accounts:
sudo usermod -e 2026-12-31 jsmith
sudo chage -l jsmithGroups#
# create
sudo groupadd developers
# add a user - -a is essential
sudo usermod -aG developers jsmith
# remove from a group
sudo gpasswd -d jsmith developers
# list a user's groups
groups jsmith
id jsmith
# list members of a group
getent group developersWarning:usermod -Gwithout-areplaces every supplementary group the user has. Runningusermod -G developers jsmithon an admin removes them fromsudo/wheel. Always use-aG.
Granting administrative access#
Add the user to the administrative group rather than writing individual sudoers entries:
# RHEL family
sudo usermod -aG wheel jsmith
# Debian / Ubuntu
sudo usermod -aG sudo jsmithFor a specific, limited grant, use a file in /etc/sudoers.d/ — never edit /etc/sudoers directly:
sudo visudo -f /etc/sudoers.d/webteam# Allow the web team to manage nginx only
%webteam ALL=(root) /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx, /usr/bin/nginx -tsudo chmod 440 /etc/sudoers.d/webteamWarning: Always usevisudo, including for files insudoers.d. It validates syntax before saving. A malformed sudoers file breakssudofor everyone, and fixing it then requires the root password or single-user mode.
Verify what a user can do:
sudo -l -U jsmithAuditing accounts#
Run these periodically, and always during an offboarding review.
# real user accounts
awk -F: '$3 >= 1000 && $3 < 65534 {print $1, $3, $6, $7}' /etc/passwd
# accounts with a login shell
grep -E "/bin/(ba)?sh$" /etc/passwd
# accounts with no password set - should return nothing
sudo awk -F: '$2 == "" {print $1}' /etc/shadow
# UID 0 accounts other than root - should return nothing
awk -F: '$3 == 0 {print $1}' /etc/passwd
# who holds administrative rights
getent group wheel sudo
# password ageing for one account
sudo chage -l jsmith
# accounts that have never logged in
lastlog | grep "Never logged in"
# recent logins
last -20Warning: Any account other than root with UID 0 is a full root equivalent and is a classic backdoor. Investigate immediately if one appears.
Disabling an account#
Do this the moment someone leaves. It is reversible and takes seconds.
# lock the password
sudo usermod -L jsmith
# also prevent SSH key login by changing the shell
sudo usermod -s /sbin/nologin jsmith
# expire the account entirely
sudo usermod -e 1 jsmithWarning:usermod -Llocks the password only. If the user has an SSH key in~/.ssh/authorized_keys, they can still log in. Locking without changing the shell — or removing the key — is the most common offboarding mistake.
Remove their SSH access explicitly:
sudo mv /home/jsmith/.ssh/authorized_keys /home/jsmith/.ssh/authorized_keys.disabledTerminate any live sessions:
who | grep jsmith
sudo pkill -KILL -u jsmithRemoving an account#
Only after the account has been disabled for an agreed period and nothing has broken.
# find files owned by the user first
sudo find / -user jsmith -not -path "/proc/*" 2>/dev/null
# check for scheduled jobs
sudo crontab -l -u jsmithArchive the home directory before deletion:
sudo tar -czf /root/leavers/jsmith-$(date +%F).tar.gz /home/jsmithThen remove:
# keep the home directory
sudo userdel jsmith
# remove home and mail spool as well
sudo userdel -r jsmithWarning: Files elsewhere on the system remain owned by the now-free UID. If a new account later reuses that UID, it silently inherits ownership of those files. Always run the find above and reassign or delete what it reports.
Offboarding checklist#
- [ ] Lock the password (
usermod -L) - [ ] Change shell to
/sbin/nologin - [ ] Disable
~/.ssh/authorized_keys - [ ] Remove from
wheel/sudoand any application groups - [ ] Kill active sessions
- [ ] Check for cron jobs and running processes
- [ ] Archive the home directory
- [ ] Repeat on every server, not just the obvious ones
- [ ] Rotate any shared credentials the person knew
Verification#
# account exists with expected properties
id jsmith
getent passwd jsmith
# group membership
groups jsmith
# sudo rights
sudo -l -U jsmith
# locked state - ! or * prefix on the hash means locked
sudo passwd -S jsmithFor a new account, have the user log in and run sudo -v before closing the ticket. For a disabled account, confirm login is refused by both password and key.
Troubleshooting#
| Symptom | Cause and fix |
|---|---|
| User cannot sudo after being added to the group | Group membership applies at login. Have them log out and back in, or run newgrp wheel. |
sudo: /etc/sudoers.d/x is mode 0644, should be 0440 | Wrong permissions. sudo chmod 440 the file. |
sudo broken for everyone | Malformed sudoers file. Recover via console: pkexec visudo, or boot single-user. |
User locked out despite usermod -L not being run | Account expiry set. Check chage -l. |
| Disabled user still logging in | SSH key still present. Remove authorized_keys. |
Home directory missing after useradd | -m was omitted. Create it and chown to the user. |
userdel: user is currently used by process | Live session or running service. Kill with pkill -u, then retry. |
| Files show a numeric owner instead of a name | The owning account was deleted. Reassign with chown. |