Skip to content

sudo Configuration

Applies to CentOS Stream 9 & 10 / AlmaLinux 9.x & 10.x / Rocky Linux 9.x & 10.x

sudo allows regular users to execute commands as another user (typically root) without knowing the root password. Properly configuring sudo is a critical aspect of server security management.

  • How sudo works and basic usage
  • Safely editing the sudoers file with visudo
  • sudoers file syntax
  • Configuring sudo privileges for users and groups
  • NOPASSWD configuration
  • sudo log auditing
  • The wheel group on EL systems
  • A system with EL 9.x installed
  • Currently have sudo privileges or can log in as root
  • Familiarity with the basics of User and Group Management

When you execute sudo <command>:

  1. The system checks the /etc/sudoers file to verify whether the current user has permission
  2. The user is prompted to enter their own password (not the root password)
  3. After successful verification, the command is executed as the target user (root by default)
  4. The action is recorded in the system log
Execute a command as root
$ sudo systemctl restart nginx
[sudo] password for admin:
Execute a command as another user
$ sudo -u postgres psql
View the current user's sudo privileges
$ sudo -l

Example output:

Matching Defaults entries for admin on myserver:
!visiblepw, always_set_home, match_group_by_gid, always_query_group_plugin,
env_reset, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS",
secure_path=/sbin:/bin:/usr/sbin:/usr/bin
User admin may run the following commands on myserver:
(ALL) ALL

On EL systems, the wheel group is the default administrator group. Users belonging to the wheel group have full sudo privileges.

View wheel group members
$ getent group wheel
wheel:x:10:admin
Add a user to the wheel group to grant sudo privileges
$ sudo usermod -aG wheel newadmin

This is the default wheel group configuration in /etc/sudoers:

View the wheel configuration in sudoers
$ sudo grep wheel /etc/sudoers
## Allows people in group wheel to run all commands
%wheel ALL=(ALL) ALL

The visudo command automatically checks for syntax errors when saving:

Edit sudoers using visudo
$ sudo visudo

If you want to use a different editor:

Use vim as the visudo editor
$ sudo EDITOR=vim visudo

It is recommended to place custom configurations in the /etc/sudoers.d/ directory rather than modifying the main /etc/sudoers file directly:

Create a custom sudoers configuration
$ sudo visudo -f /etc/sudoers.d/custom-rules

Confirm that the main file includes a reference to this directory (EL 9 includes it by default):

Confirm sudoers references the sudoers.d directory
$ sudo grep "includedir" /etc/sudoers
#includedir /etc/sudoers.d
user host=(target-user:target-group) command

Part descriptions:

PartDescription
UserThe authorized username; prefix group names with %
HostThe host this rule applies to; ALL means all hosts
Target userThe user that can be switched to; ALL means all users
Target groupThe group that can be switched to (optional)
CommandThe commands allowed; ALL means all commands
Allow user deploy to execute all commands
deploy ALL=(ALL) ALL
Allow all members of the developers group to execute all commands
%developers ALL=(ALL) ALL
Allow a user to execute only specific commands
webadmin ALL=(ALL) /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx
Allow a user to execute commands as the postgres user
dbadmin ALL=(postgres) ALL
Deny a user from executing certain commands
operator ALL=(ALL) ALL, !/usr/bin/su, !/usr/bin/passwd root

When multiple users need the same privileges, aliases can simplify the configuration:

Define command aliases
Cmnd_Alias WEB_CMDS = /usr/bin/systemctl restart nginx, \
/usr/bin/systemctl reload nginx, \
/usr/bin/systemctl status nginx
Cmnd_Alias PKG_CMDS = /usr/bin/dnf install *, \
/usr/bin/dnf update *, \
/usr/bin/dnf remove *
Use command aliases
webadmin ALL=(ALL) WEB_CMDS
pkgadmin ALL=(ALL) PKG_CMDS

You can also define user aliases and host aliases:

Define a user alias
User_Alias WEBTEAM = zhangsan, lisi, wangwu
WEBTEAM ALL=(ALL) WEB_CMDS

By default, using sudo requires the user to enter their own password. You can configure password-free execution:

Allow a user to execute all commands without a password
deploy ALL=(ALL) NOPASSWD: ALL
Password-free for specific commands only
monitor ALL=(ALL) NOPASSWD: /usr/bin/systemctl status *, /usr/bin/journalctl
wheel group password-free (not recommended for production)
%wheel ALL=(ALL) NOPASSWD: ALL
Some commands password-free, others require a password
operator ALL=(ALL) NOPASSWD: /usr/bin/systemctl status *, PASSWD: /usr/bin/systemctl restart *

All sudo operations are recorded in the system log, which is essential for security auditing.

View sudo logs (using journalctl)
$ sudo journalctl -u sudo
View sudo records in /var/log/secure
$ sudo grep sudo /var/log/secure

Example output:

Mar 24 14:30:22 myserver sudo: admin : TTY=pts/0 ; PWD=/home/admin ; USER=root ; COMMAND=/usr/bin/systemctl restart nginx

You can configure additional logging options in sudoers:

Edit sudoers to add logging configuration
$ sudo visudo -f /etc/sudoers.d/logging
Enable sudo command logging
Defaults log_input, log_output
Defaults logfile="/var/log/sudo.log"
Defaults iolog_dir="/var/log/sudo-io/%{seq}"

Practical Example: Configuring Multi-Level Privileges

Section titled “Practical Example: Configuring Multi-Level Privileges”

The following example demonstrates how to configure different sudo privileges for different roles.

  1. Create the role configuration file

    Create a custom sudoers file
    $ sudo visudo -f /etc/sudoers.d/team-roles
  2. Define command aliases

    # Service management commands
    Cmnd_Alias SVC_CMDS = /usr/bin/systemctl start *, \
    /usr/bin/systemctl stop *, \
    /usr/bin/systemctl restart *, \
    /usr/bin/systemctl reload *, \
    /usr/bin/systemctl status *
    # Read-only monitoring commands
    Cmnd_Alias MON_CMDS = /usr/bin/systemctl status *, \
    /usr/bin/journalctl *, \
    /usr/bin/top, \
    /usr/bin/htop, \
    /usr/bin/ss, \
    /usr/bin/df, \
    /usr/bin/free
  3. Assign privileges

    # Operations staff: full service management privileges
    %ops ALL=(ALL) SVC_CMDS
    # Monitoring staff: read-only privileges, no password required
    %monitors ALL=(ALL) NOPASSWD: MON_CMDS
    # Deployment account: full privileges, no password
    deploy ALL=(ALL) NOPASSWD: ALL
  4. Create the corresponding groups and add users

    Create groups and add users
    $ sudo groupadd ops
    $ sudo groupadd monitors
    $ sudo usermod -aG ops zhangsan
    $ sudo usermod -aG monitors lisi
  5. Verify the configuration

    Verify zhangsan's privileges
    $ sudo -U zhangsan sudo -l
CommandDescription
sudo <command>Execute a command as root
sudo -u <user> <command>Execute a command as a specified user
sudo -lList the current user’s sudo privileges
sudo -U <user> -lList a specified user’s sudo privileges (requires root)
sudo -iSwitch to root’s login shell
sudo -sStart a shell as root (without switching environment)
sudo -kClear the sudo password cache
sudo -vRefresh the password cache timeout

The user does not have sudo privileges. Add the user to the wheel group as root:

Operate as root
$ su -
# usermod -aG wheel username
# exit

”syntax error” Prevents sudo from Working

Section titled “”syntax error” Prevents sudo from Working”

If you incorrectly edited /etc/sudoers directly and introduced a syntax error:

Method 1: If you have another user with sudo privileges or can log in as root:

Fix the sudoers syntax
$ su -
# visudo

Method 2: If you cannot log in as root, you will need to enter rescue mode.

How to Adjust the sudo Password Cache Duration

Section titled “How to Adjust the sudo Password Cache Duration”
Set the password cache timeout to 15 minutes
$ sudo visudo -f /etc/sudoers.d/timeout
Defaults timestamp_timeout=15

Set to 0 to require a password every time. Set to -1 to never expire (not recommended).

For automated scripts, it is recommended to configure NOPASSWD privileges for the script-executing user (limited to specific commands) to avoid the script hanging at a password prompt.

Configure password-free access for automation scripts
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart myapp, /usr/bin/dnf update myapp