# Linux sudo 命令详解 - 提升权限与安全管理

URL: https://caijiao.org/linux/user-management/sudo
Source: docs/linux/user-management/sudo.md
Description: 全面介绍 Linux sudo 命令的使用方法、配置技巧和安全最佳实践，包括 sudoers 文件配置、权限委托和审计日志等内容。

## 1. sudo 命令概述

### 1.1 什么是 sudo

`sudo`（superuser do）是 Linux 系统中一个强大的命令，允许授权用户以其他用户（通常是超级用户 root）的身份执行命令。它提供了一种安全的方式来分配特权，而无需共享 root 密码。

### 1.2 sudo 的工作原理

1. 用户执行 `sudo` 命令并输入自己的密码进行认证
2. 系统检查 `/etc/sudoers` 文件，确认该用户是否有权限执行请求的命令
3. 如果授权有效，系统以目标用户（默认为 root）身份执行命令
4. 执行结果返回给原用户

### 1.3 sudo 的主要优势

- **权限委托**：可以精确控制哪些用户可以执行哪些特权命令
- **责任追溯**：所有 sudo 执行的命令都被记录在日志中
- **无需共享 root 密码**：用户使用自己的密码进行认证
- **会话时效性**：认证成功后有一定的缓存时间，不需要频繁输入密码
- **自定义权限**：可以针对不同用户或组设置不同的命令执行权限

## 2. sudo 命令基础

### 2.1 基本语法

```bash
sudo [选项] 命令
```

### 2.2 常用选项

- `-b, --background`：在后台运行命令
- `-E, --preserve-env`：保留当前用户的环境变量
- `-h, --help`：显示帮助信息
- `-i, --login`：以目标用户身份登录并运行 shell，加载该用户的环境变量
- `-k, --reset-timestamp`：立即失效认证时间戳，下次使用 sudo 时需要重新输入密码
- `-l, --list`：列出用户可以执行的 sudo 命令
- `-n, --non-interactive`：非交互式模式，不提示输入密码
- `-p, --prompt=PROMPT`：自定义密码提示
- `-s, --shell`：运行 shell 命令
- `-u, --user=USER`：以指定用户身份执行命令，而不是默认的 root
- `-v, --validate`：延长 sudo 会话时间，而不执行任何命令
- `-V, --version`：显示版本信息

### 2.3 基本用法示例

```bash
# 以 root 身份执行命令
sudo apt update

# 以特定用户身份执行命令
sudo -u john ls -la /home/john

# 以 root 身份登录 shell
sudo -i
# 或
sudo -s

# 查看用户可用的 sudo 权限
sudo -l

# 在后台运行命令
sudo -b systemctl restart nginx

# 保留环境变量执行命令
sudo -E env

# 延长 sudo 会话时间
sudo -v

# 立即重置 sudo 认证
sudo -k
```

## 3. sudoers 文件配置

### 3.1 sudoers 文件简介

`sudoers` 文件位于 `/etc/sudoers`，定义了哪些用户或组可以以哪些用户身份执行哪些命令。该文件的配置非常关键，错误的配置可能导致安全问题或系统无法正常运行。

### 3.2 安全编辑 sudoers 文件

**重要**：永远不要直接使用普通编辑器编辑 `/etc/sudoers` 文件，而应该使用 `visudo` 命令，它会在保存前检查语法错误，防止配置错误导致系统锁定。

```bash
# 编辑 sudoers 文件
visudo

# 检查 sudoers 文件语法
visudo -c

# 编辑特定的 sudoers 配置文件
visudo -f /etc/sudoers.d/custom
```

### 3.3 sudoers 文件基本结构

`sudoers` 文件的基本语法为：

```
授权用户 主机=([执行身份]:[是否需要密码]) [NOPASSWD:]命令
```

**字段说明**：
- `授权用户`：可以是用户名、组名（以 % 开头）或别名
- `主机`：指定在哪些主机上生效
- `执行身份`：可以以什么用户身份执行命令，默认为 root
- `是否需要密码`：是否需要输入密码确认，默认为需要
- `NOPASSWD:`：指定不需要密码验证
- `命令`：可以执行的命令，必须使用绝对路径

### 3.4 配置示例

```bash
# 允许用户 john 执行所有命令，需要输入密码
john ALL=(ALL:ALL) ALL

# 允许用户 mary 执行所有命令，不需要输入密码
mary ALL=(ALL:ALL) NOPASSWD:ALL

# 允许组 admins 执行所有命令
group admins ALL=(ALL) ALL

# 允许用户 john 仅执行特定命令
ejohn ALL=(ALL) /usr/bin/apt, /usr/bin/systemctl restart nginx

# 允许用户 tom 以用户 www-data 身份执行命令
tom ALL=(www-data) /usr/bin/php

# 允许用户 bob 执行命令时设置特定的环境变量
bob ALL=(ALL) SETENV: /usr/local/bin/backup.sh

# 禁止用户执行某些危险命令
denyuser ALL=!/usr/bin/passwd, !/usr/bin/su

# 允许用户使用通配符执行一组命令
alice ALL=(ALL) /usr/bin/systemctl * nginx
```

### 3.5 使用 sudoers.d 目录

为了更好地管理 sudo 权限，可以在 `/etc/sudoers.d/` 目录中创建单独的配置文件，而不是直接修改主 sudoers 文件。

```bash
# 创建自定义 sudo 配置文件
sudo visudo -f /etc/sudoers.d/webadmin
```

配置文件示例：
```
# 允许 webadmin 组管理 web 服务
%webadmin ALL=(ALL) /usr/bin/systemctl * apache2, /usr/bin/systemctl * nginx, /usr/bin/apachectl
```

**注意**：sudoers.d 目录中的文件命名通常不包含扩展名，并且权限应该设置为 440。

### 3.6 别名设置

在 sudoers 文件中，可以使用别名来简化配置：

```bash
# 定义用户别名
User_Alias ADMINS = john, mary

# 定义主机别名
Host_Alias SERVERS = server1, server2

# 定义命令别名
Cmnd_Alias WEB_COMMANDS = /usr/bin/systemctl * apache2, /usr/bin/apachectl
Cmnd_Alias NETWORK_COMMANDS = /usr/sbin/ifconfig, /usr/sbin/route

# 使用别名配置权限
ADMINS SERVERS=(ALL) WEB_COMMANDS, NETWORK_COMMANDS
```

### 3.7 高级配置选项

#### Defaults 指令

`sudoers` 文件中的 `Defaults` 指令用于设置全局配置选项：

```bash
# 设置密码超时时间为 30 分钟
Defaults timestamp_timeout=30

# 要求使用 TTY 终端（防止通过脚本执行 sudo）
Defaults requiretty

# 设置密码尝试次数
Defaults passwd_tries=3

# 自定义密码提示
Defaults passprompt="[sudo] 输入 %u 的密码: "

# 设置日志格式
Defaults logfile="/var/log/sudo.log"
Defaults loglinelen=0

# 忽略某些环境变量
Defaults env_delete+="MAIL PS1 PS2"

# 保留某些环境变量
Defaults env_keep+="PATH PYTHONPATH"
```

#### 权限继承

```bash
# 允许用户执行命令时保持权限（用于脚本中嵌套执行 sudo）
john ALL=(ALL) ALL, SETENV: ALL
```

## 4. sudo 日志和审计

### 4.1 sudo 日志记录

`sudo` 执行的命令默认记录在系统日志中：

- 在大多数 Linux 发行版中，sudo 日志通常记录在 `/var/log/auth.log`（Debian/Ubuntu）或 `/var/log/secure`（CentOS/RHEL）
- 可以在 sudoers 文件中使用 `Defaults logfile` 指定自定义日志文件

### 4.2 配置自定义日志

```bash
# 在 sudoers 文件中设置自定义日志
Defaults logfile="/var/log/sudo.log"
Defaults loglinelen=0
Defaults syslog=auth
```

### 4.3 审计 sudo 命令

可以使用 `ausearch` 和 `aureport` 工具（如果系统有 auditd 服务）来审计 sudo 执行情况：

```bash
# 查看 sudo 相关的审计日志
ausearch -c sudo

# 生成 sudo 活动报告
aureport -x -i | grep sudo
```

### 4.4 监控 sudo 使用情况

```bash
# 实时查看 sudo 日志
 sudo tail -f /var/log/auth.log | grep sudo

# 统计 sudo 使用次数
grep "sudo" /var/log/auth.log | wc -l

# 查看特定用户的 sudo 活动
grep "sudo.*john" /var/log/auth.log
```

## 5. sudo 安全最佳实践

### 5.1 最小权限原则

- 只授予用户完成工作所必需的最小权限
- 避免使用 `ALL=(ALL) ALL` 过于宽松的权限设置
- 尽可能限制用户可以执行的具体命令

### 5.2 密码策略

- 不要在 sudoers 文件中过度使用 `NOPASSWD` 选项
- 为不同用户组设置不同的密码策略
- 定期更改密码

### 5.3 日志监控

- 定期审查 sudo 日志，及时发现可疑活动
- 考虑使用集中日志管理系统收集和分析 sudo 日志
- 设置日志告警，对异常 sudo 使用行为进行通知

### 5.4 会话安全

```bash
# 减少密码缓存时间
Defaults timestamp_timeout=5

# 要求使用 TTY 终端
Defaults requiretty

# 限制环境变量
Defaults env_reset
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
```

### 5.5 使用 sudoers.d 进行权限管理

- 为不同的权限类别创建单独的配置文件
- 使用描述性文件名，便于管理和审计
- 设置正确的文件权限（chmod 440）

### 5.6 禁用 root 直接登录

通过配置 `sshd_config` 禁止 root 用户直接登录，强制使用 sudo 进行权限提升：

```bash
# 编辑 SSH 配置文件
sudo nano /etc/ssh/sshd_config

# 设置 PermitRootLogin 为 no
PermitRootLogin no
```

## 6. sudo 高级功能

### 6.1 命令别名和组权限

```bash
# 定义系统维护命令集
Cmnd_Alias SYS_MAINT = /usr/bin/apt update, /usr/bin/apt upgrade, /usr/bin/dpkg *, /sbin/reboot, /sbin/shutdown

# 定义网络管理命令集
Cmnd_Alias NETWORKING = /sbin/ifconfig, /usr/sbin/route, /usr/sbin/iptables, /usr/bin/netstat

# 定义存储管理命令集
Cmnd_Alias STORAGE = /sbin/fdisk, /sbin/sfdisk, /sbin/parted, /sbin/mkfs, /bin/mount, /bin/umount

# 分配权限给不同的组
%sysadmin ALL=(ALL) SYS_MAINT, NETWORKING, STORAGE
%netadmin ALL=(ALL) NETWORKING
%storageadmin ALL=(ALL) STORAGE
```

### 6.2 限制命令参数

```bash
# 限制用户只能使用特定参数重启服务
devops ALL=(ALL) /usr/bin/systemctl restart apache2, /usr/bin/systemctl restart nginx

# 允许用户执行特定参数的命令
dba ALL=(postgres) /usr/bin/psql -d production, /usr/bin/psql -d staging
```

### 6.3 使用通配符

```bash
# 允许用户管理特定目录中的所有文件
editor ALL=(ALL) /bin/chown *,/bin/chmod * /var/www/html/

# 允许用户重启特定服务
operator ALL=(ALL) /usr/bin/systemctl restart *.service
```

### 6.4 条件权限

```bash
# 限制用户只能从特定主机使用 sudo
john server1=(ALL) ALL

# 限制用户只能在特定时间使用 sudo
Defaults:mary timestamp_timeout=0, !tty_tickets
mary ALL=(ALL) TIME=9:00-17:00 ALL
```

## 7. sudo 故障排除

### 7.1 常见问题及解决方案

**问题 1：用户无法使用 sudo**
- 检查用户是否在 sudo 组中：`grep sudo /etc/group`
- 验证 sudoers 文件中的权限设置
- 检查文件权限：`ls -l /etc/sudoers`

**问题 2：visudo 报错**
- 使用 `visudo -c` 检查语法错误
- 检查 /etc/sudoers.d/ 目录中的文件是否有语法错误

**问题 3：sudo 提示 "Sorry, user X may not run sudo on Y"**
- 确认用户在 sudoers 文件中有正确的配置
- 检查主机名设置是否与 sudoers 配置匹配

**问题 4：sudo 会话异常**
- 使用 `sudo -k` 重置 sudo 认证
- 检查 timestamp_timeout 设置

### 7.2 恢复 sudo 访问权限

如果 sudo 配置错误导致无法使用 sudo，可以尝试以下方法恢复：

1. **使用 root 账户登录**：如果系统允许 root 直接登录
2. **通过单用户模式恢复**：重启系统进入单用户模式
3. **使用 live CD/USB**：启动系统并挂载根分区，修改 sudoers 文件

## 8. 替代工具

### 8.1 su 命令

`su` 命令用于切换用户身份，与 sudo 的区别在于：

- `su` 需要目标用户的密码，而 sudo 使用当前用户的密码
- `su` 默认切换到 root 并开启新的 shell，而 sudo 仅执行单个命令
- `su -` 加载目标用户的完整环境，相当于完全登录

```bash
# 切换到 root 用户
su -

# 切换到特定用户
su - john

# 以特定用户身份执行单个命令
su -c "command" john
```

### 8.2 doas

doas 是一个轻量级的 sudo 替代工具，主要在 OpenBSD 系统中使用，但也可用于 Linux：

```bash
# 安装 doas（以 Debian/Ubuntu 为例）
sudo apt install doas

# 基本用法
doas command
```

### 8.3 polkit

polkit（PolicyKit）是一个用于控制系统范围权限的框架，常用于图形界面应用程序获取特权：

```bash
# 使用 pkexec 以管理员权限执行程序
pkexec command
```

## 9. 总结

`sudo` 是 Linux 系统中一个非常强大的命令，它提供了精细的权限控制机制，使系统管理员能够安全地委托特权而无需共享 root 密码。通过正确配置 sudoers 文件，可以实现对系统访问的细粒度控制，同时通过日志记录实现对特权操作的完整审计。

本文详细介绍了 sudo 命令的基本用法、sudoers 文件的配置技巧、安全最佳实践、高级功能以及故障排除方法。掌握这些知识，可以帮助您建立一个更加安全和可控的 Linux 系统环境。

在使用 sudo 时，务必遵循最小权限原则，定期审查权限设置和日志记录，及时发现并处理潜在的安全问题。正确使用 sudo 是构建安全 Linux 系统的重要一环。
