Basic use
sudo whoami
▸root (if you are in sudoers)
sudo apt update # run apt as root
sudo -u alice ls /home/alice # -u: as a specific user, not root
sudo -i # open a full root session
sudo -s # a root shell, but with your environment
sudo -E command # keep your environment (env)
It asks for your password (not root's), to confirm that this is still you and not someone who grabbed the terminal. By default it remembers you for 5 to 15 minutes (the timestamp).
/etc/sudoers: who can do what
This is the main policy file. Never edit it directly. Use
visudo, which checks the syntax before saving (otherwise you can
lock yourself out of sudo entirely).
sudo visudo # /etc/sudoers
sudo visudo -f /etc/sudoers.d/myapp # a separate fragment
The modern practice is to put custom rules in /etc/sudoers.d/*
and leave the base file alone.
Rule syntax
user host = (run-as) [tag:] command
Examples:
alice ALL=(ALL) ALL # alice: everything, everywhere, as any user
bob ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx
# ↑ bob can restart nginx without a password, and nothing else
%wheel ALL=(ALL) ALL # everyone in the wheel group: full rights
%dev ALL=(ALL) NOPASSWD: /usr/local/bin/deploy.sh
Tags:
- NOPASSWD: runs without a password prompt
- PASSWD: is the reverse
- NOEXEC: stops child processes from calling exec*
- SETENV: allows -E (passing env through)
sudo -l: what am I allowed to do
sudo -l # list the commands available to me
sudo -l -U alice # what alice is allowed (root needed to view another user)
This is the standard command when you onboard onto a new server: "what can I do here".
Logging
Every sudo call writes to /var/log/auth.log (Debian/Ubuntu) or to
journalctl _COMM=sudo:
sudo journalctl _COMM=sudo --since today
# Apr 28 14:23:01 host sudo: alice : TTY=pts/0 ; PWD=/home/alice ;
# USER=root ; COMMAND=/usr/bin/apt update
Production systems often turn on sudoreplay, which records everything
that happened in a sudo session (Defaults log_input,log_output).
Safe patterns
1. Groups instead of individual users. The wheel or sudo group
is the standard way to grant "full" rights:
sudo usermod -aG sudo alice
2. NOPASSWD only for specific commands. Do not grant NOPASSWD on ALL. That is equivalent to "pwn without a password once you take over a sudo user".
3. Do not use sudo in scripts with a password in the arguments.
Use NOPASSWD for a specific command, or a systemd service running as root.
4. Defaults requiretty is a deprecated option. It used to force you
to work only on a tty (a mitigation against credential stealing). These
days it is usually disabled for the sake of automation.
Alternatives
- doas (OpenBSD-portable) is a minimal sudo replacement with a simpler config; it ships as an option on Alpine/Arch
- pkexec (polkit) is for graphical environments, governed by polkit rules
- systemd PrivateUsers/CAP_: for services, set capabilities in the unit file rather than going through sudo
sudo vs su
su - also gives you root, but through root's password. The modern
practice is to disable the root password altogether (sudo passwd -l root)
and use only sudo. This gives you:
- A per-user audit log (you see WHO did what)
- Granular rules (one person can do everything, another only nginx)
- No shared root password to store
sudo and file-permissions / capabilities
Sometimes you do not need sudo at all. If your binary needs to listen on port 80:
- Bad:
sudo ./myappis overkill, the whole binary runs as root - Better:
setcap cap_net_bind_service+ep ./myapp && ./myappgrants a single capability (capabilities) - Better still: a systemd unit with
AmbientCapabilities=CAP_NET_BIND_SERVICEandUser=myapp
Sudo is a hammer. Often what you want is a screwdriver.