The sudo (superuser do) command is one of the most critical security components in Linux systems, allowing authorized users to execute commands with elevated privileges. Proper sudo configuration is essential for maintaining system security while providing necessary administrative access. This comprehensive guide covers everything you need to know about configuring sudo access and managing privilege escalation in AlmaLinux.
Understanding sudo and Privilege Escalation
What is sudo?
sudo allows authorized users to run commands as another user (typically root) based on policies defined in the sudoers file. Unlike logging in as root directly, sudo provides:
- Accountability: All commands are logged with the user who executed them
- Granular Control: Specific commands can be allowed or denied
- Temporary Elevation: Privileges are elevated only for specific commands
- Password Verification: User’s own password is used (not root password)
How sudo Works
When a user runs a sudo command:
- sudo checks the
/etc/sudoers
file for permissions - Prompts for the user’s password (if required)
- Verifies the user has permission for the specific command
- Executes the command with elevated privileges
- Logs the action to the system log
Default sudo Behavior
# Check sudo version
sudo -V
# List current user's sudo privileges
sudo -l
# Run command as root
sudo command
# Run command as specific user
sudo -u username command
# Run shell as root
sudo -i
sudo -s
# Edit file with sudo
sudo -e /etc/hosts
sudoedit /etc/hosts
sudo Configuration Files
Primary Configuration Files
/etc/sudoers
: Main configuration file/etc/sudoers.d/
: Directory for additional configuration files/etc/sudo.conf
: sudo front-end configuration
Editing sudoers Safely
Always use visudo
to edit sudoers files:
# Edit main sudoers file
sudo visudo
# Edit specific file in sudoers.d
sudo visudo -f /etc/sudoers.d/custom
# Check sudoers syntax
sudo visudo -c
# Use specific editor
sudo EDITOR=nano visudo
sudoers File Structure
# /etc/sudoers basic structure
# User privilege specification
root ALL=(ALL:ALL) ALL
# Group privilege specification
%wheel ALL=(ALL:ALL) ALL
# User alias specification
User_Alias ADMINS = john, jane, bob
# Command alias specification
Cmnd_Alias SHUTDOWN = /sbin/shutdown, /sbin/reboot
# Host alias specification
Host_Alias SERVERS = server1, server2, 192.168.1.0/24
Basic sudo Configuration
Granting Basic sudo Access
# Method 1: Add user to wheel group
sudo usermod -aG wheel username
# Method 2: Create user-specific rule
sudo visudo
# Add line:
username ALL=(ALL) ALL
# Method 3: Create file in sudoers.d
echo "username ALL=(ALL) ALL" | sudo tee /etc/sudoers.d/username
sudo chmod 440 /etc/sudoers.d/username
Password Configuration
# In sudoers file:
# Require password (default)
username ALL=(ALL) ALL
# No password required
username ALL=(ALL) NOPASSWD: ALL
# No password for specific commands
username ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart httpd
# Password timeout (in minutes)
Defaults timestamp_timeout=30
# Always require password
Defaults timestamp_timeout=0
# Require password for each command
Defaults timestamp_type=global
Basic Restrictions
# Allow specific commands only
username ALL=(ALL) /usr/bin/systemctl, /usr/bin/journalctl
# Deny specific commands
username ALL=(ALL) ALL, !/usr/bin/su, !/usr/bin/passwd root
# Allow command with specific arguments
username ALL=(ALL) /usr/bin/systemctl restart httpd
username ALL=(ALL) /usr/bin/systemctl reload httpd
# Prevent shell escapes
username ALL=(ALL) NOEXEC: /usr/bin/vi
Advanced sudoers Syntax
User and Host Specifications
# Syntax: user host=(runas_user:runas_group) commands
# Allow on specific host only
john server1=(ALL) ALL
# Allow from specific network
john 192.168.1.0/24=(ALL) ALL
# Run as specific user
john ALL=(apache) /usr/bin/apachectl
# Run as specific user and group
john ALL=(apache:apache) /var/www/scripts/*
Using Aliases
# User aliases
User_Alias ADMINS = john, jane, %sysadmin
User_Alias DEVELOPERS = alice, bob, charlie
User_Alias OPERATORS = dave, eve
# Command aliases
Cmnd_Alias SHUTDOWN_CMDS = /sbin/shutdown, /sbin/reboot, /sbin/halt
Cmnd_Alias NETWORK_CMDS = /sbin/ifconfig, /sbin/ip, /usr/bin/netstat
Cmnd_Alias SERVICE_CMDS = /usr/bin/systemctl start *, \
/usr/bin/systemctl stop *, \
/usr/bin/systemctl restart *
# Host aliases
Host_Alias WEBSERVERS = web1, web2, web3
Host_Alias DBSERVERS = db1, db2
Host_Alias DMZ = 10.0.1.0/24
# Using aliases in rules
ADMINS ALL=(ALL) ALL
DEVELOPERS WEBSERVERS=(apache) SERVICE_CMDS
OPERATORS ALL=(ALL) SHUTDOWN_CMDS, NETWORK_CMDS
Complex Rules
# Multiple commands with different runas
john ALL=(root) /usr/bin/yum, (apache) /usr/bin/apachectl
# Wildcards and patterns
john ALL=(ALL) /bin/cat /var/log/messages*
john ALL=(ALL) /usr/bin/systemctl * httpd
# Negation
john ALL=(ALL) ALL, !/usr/bin/passwd root, !/usr/bin/su -
# Combining conditions
ADMINS WEBSERVERS=(ALL) NOPASSWD: SERVICE_CMDS, \
PASSWD: SHUTDOWN_CMDS
User and Group Management
Group-Based Access
# Grant sudo to wheel group members
%wheel ALL=(ALL) ALL
# Custom group with limited access
%webadmin ALL=(ALL) /usr/bin/systemctl * httpd, \
/usr/bin/systemctl * nginx
# Nested groups
%sysadmin ALL=(ALL) ALL
%junior_admin ALL=(ALL) /usr/bin/systemctl, /usr/bin/journalctl
# AD/LDAP groups (with space)
%"domain admins" ALL=(ALL) ALL
Per-User Configuration
# Create individual user files
sudo touch /etc/sudoers.d/john
sudo chmod 440 /etc/sudoers.d/john
sudo visudo -f /etc/sudoers.d/john
# Content example:
# User-specific sudo rules for john
john ALL=(ALL) NOPASSWD: /usr/bin/docker *
john ALL=(ALL) PASSWD: /usr/bin/systemctl
Defaults for Users and Groups
# Set defaults for specific users
Defaults:john !lecture, timestamp_timeout=60
# Set defaults for groups
Defaults:%developers env_keep += "JAVA_HOME MAVEN_HOME"
# Different defaults per host
Defaults@WEBSERVERS log_input, log_output
Command Aliases and Restrictions
Creating Useful Command Aliases
# Package management
Cmnd_Alias PACKAGE_MGMT = /usr/bin/yum install *, \
/usr/bin/yum update *, \
/usr/bin/yum remove *, \
/usr/bin/rpm -*, \
/usr/bin/dnf *
# Container management
Cmnd_Alias DOCKER = /usr/bin/docker *, \
/usr/bin/docker-compose *, \
!/usr/bin/docker exec * /bin/bash, \
!/usr/bin/docker exec * /bin/sh
# Database administration
Cmnd_Alias DB_ADMIN = /usr/bin/mysql, \
/usr/bin/mysqldump, \
/usr/bin/psql, \
/usr/bin/pg_dump
# Monitoring commands
Cmnd_Alias MONITORING = /usr/bin/top, \
/usr/bin/htop, \
/usr/bin/iotop, \
/usr/bin/nethogs, \
/usr/bin/ss, \
/usr/bin/netstat
Restricting Dangerous Commands
# Prevent privilege escalation
Cmnd_Alias DANGEROUS = /usr/bin/su -, \
/usr/bin/su root, \
/usr/bin/passwd root, \
/usr/bin/visudo, \
/usr/bin/vim /etc/sudoers, \
/usr/bin/nano /etc/sudoers
# Allow all except dangerous
developers ALL=(ALL) ALL, !DANGEROUS
# Restrict shell access
Cmnd_Alias SHELLS = /bin/bash, /bin/sh, /bin/zsh, \
/usr/bin/fish, /usr/bin/csh
operators ALL=(ALL) ALL, !SHELLS
Safe Editor Configuration
# Prevent shell escapes from editors
Cmnd_Alias EDITORS = /usr/bin/vim, /usr/bin/vi, \
/usr/bin/nano, /usr/bin/emacs
# Use NOEXEC to prevent shell escapes
developers ALL=(ALL) NOEXEC: EDITORS
# Safe editing with sudoedit
developers ALL=(ALL) sudoedit /etc/httpd/conf/httpd.conf, \
sudoedit /etc/nginx/nginx.conf
Environment Variables and Security
Managing Environment Variables
# Default environment behavior
Defaults env_reset
Defaults env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE LS_COLORS"
Defaults env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_*"
Defaults env_keep += "XAUTHORITY"
# Secure path
Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin
# Keep specific variables for users
Defaults:developers env_keep += "JAVA_HOME PATH PYTHONPATH"
# Remove dangerous variables
Defaults env_delete += "LD_PRELOAD LD_LIBRARY_PATH"
# Check environment
Defaults env_check += "TERM TZ"
Security Options
# Require TTY
Defaults requiretty
# Disable for specific users (for automation)
Defaults:automation !requiretty
# Use pty
Defaults use_pty
# Lecture users
Defaults lecture = always
Defaults lecture_file = /etc/sudo_lecture.txt
# Insults for wrong password
Defaults insults
# Mail on sudo usage
Defaults mail_always
Defaults mailto = "[email protected]"
Time-Based Access Control
Implementing Time Restrictions
# Basic time restrictions (requires sudo compiled with timeout support)
john ALL=(ALL) TIMEOUT=8:00-17:00 ALL
# Using external script for time checking
#!/bin/bash
# /usr/local/bin/check_time.sh
HOUR=$(date +%H)
if [ $HOUR -ge 8 ] && [ $HOUR -lt 17 ]; then
exit 0
else
exit 1
fi
# In sudoers:
john ALL=(ALL) /usr/local/bin/check_time.sh && /usr/bin/command
Temporary Access
# Create temporary sudo access
#!/bin/bash
# /usr/local/sbin/grant_temp_sudo.sh
USER=$1
HOURS=$2
EXPIRE=$(date -d "+${HOURS} hours" +%s)
cat > /etc/sudoers.d/temp_$USER << EOF
# Temporary sudo access until $(date -d @$EXPIRE)
# This file will be auto-removed
$USER ALL=(ALL) ALL
EOF
# Schedule removal
echo "rm -f /etc/sudoers.d/temp_$USER" | at now + $HOURS hours
Logging and Auditing
Configure sudo Logging
# Enable logging in sudoers
Defaults logfile = /var/log/sudo.log
Defaults log_input
Defaults log_output
Defaults iolog_dir = /var/log/sudo-io
# Syslog configuration
Defaults syslog = authpriv
Defaults syslog_goodpri = notice
Defaults syslog_badpri = alert
# Per-command logging
john ALL=(ALL) LOG_INPUT: LOG_OUTPUT: /usr/bin/mysql
Setting Up Comprehensive Logging
# Create sudo log directory
sudo mkdir -p /var/log/sudo-io
sudo chmod 700 /var/log/sudo-io
# Configure rsyslog for sudo
echo "authpriv.* /var/log/sudo.log" | sudo tee -a /etc/rsyslog.d/sudo.conf
sudo systemctl restart rsyslog
# Logrotate configuration
cat << EOF | sudo tee /etc/logrotate.d/sudo
/var/log/sudo.log {
weekly
rotate 52
compress
delaycompress
missingok
notifempty
create 0640 root root
}
EOF
Monitoring sudo Usage
# View sudo logs
sudo grep sudo /var/log/secure
sudo journalctl -u sudo
# Parse sudo log
sudo cat /var/log/sudo.log | grep -E "COMMAND|USER"
# Real-time monitoring
sudo tail -f /var/log/secure | grep sudo
# Audit sudo usage report
#!/bin/bash
echo "=== Sudo Usage Report ==="
echo "Date: $(date)"
echo -e "\n--- Commands by User ---"
sudo grep "COMMAND" /var/log/sudo.log | awk '{print $6}' | sort | uniq -c | sort -rn
echo -e "\n--- Failed sudo Attempts ---"
sudo grep "incorrect password" /var/log/secure | tail -20
Security Best Practices
1. Principle of Least Privilege
# Bad: Too permissive
developer ALL=(ALL) NOPASSWD: ALL
# Good: Specific permissions
developer ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart httpd, \
/usr/bin/systemctl reload httpd, \
/usr/bin/tail -f /var/log/httpd/*
2. Use Aliases for Clarity
# Define clear aliases
User_Alias DBA = oracle, postgres
Cmnd_Alias DB_BACKUP = /usr/local/bin/backup_db.sh
Cmnd_Alias DB_RESTORE = /usr/local/bin/restore_db.sh
# Use aliases in rules
DBA ALL=(ALL) NOPASSWD: DB_BACKUP, PASSWD: DB_RESTORE
3. Secure Default Configuration
# Secure defaults
Defaults requiretty
Defaults !visiblepw
Defaults always_set_home
Defaults match_group_by_gid
Defaults use_pty
Defaults env_reset
Defaults secure_path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Defaults timestamp_timeout = 15
Defaults passwd_tries = 3
Defaults loglinelen = 0
Defaults insults
4. Regular Auditing
#!/bin/bash
# /usr/local/sbin/audit_sudo.sh
# Audit sudo configuration
echo "=== Sudo Security Audit ==="
echo "Date: $(date)"
echo -e "\n--- Users with full sudo access ---"
sudo grep -E "ALL=(ALL).*ALL" /etc/sudoers /etc/sudoers.d/* 2>/dev/null | grep -v "^#"
echo -e "\n--- NOPASSWD rules ---"
sudo grep -i "NOPASSWD" /etc/sudoers /etc/sudoers.d/* 2>/dev/null | grep -v "^#"
echo -e "\n--- sudoers.d files ---"
ls -la /etc/sudoers.d/
echo -e "\n--- Last sudo usage ---"
sudo journalctl -u sudo -n 20 --no-pager
5. Implement sudo Policies
# Create organization-wide policy
cat << EOF | sudo tee /etc/sudoers.d/00-policy
# Organization Sudo Policy
# Last updated: $(date)
# Global defaults
Defaults requiretty
Defaults !visiblepw
Defaults timestamp_timeout=15
Defaults passwd_tries=3
Defaults lecture=always
Defaults log_input
Defaults log_output
Defaults logfile=/var/log/sudo.log
# Banned commands
Cmnd_Alias FORBIDDEN = /usr/bin/su -, \
/usr/bin/su root, \
/usr/bin/passwd root, \
/usr/bin/visudo, \
/bin/bash -c *, \
/bin/sh -c *
# No one should run these
ALL ALL=(ALL) !FORBIDDEN
EOF
Troubleshooting sudo Issues
Common Problems and Solutions
1. User Not in sudoers File
# Error: user is not in the sudoers file
# Solution 1: Add to wheel group
sudo usermod -aG wheel username
# Solution 2: Add specific entry
echo "username ALL=(ALL) ALL" | sudo tee /etc/sudoers.d/username
sudo chmod 440 /etc/sudoers.d/username
2. Syntax Errors
# Check syntax before saving
sudo visudo -c
# If locked out, boot in single user mode
# Add to kernel parameters: init=/bin/bash
# Then:
mount -o remount,rw /
visudo
# Fix the error
reboot
3. TTY Required
# Error: sorry, you must have a tty to run sudo
# Fix for specific user
echo "Defaults:username !requiretty" | sudo tee -a /etc/sudoers.d/username
# Fix for automation
echo "Defaults:automation !requiretty" | sudo tee -a /etc/sudoers.d/automation
Debugging sudo
# Enable debug mode
echo "Debug sudo /var/log/sudo_debug all@debug" | sudo tee /etc/sudo.conf
# Test sudo rules
sudo -l -U username
# Validate specific command
sudo -l -U username /usr/bin/command
# Check effective permissions
sudo -k # Clear cached credentials
sudo -v # Validate and cache credentials
Recovery Procedures
# If locked out of sudo:
# Method 1: Use root account (if enabled)
su -
visudo
# Method 2: Boot from live media
# Mount the system partition
mount /dev/sda1 /mnt
chroot /mnt
visudo
# Method 3: Single user mode
# Edit grub, add: systemd.unit=rescue.target
# or: init=/bin/bash
Alternative Privilege Escalation Methods
Using su Command
# Switch to root (requires root password)
su -
# Switch to specific user
su - username
# Run single command
su -c "command" - username
Polkit (PolicyKit)
# Check polkit policies
pkaction
# Create custom polkit rule
cat << EOF | sudo tee /etc/polkit-1/rules.d/50-custom.rules
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
subject.isInGroup("wheel")) {
return polkit.Result.YES;
}
});
EOF
Using setuid Programs
# Create setuid wrapper (use with caution)
cat << EOF > /tmp/wrapper.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
setuid(0);
system("/usr/local/bin/specific_command");
return 0;
}
EOF
gcc -o /usr/local/bin/wrapper /tmp/wrapper.c
sudo chown root:root /usr/local/bin/wrapper
sudo chmod 4755 /usr/local/bin/wrapper
Capabilities
# Grant specific capability instead of full sudo
sudo setcap cap_net_bind_service=+ep /usr/bin/python3
# View capabilities
getcap /usr/bin/python3
# Remove capabilities
sudo setcap -r /usr/bin/python3
Advanced sudo Features
Using sudo with Scripts
#!/bin/bash
# Script that requires selective sudo
# Check if running with sudo for specific parts
if [[ $EUID -ne 0 ]]; then
echo "This script must be run with sudo"
exit 1
fi
# Drop privileges for non-critical parts
sudo -u $SUDO_USER command_as_original_user
# Elevate again for critical parts
critical_admin_command
sudo in Automation
# Ansible playbook example
- name: Configure sudo for automation
lineinfile:
path: /etc/sudoers.d/ansible
line: "ansible ALL=(ALL) NOPASSWD: ALL"
create: yes
mode: '0440'
validate: '/usr/sbin/visudo -cf %s'
# Puppet example
sudo::conf { 'puppet':
ensure => present,
content => 'puppet ALL=(ALL) NOPASSWD: ALL',
}
Integration with LDAP/AD
# Configure sudo LDAP
cat << EOF | sudo tee -a /etc/sudo-ldap.conf
uri ldap://ldap.example.com
sudoers_base ou=SUDOers,dc=example,dc=com
binddn cn=sudo,dc=example,dc=com
bindpw secret
ssl start_tls
tls_checkpeer yes
tls_cacertfile /etc/ssl/certs/ca-cert.pem
EOF
# NSS configuration
echo "sudoers: files ldap" | sudo tee -a /etc/nsswitch.conf
Conclusion
Proper sudo configuration is essential for maintaining security while providing necessary administrative access. Key takeaways:
- Always use visudo to edit sudoers files
- Follow the principle of least privilege
- Use aliases for clarity and maintainability
- Enable comprehensive logging and auditing
- Regular review and update sudo policies
- Test configurations thoroughly before deployment
- Document your sudo policies and procedures
Remember that sudo is a powerful tool that, when properly configured, provides a secure and auditable way to manage administrative access. Regular reviews and updates of sudo policies ensure they continue to meet security requirements while supporting operational needs.