LinuxV · sudo and Privileged Accesssudoers
sudoers syntax — rules, aliases, and defaults
What you'll learn
- Read and write sudoers rules with the correct grammar
- Use User_Alias, Runas_Alias, Host_Alias, and Cmnd_Alias
- Apply Defaults selectively
- Validate sudoers with visudo before saving
Prerequisites
Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09
The sudoers file format is unusual: it is not a simple INI or YAML. It has its own grammar, its own reserved words, and rules about how to combine them. Mistakes are silent until production breaks.
The basic rule
A sudoers rule has the form:
WHO WHERE=(AS_WHOM) [NOPASSWD:] WHAT
| Field | Meaning |
|---|---|
| WHO | User, group (with %), or User_Alias |
| WHERE | Host, Host_Alias, or ALL |
(AS_WHOM) | Target user (default: root). Optional. |
[NOPASSWD:] | Skip the password prompt |
| WHAT | Command, Cmnd_Alias, or ALL |
$ sudo -l -U aliceUser alice may run the following commands on host01:
(ALL) ALL
(root) /usr/bin/systemctl status ssh, /usr/bin/systemctl restart sshIllustrative output
Aliases
For fleets, listing every user or every command in every file is unmaintainable. sudoers has four alias types:
User_Alias OPS = alice, bob, carol
Runas_Alias APP = root, www-data
Host_Alias PROD = host01, host02, host03
Cmnd_Alias RESTART = /usr/bin/systemctl restart ssh, /usr/bin/systemctl restart nginx
OPS PROD = (APP) RESTART
| Alias | Resolves to |
|---|---|
User_Alias | A list of users, groups (with %), or other User_Aliases |
Runas_Alias | A list of target users (root, %group, etc.) |
Host_Alias | A list of hosts, IPs, netgroups, or other Host_Aliases |
Cmnd_Alias | A list of commands, with optional arguments |
Defaults
The Defaults directive sets options globally or per-rule:
$ sudo -l | head -10Matching Defaults entries for alice on host01:
env_reset, mail_badpass, secure_path=/usr/local/sbin\\:/usr/local/bin\\:/usr/sbin\\:/usr/bin\\:/sbin\\:/bin, use_pty
User alice may run the following commands on host01:
...Illustrative output
Common Defaults:
| Default | Effect |
|---|---|
env_reset | Clear the user’s environment, set a clean one |
secure_path | PATH the elevated command uses |
use_pty | Allocate a pseudo-terminal for the command |
log_input, log_output | Log stdin/stdout of elevated commands |
iolog_dir | Where input/output logs are written |
timestamp_timeout=0 | Always require re-authentication |
timestamp_timeout=5 | Default — 5 minute grace |
mail_badpass | Email root on bad password attempts |
passwd_tries=3 | Three attempts before sudo gives up |
insults | Insult the user on bad password (humorous, but rarely enabled) |
Per-rule defaults
A Defaults can be scoped to a specific rule:
Defaults:ops !log_input, !log_output
ops ALL=(ALL) ALL
The Defaults line applies only to the rules that match the user
list ops.
Least privilege: enumerate positively
Write the commands you intend to permit, one at a time, with
absolute paths. Never start from ALL and carve pieces out.
Cmnd_Alias SSH_OPS = /usr/bin/systemctl restart ssh, \
/usr/bin/systemctl status ssh
alice ALL=(root) SSH_OPS
This is the only model that actually constrains what alice can do, because sudo grants exactly what is listed and nothing else. Every addition is a deliberate, reviewable line.
Last match wins
sudo does not stop at the first matching rule. It evaluates every entry that matches and applies the last one.
%ops ALL=(ALL) !/usr/bin/su # intended as a deny
%ops ALL=(ALL) ALL # this wins - the deny above is dead
Negation and exceptions
The ! operator removes a command from a list:
alice ALL=(ALL) ALL, !/usr/bin/sudo, !/usr/bin/su
Read literally, this allows alice to run anything except sudo and
su. It parses cleanly. It is also not a security control.
Editing sudoers safely
$ sudo visudo -c -f /etc/sudoers.d/myapp/etc/sudoers.d/myapp: parsed OKIllustrative output
Drop-in files
Place service-specific rules in /etc/sudoers.d/<name>. Each file
must be owned by root, mode 0440. Files are parsed in lexical
order; place general rules early, specific rules late.
$ ls -l /etc/sudoers.d/-r--r----- 1 root root 450 Aug 9 11:11 /etc/sudoers.d/myapp
-r--r----- 1 root root 270 Aug 9 11:11 /etc/sudoers.d/operators
-r--r----- 1 root root 180 Aug 9 11:11 /etc/sudoers.d/breakglassIllustrative output
Knowledge check
Knowledge check · 5 questions
Q1. What does the rule `alice ALL=(root) /usr/bin/systemctl restart ssh` mean?
Q2. It is acceptable to specify a Cmnd_Alias entry without the absolute path.
Q3. Which of the following sudoers practices are correct? Select all that apply.
Q4. An auditor flags a broad grant. You add /etc/sudoers.d/10-deny-su containing `%ops ALL=(ALL) !/usr/bin/su`. The existing broad grant lives in /etc/sudoers.d/50-ops. visudo reports parsed OK. What have you actually achieved?
Q5. man 5 sudoers describes subtracting a command from ALL, as in `ALL, !/usr/bin/su`, as advisory at best rather than a real control.
Passing score: 75%. Answers are checked in this browser.