Users and Groups — In Depth
The earlier permissions post covered the basics. This one goes deeper — how Linux stores user accounts in /etc/passwd and /etc/shadow, how to manage users properly, and how the sudoers file actually works.
Series: Learning Linux from Scratch
- 1. Learning Linux from Scratch — After a Full IT Apprenticeship
- 2. What is Linux?
- 3. The Filesystem
- 4. Users and Permissions
- 5. Installing and Managing Software
- 6. Text Editors
- 7. Shell Scripting Basics
- 8. Process Management
- 9. Networking Fundamentals
- 10. SSH
- 11. systemd and Services
- 12. Disk Management
- 13. Users and Groups — In Depth
- 14. Cron and Scheduled Tasks
- 15. Firewall — iptables and ufw
- 16. Environment Variables and the Shell
- 17. Log Management
- 18. Kernel Module Management
- 19. The /proc Filesystem — In Depth
- 20. The /sys Filesystem and udev
- 21. Kernel Parameters and sysctl
- 22. Compiling and Installing a Custom Kernel
The users and permissions post earlier covered the basics — owners, groups, chmod, chown. This post goes deeper. How does Linux actually store user accounts? How does sudo work under the hood? How do you manage users properly on a multi-user system?
/etc/passwd
Every user account on the system is defined in /etc/passwd.
cat /etc/passwdEach line is one user and has seven fields separated by colons:
jan:x:1000:1000:Jan Doe:/home/jan:/bin/bash
jan— usernamex— password field. Thexmeans the password is stored in/etc/shadowinstead (more on that below)1000— UID (User ID)1000— GID (primary Group ID)Jan Doe— GECOS field, a comment. Usually the full name./home/jan— home directory/bin/bash— login shell
UIDs below 1000 are typically reserved for system accounts (daemons, services). Regular users start at 1000.
System accounts often have /usr/sbin/nologin or /bin/false as their shell — this prevents interactive login.
/etc/shadow
Passwords are not stored in /etc/passwd because that file is world-readable. Hashed passwords live in /etc/shadow, which is only readable by root.
sudo cat /etc/shadowjan:$6$randomsalt$hashedpassword...:19480:0:99999:7:::
Fields:
- Username
- Hashed password (
$6$means SHA-512) - Last password change (days since epoch)
- Minimum days before password can be changed
- Maximum days before password must be changed
- Warning days before expiry
- Days after expiry before account is disabled
- Account expiration date
A ! or * in the password field means the account is locked — no password login is possible.
/etc/group
Groups are defined in /etc/group:
cat /etc/groupsudo:x:27:jan,luca
docker:x:999:jan
Fields:
- Group name
- Password (almost always
xor empty) - GID
- Comma-separated list of members
Managing users
useradd
sudo useradd -m -s /bin/bash -c "Full Name" username-m— create the home directory-s /bin/bash— set the login shell-c— comment (full name)
Without -m, no home directory is created. Always use it for real users.
Set a password:
sudo passwd usernameusermod
Modify an existing user:
sudo usermod -aG docker jan # add jan to the docker group
sudo usermod -s /bin/zsh jan # change login shell
sudo usermod -L jan # lock the account
sudo usermod -U jan # unlock the account
sudo usermod -e 2026-12-31 jan # set account expiry dateThe -aG flag is important. -G alone replaces all supplementary groups. -aG appends. Forgetting the -a can remove a user from all their existing groups.
userdel
sudo userdel jan # delete user but keep home directory
sudo userdel -r jan # delete user and home directoryManaging groups
sudo groupadd developers # create a group
sudo groupdel developers # delete a group
sudo gpasswd -d jan developers # remove jan from the groupTo see which groups a user belongs to:
groups janOr with GIDs:
id janThe sudoers file
sudo is configured in /etc/sudoers. Never edit this file directly — use visudo, which validates the syntax before saving. A syntax error in sudoers can lock everyone out of sudo.
sudo visudoThe sudoers syntax:
user host=(runas) commands
Give a user full sudo access:
jan ALL=(ALL:ALL) ALL
Breaking this down:
jan— the user this applies toALL— from any host(ALL:ALL)— can run as any user and any groupALL— can run any command
Allow a user to run a specific command without a password:
jan ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx
Allow a group to have sudo access (the % prefix means group):
%developers ALL=(ALL:ALL) ALL
sudoers.d
Rather than editing the main sudoers file, you can drop files into /etc/sudoers.d/. Each file is included automatically.
sudo visudo -f /etc/sudoers.d/janThis is cleaner for managing per-user or per-application sudo rules.
Switching users
su - jan # switch to jan (full login shell)
su - # switch to root (full login shell)
sudo -u jan command # run a single command as jan
sudo -i # open a root shellThe - in su - is important. Without it, you switch user but keep the current environment. With it, you get a full login shell with that user's environment.
Most of this happens in the background on a desktop system where you are the only user. On a server with multiple users, shared services, and strict access control, this is the layer that keeps things secure and organised.
Next up: cron and scheduled tasks — automating jobs on a schedule.