4. 特权管理与sudo加固

在 Linux 主机安全中,root 权限是最核心的攻击目标。一旦攻击者获得 root,系统上几乎所有防护措施都可能被绕过。因此,特权管理的目标不是“让管理员更方便地用 root”,而是把 root 权限拆解、委派、记录和约束,让每一次高权限操作都有明确的身份、范围、命令和审计痕迹。本节围绕 sudo 的配置语法、最小权限委派、日志审计、su 与 sudo 的差异,以及禁用 root 直接登录展开。

一、su 与 sudo 的本质差异

su 的语义是“切换用户”。执行 su - 后输入 root 密码,当前会话就变成 root 的登录 shell,之后所有命令都以 root 身份运行,且不再区分具体执行了什么。它的关键问题是:要使用 root,必须知道 root 密码;一旦切换成功,权限边界就消失了,审计也只能看到“某人 su 成了 root”,无法精确到命令级别。

sudo 的语义是“以另一个用户身份执行一条命令”。它校验的是执行者自己的密码(也可配置为免密),然后根据 /etc/sudoers 中的规则判断该用户能否以目标身份运行指定命令。sudo 的权限粒度可以细到“某用户在某主机上以某身份运行某条命令”,并且每次调用都会记录日志。因此,现代 Linux 加固普遍推荐:日常管理走 sudo,root 密码尽量不扩散,root 直接登录关闭。

su 与 sudo 的权限路径与审计能力对比 su 路径:整会话提权 普通用户 alice root 密码 root 登录 shell 权限边界消失 审计粒度:仅记录“谁 su 成功” 风险:root 密码扩散、命令不可追溯 ✗ 不满足最小权限与命令级审计 sudo 路径:单命令委派 普通用户 alice 自身密码 sudoers 规则匹配 命令级授权 审计粒度:用户 + 命令 + 时间 + 结果 风险:规则过宽、NOPASSWD 滥用 ✓ 支持最小权限与命令级审计 sudo 执行时的规则匹配与日志落点 用户执行 sudo cmd 匹配 /etc/sudoers 及 sudoers.d/ 允许 / 拒绝 命令与身份判定 写入日志 auth.log / secure 日志关键字段:执行用户、目标用户、终端、工作目录、完整命令、时间戳、成功或失败 加固要点:规则最小化、命令写绝对路径、慎用通配符与 NOPASSWD、集中收集 sudo 日志 禁用 root 直接登录:PermitRootLogin no,切断 SSH 直连 root 的入口

二、sudoers 语法与安全配置

sudo 的规则集中在 /etc/sudoers,但生产环境不应直接编辑该文件,而应使用 visudo,它会在保存前做语法检查,避免写坏后所有人无法提权。更推荐的做法是在 /etc/sudoers.d/ 下按用途拆分文件,例如 10-admins、20-dba,便于审计和回收。

一条 sudoers 规则的基本形式是:

用户  主机=(目标用户:目标组)  命令列表

例如,允许运维组成员 alice 在任意主机上以 root 身份重启 nginx 和查看服务状态:

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

这里有几个安全细节必须注意。第一,命令要写绝对路径,否则可能被同名恶意程序劫持。第二,命令参数要尽量限定,例如只允许 systemctl restart nginx,而不是允许 /usr/bin/systemctl 全部子命令,否则用户可以通过 systemctl 的其他子命令间接获得更高权限。第三,慎用 ALL 和通配符 *,alice ALL=(ALL) ALL 等价于把 root 权限完整交出。第四,NOPASSWD 只应在自动化脚本等确有必要时使用,且必须配合命令白名单。

sudoers 中命令参数里的通配符非常危险。例如 /usr/bin/vi /var/log/* 看似只允许编辑日志,但 vi 可以执行 shell 命令,用户进入 vi 后输入 :!sh 即可获得 root shell。凡是允许交互式程序、编辑器、解释器、分页器的规则,都要按“可逃逸”对待。

三、最小权限委派

最小权限委派的核心是:按角色拆分命令集,而不是按人给权限。建议先定义角色,再把用户加入角色对应的 sudoers 文件。例如:

  • 运维角色:允许 systemctl restart/status 指定服务、journalctl 查看日志。
  • 数据库角色:允许 systemctl restart mysqld、以 mysql 用户执行备份脚本。
  • 审计角色:只允许读取 /var/log/ 下日志和 last、who 等命令。

委派时还要考虑“目标用户”维度。很多操作不需要 root,只需要以服务账号身份运行,例如 dba ALL=(mysql) /usr/local/bin/backup.sh,这样即使脚本被利用,影响范围也限制在 mysql 用户内。对于需要 root 的操作,优先使用 sudoedit 而不是 sudo vi,因为 sudoedit 会以调用者身份编辑临时副本,再以目标身份写回,避免编辑器逃逸。

四、sudo 日志审计

sudo 默认会把每次调用记录到系统日志,Debian/Ubuntu 通常在 /var/log/auth.log,RHEL/CentOS 在 /var/log/secure。典型记录包含执行用户、目标用户、终端、工作目录、完整命令和结果。例如:

Mar 12 10:22:41 web01 sudo: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/systemctl restart nginx

要提升审计能力,可以在 sudoers 中启用日志输入输出:

Defaults log_input, log_output
Defaults iolog_dir=/var/log/sudo-io
Defaults logfile=/var/log/sudo.log

这样不仅能记录命令,还能回放会话输入输出,适合对高风险操作做取证。审计时重点关注:非工作时间的 sudo 调用、USER=root 且命令为 shell 或编辑器的记录、失败尝试、以及 NOPASSWD 规则的异常使用。建议把 sudo 日志集中转发到日志服务器,防止本地日志被篡改。

五、禁用 root 直接登录

即使 sudo 配置得当,只要 SSH 允许 root 直接登录,攻击者仍可对 root 账户进行密码爆破。加固方式是编辑 /etc/ssh/sshd_config:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes

修改后先执行 sshd -t 检查语法,再 systemctl reload sshd 生效。注意:禁用 root 登录前,必须确认已有普通用户可通过密钥登录并能 sudo 提权,否则可能把自己锁在系统外。对于必须保留 root 远程能力的场景,可退而使用 PermitRootLogin prohibit-password,即只允许密钥、禁止密码。

推荐组合:普通用户 + SSH 密钥登录 + sudo 命令级委派 + sudo 日志集中收集 + PermitRootLogin no。这样既保留了可管理性,又把 root 权限从“一个密码”变成“一组可审计的授权规则”。

最后给出一个可参考的加固检查清单:确认 /etc/sudoers 无 ALL=(ALL) ALL 的普通用户;确认 /etc/sudoers.d/ 文件权限为 0440 且属主 root;确认无多余 NOPASSWD;确认 sudo 日志已开启并集中收集;确认 PermitRootLogin no 且已用普通用户验证过 sudo 提权。完成这些检查后,root 权限就从“共享密码”转变为“按需委派、全程留痕”的可控能力。