15.3 visudo: The Only Safe Way to Edit sudoers
Right, let’s talk about visudo. This is one of those rare, non-negotiable best practices in system administration. You could just open /etc/sudoers in vim, nano, or even (shudder) notepad.exe if you’re feeling particularly self-destructive. But you absolutely should not. Here’s why.
The sudoers file is the single point of truth for who gets to do what with sudo. If you introduce a syntax error into this file—a missing comma, a stray quote, a typo in a hostname—you can completely lock yourself and every other admin out of root access. The system will refuse to run sudo at all until the error is fixed. And how do you fix it? Without sudo, you can’t edit the file you just broke. You’d have to reboot into single-user mode or use a live CD. It’s a spectacularly annoying and entirely preventable self-own.
visudo is your safety net. It’s a wrapper that locks the file (so two people aren’t editing it at once) and, most importantly, it performs a syntax check on the file before it saves your changes and replaces the original. If you’ve borked it, visudo will stop you, tell you exactly what’s wrong, and ask if you want to edit it again. It saves you from yourself.
How to Actually Use visudo
By default, visudo uses the vi editor. If the mere thought of :wq gives you hives, you can point it at your preferred editor by setting the EDITOR environment variable.
# To use nano instead (no judgment, we all start somewhere)
export EDITOR=nano
visudo
# Or to make it permanent for your user, stick it in your ~/.bashrc
echo 'export EDITOR=nano' >> ~/.bashrc
Once you’re in, you’ll see the stock sudoers file. It looks intimidating, but most of it is helpful comments. The key lines you’ll likely be messing with are the # User privilege specification section.
The Syntax: It’s Weird, Just Roll With It
The syntax is its own little language. It’s not a standard config format like YAML or JSON; it’s its own thing, and it’s a bit persnickety. The basic structure for a rule is:
who where = (as_whom) what
Let’s break that down with an example. Say you want to let the deploy user run only the systemctl restart nginx command without a password.
# This is the line you'd add with visudo:
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx
deploy: The user (who).ALL: The hostname this rule applies to (where).ALLmeans… all hosts. Useful if your sudoers file is shared across a network, which is a whole other can of worms.(root): The user they can run the commandas_whom. The parentheses are mandatory.NOPASSWD:: This is a “tag”. It means they won’t be prompted for their password. Remove it, and they will be./usr/bin/systemctl restart nginx: The command itself. Crucially, you must use the full path. This is a classic pitfall.sudohas no idea what your$PATHis, for security reasons. It uses a secure, default path. If you writesystemctlinstead of/usr/bin/systemctl, the rule will simply never match and the command will be denied.
Aliases and Grouping: For Your Sanity
Typing out every single user and command would be madness. The designers knew this, so they gave us aliases. You can define groups of users (User_Alias), groups of commands (Cmnd_Alias), and groups of run-as users (Runas_Alias).
Let’s say you have a team of three developers who all need to manage the web stack. Here’s how you’d do it cleanly:
# Define a group of users
User_Alias WEB_ADMINS = alice, bob, carol
# Define a group of commands for web stuff
Cmnd_Alias WEB_CMDS = /usr/bin/systemctl reload nginx, \
/usr/bin/systemctl restart nginx, \
/usr/bin/tail -f /var/log/nginx/access.log
# Now the rule is simple and readable
WEB_ADMINS ALL=(root) WEB_CMDS
Notice the backslashes (\). They are essential for continuing a command alias onto a new line. Forget one, and visudo will (thankfully) yell at you.
The Nuclear Option: Shell Escape and Wildcards
Be terrified of wildcards. No, really. A rule like deploy ALL=(root) NOPASSWD: /usr/bin/apt * seems convenient. It lets the deploy user run apt install, apt update, etc. But what does apt actually do? It calls other programs. And what can you do with a wildcard? Everything. A user could run sudo apt update && chmod -R 777 / by exploiting how shell escaping works.
If you must use a wildcard, be as specific as humanly possible. Prefer something like NOPASSWD: /usr/bin/apt install package-name, /usr/bin/apt remove package-name instead of just *. Your future self, dealing with a compromised system, will thank you for the extra keystrokes.
The bottom line is this: visudo isn’t a suggestion; it’s the law. Use it. Rely on its syntax check. And for the love of all that is holy, test your new rules in a new terminal session before you log out of your root-capable one. Trust, but verify. Especially when you’re the one who did the trusting.