Skip to content

Configuring sudo Properly

💡
Before you start

You need a Linux machine where you can use sudo, and you should not practise on a server anyone depends on. The commands here change real system state. A spare machine, a virtual machine, or a cloud instance you can rebuild is the right place; a laptop you own is fine too. If the terminal itself is new to you, do Introduction to the Linux Terminal first — it takes about ten minutes and everything below assumes it. Every step tells you how to undo it.

What sudo Is Actually For

sudo exists so that nobody has to log in as root. Each administrator keeps their own account and password, elevates only for the commands that need it, and every elevation is logged against a real person. Shared root passwords give you none of that: no attribution, no revocation without changing it for everyone, no audit trail.

Start by seeing what you can already do:

sudo -l

This lists the rules that apply to you. It is also the first thing an attacker runs after compromising an account, for exactly the same reason.

Always Edit With visudo

⚠️
Never open /etc/sudoers in a plain editor.

A syntax error there can make sudo refuse to run at all — and if root login is disabled, you have locked yourself out of administering the machine. visudo checks the syntax before saving and refuses to write a broken file. That check is the entire point.

sudo visudo                                   # the main file
sudo visudo -f /etc/sudoers.d/deploy          # a drop-in
sudo visudo -c                                # check the current configuration

Prefer drop-in files under /etc/sudoers.d/ over editing the main file. They survive package upgrades, are easy to review, and can be removed cleanly. Note that files with a dot in the name are ignored — name it deploy, not deploy.conf.

Keep a second root session open while changing sudo rules, so a mistake is an inconvenience rather than a lockout.

Reading a Rule

alice   ALL=(ALL:ALL) ALL

Four parts, left to right:

  • alice — who the rule applies to. A leading % means a group (%sudo, %wheel)
  • ALL= — on which hosts. Almost always ALL on a single machine
  • (ALL:ALL) — which users and groups they may run as
  • final ALL — which commands. This is where least privilege lives

Granting a specific, limited capability:

%webadmin ALL=(root) /usr/bin/systemctl restart nginx, /usr/bin/systemctl status nginx

Always use absolute paths. A bare command name can be satisfied by anything earlier in the user's PATH.

Rules That Look Restrictive But Are Not

This is the part that matters most, and it is genuinely counter-intuitive: many narrow-looking grants are equivalent to full root.

  • Any editorsudo vim, nano, less and more can all spawn a shell from inside. Granting one grants root. Use sudoedit instead
  • Any interpreterpython, perl, awk, find (via -exec) all execute arbitrary code
  • Wildcards in arguments/bin/chown * /srv lets the user supply arguments you did not anticipate. Wildcards in sudoers are far weaker than they look
  • A writable script — if the user can edit the script they are allowed to run as root, they can run anything as root. Check the script's own permissions
  • systemctl without a specific unit — general systemctl access allows starting a unit the user controls
💡
Use sudoedit for files, never sudo <editor>.

sudoedit /etc/nginx/nginx.conf copies the file to a temporary location, opens it as your unprivileged user, and copies it back on save. The editor never runs as root, so there is no shell to escape into. Grant it as sudoedit /etc/nginx/*.

NOPASSWD, and When It Is Defensible

deploy ALL=(root) NOPASSWD: /usr/bin/systemctl reload nginx

NOPASSWD removes the password prompt. It is legitimate for automation — a deploy account cannot type a password — but it means anyone who obtains that account's shell gets that capability instantly, with no second factor.

  • Never NOPASSWD: ALL for a human account. That is a root login with extra steps
  • Scope it to exact commands with absolute paths and no wildcards
  • Pair it with a locked-down account — key-only SSH, no interactive shell where possible

Useful Defaults

Defaults        timestamp_timeout=5
Defaults        logfile="/var/log/sudo.log"
Defaults        passwd_tries=3
Defaults        lecture=once
Defaults:deploy !requiretty
  • timestamp_timeout — minutes before sudo asks again. 0 means every single time; a low number is a good balance on a shared machine
  • logfile — a dedicated sudo log alongside the syslog entries
  • env_reset — on by default and should stay that way; it strips the caller's environment so variables like LD_PRELOAD cannot follow you into a root process

Auditing

sudo -l -U alice                         # what alice may do
sudo grep sudo /var/log/auth.log | tail   # recent sudo activity (Debian/Ubuntu)
journalctl _COMM=sudo -n 50               # the same via journald
getent group sudo                         # who is in the sudo group

Review group membership as carefully as the rules themselves. Most real over-privilege comes from an account quietly sitting in sudo or wheel, not from an exotic sudoers line.

Now Do It Yourself: Five Steps

A sudo rule that parses is not the same as a sudo rule that is safe. You will write rules, break them on purpose to learn the error format, and then see a rule that passes every check while quietly granting full root. Steps 1 to 4 need no sudo at all — you can do them on any machine, because visudo will check a file you own.

1
Find out what you are currently allowed to do

Go: open a terminal.

Do: run sudo -l. It will ask for your password.

You should see: a Matching Defaults entries block listing settings such as env_reset and timestamp_timeout, then the commands you may run. env_reset is a security control worth noticing: it strips your environment variables before running the command, so you cannot smuggle in a hostile PATH.

If not: user is not allowed to run sudo means your account is not in the administrators group — on Debian and Ubuntu that is sudo, on Red Hat-family systems wheel. Steps 2 to 4 still work regardless, because they only validate files.

2
Write a rule, and check it the safe way

Go: run cd, then mkdir -p practice and cd practice. You are writing an ordinary file, not touching the real configuration.

Do: run these two commands.

printf 'alice ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx\n' > ok.rule
visudo -c -f ok.rule

You should see: ok.rule: parsed OK. Read the rule as five parts: who (alice), on which hosts (ALL), as whom they may run ((ALL)), whether a password is required (NOPASSWD), and exactly which command.

If not: visudo: command not found means it is in /usr/sbin, which is not on a normal user's path — run /usr/sbin/visudo -c -f ok.rule. 🔴 Never edit the real sudoers file with an ordinary editor. Use sudo visudo, which validates before saving. A syntax error in that file can lock every administrator out of the machine, and fixing it then needs a rescue boot.

3
Break it on purpose and learn to read the error

Go: same folder.

Do: run these two commands. The colon after NOPASSWD is missing.

printf 'alice ALL=(ALL) NOPASSWD /usr/bin/systemctl\n' > bad.rule
visudo -c -f bad.rule

You should see: bad.rule:1:44: syntax error, the offending line printed back, and a ^ underneath pointing at the position. The format is file:line:column.

If not: note carefully where the caret points — the end of the line, not at the missing colon. A parser reports where it gave up, not where you went wrong, and those are rarely the same place. The same end-of-line caret appears if you misspell the keyword as NOPASWD, which is why reading the whole line yourself beats trusting the pointer.

4
Grant a group instead of a person, using an alias

Go: same folder.

Do: run these two commands. The % is what marks a group.

printf 'Cmnd_Alias SERVICES = /usr/bin/systemctl start nginx, /usr/bin/systemctl stop nginx\n%%developers ALL=(ALL) NOPASSWD: SERVICES\n' > group.rule
visudo -c -f group.rule

You should see: group.rule: parsed OK. Granting to a group rather than to named people is what stops sudoers rotting — when someone joins or leaves you change their group membership, and no rule needs touching.

If not: if you write the group without % it is read as a username, so the rule silently applies to nobody and never fires. That failure is invisible: the file parses, sudo simply does not match. Confirm a rule actually applies with sudo -l -U username.

5
See a rule that passes every check and still gives away root

Go: same folder. This is the step that matters.

Do: run these two commands.

printf 'alice ALL=(ALL) NOPASSWD: /usr/bin/find\n' > danger.rule
visudo -c -f danger.rule

You should see: danger.rule: parsed OK — completely valid. And yet it is equivalent to giving alice unrestricted root, because find has an -exec option that runs any command she names. The same is true of editors, awk, tar, less and anything else that can shell out or write arbitrary files.

If not: there is nothing to fix here — the point is that the validator checks grammar, never consequences. Before granting any command, ask what else it can be made to do. Prefer whole-command paths with fixed arguments, never a wildcard, and never a program that can spawn another. When in doubt, look the program up on GTFOBins, a public catalogue of exactly these escapes.

🎉
Check yourself before moving on

Without scrolling up: visudo -c says parsed OK. What has it actually told you, and what has it not? Answer: that the grammar is valid. It says nothing at all about whether the rule is safe — a rule granting find, vi or tar parses perfectly and hands over full root.

Now do it without the page: write a rule letting the developers group restart one named service without a password, check it parses, then argue with yourself about whether that command could be turned into something wider. Then check the real file's permissions with ls -l /etc/sudoers — it is 440, readable only by root and its group, and sudo refuses to run at all if that is loosened.

Summary

  • Always visudo, and prefer drop-ins in /etc/sudoers.d/ (no dots in the filename)
  • Keep a second root session open while editing rules
  • Editors and interpreters mean full root — use sudoedit
  • Absolute paths, no wildcards, and check that granted scripts are not user-writable
  • NOPASSWD only for automation, scoped to exact commands
  • Audit group membership — that is where over-privilege usually hides
🎉
Check one thing now.

Run getent group sudo and sudo -l. If either lists an account or a capability you would not deliberately grant today, you have found the highest-value fix on the machine.