4 of 4

Users, Groups and sudoLesson 4 of 4

Privileged access with sudo

Give people the root powers they need and no more: wheel, drop-in sudoers files, command lists and passwordless rules.

  • sudo
  • visudo
  • sudo -l
  • sudo -u
  • visudo -c
  • /etc/sudoers.d
  • journalctl _COMM=sudo

45 min5 exercises

After this lesson you can

  • Grant full administrative access with the wheel group, and revoke it.
  • Write a rule for specific commands, with or without a password, in a drop-in file that is syntax-checked.
  • Read what a user may run with sudo -l, and find who ran what in the logs.

The idea

sudo runs one command as another user (root by default), after checking /etc/sudoers and every file in /etc/sudoers.d/. Compared with sharing the root password it gives you three things: individual accountability (each use is logged with the real user), least privilege (a user can be limited to certain commands), and no shared secret to change when someone leaves.

On RHEL, members of the group wheel are administrators. The line %wheel ALL=(ALL) ALL in /etc/sudoers is already active, so adding a user to wheel is the standard way to make them an admin.

For anything more specific, add a drop-in file in /etc/sudoers.d/. The rule format is:

who   where=(as_whom)   [NOPASSWD:]  commands
PartExampleMeaning
whoerin, %webopsA user, or a group (prefix %)
whereALLWhich hosts the rule applies to
as_whom(root), (ALL)The users they may become
commands/usr/bin/systemctl restart chronydFull paths. ALL allows everything

Try it

sudo usermod -aG wheel dana
sudo -l -U dana
User dana may run the following commands on rhel10:
    (ALL) ALL
sudo visudo -f /etc/sudoers.d/erin
erin ALL=(root) NOPASSWD: /usr/bin/systemctl restart chronyd
sudo visudo -c
sudo -l -U erin
/etc/sudoers: parsed OK
/etc/sudoers.d/erin: parsed OK
User erin may run the following commands on rhel10:
    (root) NOPASSWD: /usr/bin/systemctl restart chronyd

Command aliases for readability

Cmnd_Alias WEB = /usr/bin/systemctl start httpd, \
                 /usr/bin/systemctl stop httpd, \
                 /usr/bin/systemctl restart httpd, \
                 /usr/bin/systemctl status httpd
%webops ALL=(root) WEB

Matching is on the exact command line. systemctl restart httpd is allowed above; systemctl restart httpd --now or systemctl restart sshd are not.

The audit trail

Every sudo use is logged with the real user. On RHEL the entries go to the journal and to /var/log/secure:

sudo journalctl _COMM=sudo --no-pager | tail -2
Nov 03 11:21:40 rhel10 sudo[3011]:    dana : TTY=pts/0 ; PWD=/home/dana ; USER=root ; COMMAND=/usr/bin/id
Nov 03 11:21:40 rhel10 sudo[3011]: pam_unix(sudo:session): session opened for user root(uid=0) by dana(uid=1002)

Going further

sudo -l (no user) lists your own rights. sudo -u bob command runs as another user, and sudo -k forgets your cached password so the next use asks again (the cache lasts 5 minutes by default). Never give NOPASSWD: ALL to a human account, and never allow commands that can start a shell (vi, less, find -exec): a user can escape to a root shell from them. For passwordless rules use the narrowest possible command line.

Practice

0 of 5 done

Do these on your own system. They get harder. Check each result, then tick it off.

  1. Warm-up

    Make someone an administrator

    Give dana full sudo rights using group membership, not by editing the sudoers file. Verify as dana, then remove the right again.

    Check your result

    sudo -l -U dana lists (ALL) ALL while dana is in wheel, and says User dana is not allowed to run sudo after removal.

    Hint

    On RHEL the line %wheel ALL=(ALL) ALL is already active. Add or remove dana in wheel.

    Solution
    sudo usermod -aG wheel dana
    sudo -l -U dana
    sudo gpasswd -d dana wheel
    sudo -l -U dana
  2. Practice

    Allow one command, no password

    Let the user erin restart the chronyd service with sudo and no password, but nothing else. Write the rule in its own file under /etc/sudoers.d and check its syntax before relying on it. Test as erin that systemctl restart chronyd works and systemctl restart sshd is refused.

    Check your result

    sudo visudo -c prints parsed OK. sudo -l -U erin shows NOPASSWD: /usr/bin/systemctl restart chronyd. As erin the sshd restart asks for a password or is denied.

    Hint

    erin ALL=(root) NOPASSWD: /usr/bin/systemctl restart chronyd. Use visudo -f /etc/sudoers.d/erin so the file is checked on save.

    Solution
    sudo visudo -f /etc/sudoers.d/erin
    # erin ALL=(root) NOPASSWD: /usr/bin/systemctl restart chronyd
    sudo visudo -c
    sudo -l -U erin
    sudo -u erin sudo -n systemctl restart chronyd
    sudo -u erin sudo -n systemctl restart sshd
  3. Practice

    A rule for a whole group, with aliases

    Create a group webops. Let its members run systemctl start|stop|restart|status httpd and read the Apache log with tail on /var/log/httpd/error_log as root, entering their own password. Use a Cmnd_Alias so the rule stays readable.

    Check your result

    sudo visudo -c parses OK. sudo -l -U <member> lists the allowed commands.

    Hint

    Cmnd_Alias WEB = /usr/bin/systemctl start httpd, ... then %webops ALL=(root) WEB.

    Solution
    sudo groupadd webops
    sudo visudo -f /etc/sudoers.d/webops
    # Cmnd_Alias WEB = /usr/bin/systemctl start httpd, /usr/bin/systemctl stop httpd, \
    #                  /usr/bin/systemctl restart httpd, /usr/bin/systemctl status httpd, \
    #                  /usr/bin/tail /var/log/httpd/error_log
    # %webops ALL=(root) WEB
    sudo visudo -c
  4. Practice

    Find who did what

    As dana (with sudo rights) run a harmless sudo command. Then, as an administrator, find the log entry that records the user, the directory, the target user and the exact command.

    Check your result

    The journal or /var/log/secure has a line containing dana : TTY=... ; PWD=... ; USER=root ; COMMAND=....

    Hint

    sudo journalctl _COMM=sudo or sudo grep 'COMMAND=' /var/log/secure.

    Solution
    sudo -u dana sudo id
    sudo journalctl _COMM=sudo --no-pager | tail -3
  5. Challenge

    Recover from a broken sudoers file

    Explain why you should never edit /etc/sudoers with a normal editor. Then create a deliberately wrong file /etc/sudoers.d/bad containing this is not valid in a way that is caught (use visudo -c -f), and show that the live system is not affected because the check ran before the file was installed.

    Check your result

    sudo visudo -c -f /tmp/bad reports a syntax error and a non-zero exit status. sudo -l still works because the bad file never reached /etc/sudoers.d.

    Hint

    Write the candidate to /tmp/bad, check it with visudo -cf, and only install -m 0440 it if the check passes.

    Solution
    echo 'this is not valid' > /tmp/bad
    sudo visudo -c -f /tmp/bad; echo $?
    sudo -l