| |

LFCS 42 ๐Ÿง Sudo Configuration โ€” visudo and sudoers

โฑ๏ธ Estimated read: 12 min | |

The previous chapter established that sudo delegates privilege escalation through rules in /etc/sudoers. This chapter goes deeper into the two tools that make that configuration safe and maintainable: visudo and the sudoers grammar itself. The LFCS exam expects you to configure sudo access and command aliases, and to restrict privilege escalation via sudo . Both objectives converge on the same file and the same editor.

The /etc/sudoers file is parsed by a strict grammar. A misplaced character can cause sudo to refuse every request, locking you out of administrative access entirely. This is not hypotheticalโ€”it is the single most common way administrators brick a system. visudo exists to prevent this: it locks the file, opens it in an editor, parses the syntax on save, and refuses to write invalid configuration. It also checks file permissions and ownership, which sudo itself enforces at runtime.

The sudoers grammar has four components per rule: who, where, as whom, and what. Beyond the basic rule, the file supports aliases for users, hosts, runas users, and commands. Aliases reduce repetition and make policies readable. The drop-in directory /etc/sudoers.d/ lets you keep custom rules separate from the main file, so OS upgrades do not overwrite them. This chapter covers all of it: visudo usage, the grammar, aliases, and the drop-in directory.

Key point: visudo is the only safe way to edit /etc/sudoers and its drop-in files because it validates syntax before saving; the grammar follows WHO WHERE=(AS_WHOM) WHAT, and aliases (User_Alias, Cmnd_Alias, Host_Alias, Runas_Alias) reduce repetition.


Why visudo and sudoers grammar matter

The lockout problem. /etc/sudoers is parsed at every sudo invocation. If the file contains a syntax error, sudo refuses to run any command for any user. If you edited the file without visudo and introduced an error, you cannot fix it with sudo because sudo is broken. Recovery requires booting into single-user mode or using pkexec. visudo prevents this by parsing the file before saving and offering to re-edit on error .

The permission enforcement problem. sudo checks that /etc/sudoers is owned by root:root and mode 0440. If the permissions are wrong, sudo refuses to use the file, regardless of its contents. A common cause is editing with a tool that changes ownership or permissions. visudo sets the correct permissions automatically. Drop-in files in /etc/sudoers.d/ must also be 0440 and owned by root; if they are not, they are silently ignored .

The filename restriction. Files in /etc/sudoers.d/ must not contain dots (.) or end with a tilde (~). A file named admin.conf is ignored; admin works. Backup files created by editors (admin~) are also ignored, which is intentionalโ€”it prevents a broken backup from breaking sudo. The filename should use only alphanumeric characters and hyphens .

The alias problem. Without aliases, a policy that grants a group access to ten commands repeats the group name ten times. A typo in one repetition creates an inconsistent policy that is hard to audit. Aliases (Cmnd_Alias, User_Alias) define the set once and reference it by name . They also make the policy self-documenting: %webadmins ALL=(root) SERVICES is clearer than a list of five systemctl paths.

The drop-in maintenance problem. The main /etc/sudoers file is owned by the package manager. If you add custom rules there, an OS upgrade may overwrite them. The drop-in directory exists so that custom rules survive upgrades. The main file includes the directory via @includedir /etc/sudoers.d (or #includedir on some distributions) . Each drop-in file is independent: you can add or remove a role by adding or removing a file.


a. Using visudo correctly

visudo opens /etc/sudoers in the editor specified by the EDITOR environment variable (or vi if unset). It locks the file to prevent concurrent edits, parses the syntax on save, and writes only if the syntax is valid .

sudo visudo

To edit a drop-in file, use the -f flag:

sudo visudo -f /etc/sudoers.d/webadmins

This opens the specified file with the same syntax validation. If the file does not exist, visudo creates it. It also sets the correct permissions (0440) on save .

To check a file without editing it, use -c:

sudo visudo -c -f /etc/sudoers.d/webadmins

This parses the file and reports syntax errors without opening an editor. It is useful for validating files in scripts or CI pipelines .

The -q flag suppresses the “parsed OK” message, which is useful in scripts where you only care about the exit code. The exit code is 0 on success, 1 on syntax error.

If visudo detects an error, it prints the line number and the error, then asks whether to re-edit, discard changes, or quit. Choosing re-edit returns to the editor with the file unchanged. Choosing discard exits without writing. This is the safety net: an invalid file is never written to disk.


b. The sudoers grammar and aliases

Every sudoers rule has four parts:

WHO  WHERE=(AS_WHOM)  WHAT
  • WHO: a username, a %group, a #uid, or a User_Alias.
  • WHERE: a hostname, an IP address, or ALL. In practice, ALL is almost always used.
  • AS_WHOM: a parenthesized list of users the command can run as. (ALL) or (root). If omitted, it defaults to root.
  • WHAT: an absolute command path, a directory ending in /, or a Cmnd_Alias .

A complete rule for a single user:

alice  ALL=(ALL:ALL)  ALL

The :ALL after the user list specifies the group the command can run as. (ALL:ALL) means any user and any group. (root) is shorthand for (root:root).

Aliases are defined before the rules that use them. User_Alias groups users:

User_Alias WEBADMINS = alice, bob, %webteam

Cmnd_Alias groups commands. Commands must be absolute paths:

Cmnd_Alias SERVICES = /usr/bin/systemctl start *, /usr/bin/systemctl stop *, /usr/bin/systemctl restart *, /usr/bin/systemctl status *

Host_Alias groups hosts (rarely used in practice):

Host_Alias WEBSERVERS = web1, web2, 192.168.1.10

Runas_Alias groups target users:

Runas_Alias DBUSERS = postgres, mysql

Once defined, aliases are used in rules:

WEBADMINS  ALL=(root)  SERVICES

Aliases must begin with an uppercase letter and contain only uppercase letters, digits, and underscores . They are evaluated in order; if a command matches multiple aliases with different permissions, the last matching rule wins.

The NOPASSWD: tag disables the password prompt for the commands that follow it:

deploy  ALL=(root)  NOPASSWD: /opt/deploy/run.sh

This is common for automation but reduces auditability. The PASSWD: tag restores the prompt for specific commands within a broader NOPASSWD rule .


c. The /etc/sudoers.d/ drop-in directory

The main /etc/sudoers file includes the drop-in directory with a line like:

@includedir /etc/sudoers.d

On some distributions it is #includedir. The @ form is the modern syntax; the # form is historical and still works . If this line is missing or commented out, drop-in files are ignored. Some minimal container images ship without it, which is why a drop-in rule can silently fail .

Files in /etc/sudoers.d/ follow the same grammar as the main file. A file for a web administration group:

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

The permissions must be 0440 and ownership root:root. visudo -f sets these automatically. If you create the file with a normal editor, you must set them manually:

sudo chown root:root /etc/sudoers.d/webadmins
sudo chmod 0440 /etc/sudoers.d/webadmins

The filename must not contain a dot or end with a tilde . A file named webadmins.conf is ignored; webadmins is used. This is a common source of confusion: the file exists, the syntax is correct, but sudo does not see it because of the filename.

Files are parsed in lexicographical order. Numeric prefixes (10-admins, 20-developers) control precedence. If two files define rules for the same user, the later file’s rules are applied in addition to the earlier ones; they do not override. To revoke a permission, you must remove it from the file that granted it or use a negation rule in a later file.


Complete Example Session

The following session creates a command alias, grants a group access to specific services, and validates the configuration with visudo.

# ============================================
# PART 1: OPEN A NEW DROP-IN FILE
# ============================================
sudo visudo -f /etc/sudoers.d/10-webadmins

# ============================================
# PART 2: DEFINE ALIASES AND RULES
# ============================================
# Add the following content:
# Cmnd_Alias WEB_SERVICES = /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx, /usr/bin/systemctl status nginx
# %webadmins ALL=(root) WEB_SERVICES

# ============================================
# PART 3: SAVE AND VERIFY PERMISSIONS
# ============================================
ls -l /etc/sudoers.d/10-webadmins
# Expected: -r--r----- root root

# ============================================
# PART 4: VALIDATE SYNTAX
# ============================================
sudo visudo -c -f /etc/sudoers.d/10-webadmins
# Output: parsed OK

# ============================================
# PART 5: CREATE GROUP AND ADD USER
# ============================================
sudo groupadd webadmins
sudo usermod -aG webadmins bob

# ============================================
# PART 6: TEST AS BOB (after re-login)
# ============================================
su - bob
sudo systemctl status nginx
# Allowed: matches WEB_SERVICES

sudo systemctl stop nginx
# Denied: command not in alias
# Output: Sorry, user bob is not allowed to execute '/usr/bin/systemctl stop nginx' as root

# ============================================
# PART 7: ADD NOPASSWD FOR A DEPLOY SCRIPT
# ============================================
sudo visudo -f /etc/sudoers.d/20-deploy

# Content:
# deploy ALL=(root) NOPASSWD: /opt/deploy/run.sh

# ============================================
# PART 8: VERIFY THE DROP-IN IS INCLUDED
# ============================================
grep -E '^[@#]includedir' /etc/sudoers
# Expected: @includedir /etc/sudoers.d

# ============================================
# PART 9: LIST BOB'S PRIVILEGES
# ============================================
sudo -l -U bob
# Shows the WEB_SERVICES rule and any group-based rules

# ============================================
# PART 10: CLEAN UP
# ============================================
sudo rm /etc/sudoers.d/10-webadmins
sudo rm /etc/sudoers.d/20-deploy
sudo groupdel webadmins

The ten parts cover opening a drop-in file with visudo, defining an alias and a rule, verifying permissions, validating syntax, creating the group and adding a user, testing allowed and denied commands, adding a NOPASSWD rule, verifying the includedir directive, listing privileges, and cleanup. What the session demonstrates is that the drop-in directory and aliases make sudo policy modular and readable, and that visudo is the gatekeeper that prevents lockout.


Quick Reference

visudo Options

OptionPurpose
visudoEdit main /etc/sudoers
visudo -f fileEdit a drop-in file
visudo -cCheck syntax only
visudo -c -f fileCheck a specific file
visudo -qQuiet mode (suppress “parsed OK”)

Sudoers Grammar

ComponentMeaningExample
WHOUser, %group, #uid, aliasalice, %wheel
WHEREHost or ALLALL
AS_WHOMRun-as user/group(ALL:ALL), (root)
WHATCommand path or alias/bin/ls, SERVICES

Alias Types

AliasPurpose
User_AliasGroup users
Cmnd_AliasGroup commands
Host_AliasGroup hosts
Runas_AliasGroup target users

Drop-in File Rules

RequirementValue
Directory/etc/sudoers.d/
Ownershiproot:root
Permissions0440
FilenameNo dots, no trailing tilde
Included by@includedir /etc/sudoers.d

Best Practices

โœ… Do This:

sudo visudo -f /etc/sudoers.d/10-webadmins       # โœ… syntax-checked edit
sudo visudo -c -f /etc/sudoers.d/10-webadmins     # โœ… validate before relying
Cmnd_Alias SERVICES = /usr/bin/systemctl restart * # โœ… aliases for readability
chmod 0440 /etc/sudoers.d/rule                    # โœ… correct permissions

โŒ Don’t Do This:

nano /etc/sudoers                                 # โŒ no syntax check
chmod 0644 /etc/sudoers.d/rule                    # โŒ sudo ignores it
# file named webadmins.conf                       # โŒ dot causes ignore
# %webadmins ALL=(root) /usr/bin/systemctl       # โŒ wildcard without * is literal

Common Pitfalls

PitfallWhy It HappensFix
Drop-in silently ignoredWrong permissions (0644)chmod 0440
Drop-in ignoredFilename contains a dotRename without dot
Drop-in ignoredincludedir line missingAdd @includedir /etc/sudoers.d
Syntax error locks out sudoEdited without visudoUse single-user mode or pkexec
Command denied despite rulePath mismatchUse absolute path in rule
Alias not recognizedLowercase or contains invalid charUppercase, digits, underscores only

Real-World Examples

1. Edit main sudoers safely

sudo visudo

2. Create a drop-in file

sudo visudo -f /etc/sudoers.d/10-admins

3. Command alias for services

Cmnd_Alias SERVICES = /usr/bin/systemctl restart *, /usr/bin/systemctl status *

4. Group rule using alias

%ops ALL=(root) SERVICES

5. User alias

User_Alias ADMINS = alice, bob
ADMINS ALL=(ALL) ALL

6. NOPASSWD for a script

deploy ALL=(root) NOPASSWD: /opt/deploy/run.sh

7. Validate syntax

sudo visudo -c -f /etc/sudoers.d/10-admins

8. Check includedir

grep includedir /etc/sudoers

9. List user privileges

sudo -l -U username

10. Remove a drop-in rule

sudo rm /etc/sudoers.d/10-admins

Visual

visudo Safety Net

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  sudo visudo                                 โ”‚
โ”‚         โ”‚                                    โ”‚
โ”‚         โ–ผ                                    โ”‚
โ”‚  Lock file, open editor                      โ”‚
โ”‚         โ”‚                                    โ”‚
โ”‚         โ–ผ                                    โ”‚
โ”‚  User edits /etc/sudoers                     โ”‚
โ”‚         โ”‚                                    โ”‚
โ”‚         โ–ผ                                    โ”‚
โ”‚  Save                                        โ”‚
โ”‚         โ”‚                                    โ”‚
โ”‚         โ–ผ                                    โ”‚
โ”‚  Parse syntax                                โ”‚
โ”‚         โ”‚                                    โ”‚
โ”‚    โ”Œโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”                               โ”‚
โ”‚    โ”‚         โ”‚                               โ”‚
โ”‚  valid     invalid                           โ”‚
โ”‚    โ”‚         โ”‚                               โ”‚
โ”‚    โ–ผ         โ–ผ                               โ”‚
โ”‚  Write    Report error,                      โ”‚
โ”‚  file     offer re-edit                      โ”‚
โ”‚           or discard                         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Sudoers Grammar

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  %webadmins  ALL=(root)  /usr/bin/systemctl  โ”‚
โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€  โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚
โ”‚  WHO         WHERE AS_WHOM  WHAT             โ”‚
โ”‚                                              โ”‚
โ”‚  WHO:     %webadmins (group)                 โ”‚
โ”‚  WHERE:   ALL (any host)                     โ”‚
โ”‚  AS_WHOM: (root) (run as root)               โ”‚
โ”‚  WHAT:    /usr/bin/systemctl (exact path)    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Alias Expansion

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Cmnd_Alias SERVICES = /usr/bin/systemctl    โ”‚
โ”‚                        restart *, status *    โ”‚
โ”‚         โ”‚                                    โ”‚
โ”‚         โ–ผ                                    โ”‚
โ”‚  %ops ALL=(root) SERVICES                    โ”‚
โ”‚         โ”‚                                    โ”‚
โ”‚         โ–ผ                                    โ”‚
โ”‚  Equivalent to:                              โ”‚
โ”‚  %ops ALL=(root) /usr/bin/systemctl restart *โ”‚
โ”‚  %ops ALL=(root) /usr/bin/systemctl status * โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Drop-in Directory

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  /etc/sudoers                                โ”‚
โ”‚  @includedir /etc/sudoers.d                  โ”‚
โ”‚         โ”‚                                    โ”‚
โ”‚         โ–ผ                                    โ”‚
โ”‚  /etc/sudoers.d/                             โ”‚
โ”‚  โ”œโ”€โ”€ 10-admins        root:root 0440         โ”‚
โ”‚  โ”œโ”€โ”€ 20-webadmins     root:root 0440         โ”‚
โ”‚  โ””โ”€โ”€ 30-deploy        root:root 0440         โ”‚
โ”‚                                              โ”‚
โ”‚  Ignored: files with dots, wrong perms       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
Safe editorvisudo
Edit drop-invisudo -f /etc/sudoers.d/file
Syntax checkvisudo -c -f file
GrammarWHO WHERE=(AS_WHOM) WHAT
Full accessuser ALL=(ALL:ALL) ALL
Alias typesUser_Alias, Cmnd_Alias, Host_Alias, Runas_Alias
Drop-in dir/etc/sudoers.d/
Permissionsroot:root, 0440
Filename restrictionNo dots, no trailing tilde
Inclusion directive@includedir /etc/sudoers.d

Key takeaways:

  • visudo is not optional. It validates syntax before saving and prevents the lockout that a malformed sudoers file causes .
  • visudo -f edits drop-in files. It sets the correct permissions and performs the same syntax check .
  • The grammar is WHO WHERE=(AS_WHOM) WHAT. The AS_WHOM part is parenthesized and defaults to root if omitted .
  • Aliases reduce repetition. Cmnd_Alias groups commands, User_Alias groups users, and rules reference them by name .
  • Drop-in files must be 0440, root:root, and dot-free. A file with a dot in its name is silently ignored .
  • The includedir directive must be present. Without it, the drop-in directory is never read .
  • NOPASSWD: disables the prompt. Use it sparingly, and scope it to specific commands rather than ALL .

Remember: The sudoers configuration is powerful and fragile. visudo exists because the file’s grammar is unforgiving and the consequences of a mistake are total: no sudo access at all. Use visudo for every edit, visudo -c for validation, and the drop-in directory for all custom rules. Define aliases for readability, restrict commands to absolute paths, and set NOPASSWD only where automation requires it. For the LFCS exam, know how to create a drop-in file, define a Cmnd_Alias, and grant a group access to a specific set of commandsโ€”and know why visudo is the first and last tool you should reach for.


Was this helpful?


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!