当前位置:首页>Linux>每天学一个Linux命令系列(进阶篇17):sudo/visudo - 给普通用户root权限,别直接给密码

每天学一个Linux命令系列(进阶篇17):sudo/visudo - 给普通用户root权限,别直接给密码

  • 2026-09-09 06:20:20
每天学一个Linux命令系列(进阶篇17):sudo/visudo - 给普通用户root权限,别直接给密码
运
运维少年 · 科技观察

为什么不能给所有人root密码

我刚工作那会儿,公司服务器的 root 密码写在一个共享文档里,每个人去查。直到有一天,有人误操作 rm -rf /usr/local/,半个系统瘫了。事后复盘发现:他只想执行一条需要 root 的命令,但习惯性 su - 切到了 root,然后打错了路径。

从那以后,公司规定:root 密码只有两个人知道。其他人用 sudo 执行特定命令,scope(范围)严格控制。

sudo 的核心思想

sudo(superuser do,超级用户执行)的精髓是 "最小权限原则"。你是一个普通用户,暂时需要 root 能力去完成某个任务。sudo 让你在执行特定命令时获得临时提升的权限,而不是把整个 root 身份交给你。

sudo 基础用法

# 以root身份执行命令
sudo apt update

# 以其他用户身份执行命令
sudo -u www-data whoami

# 以root身份打开shell
sudo -s

# 模拟root的登录shell(加载root的环境变量)
sudo -i

-u(user,指定用户)很实用。调试 Nginx 时我会用 sudo -u www-data touch /var/www/test.html,确保 web 用户对目录有写权限。不需要切到 www-data 账户去测试。

visudo:安全编辑sudoers文件

/etc/sudoers(sudo 的配置文件)语法非常严格。写错一行可能导致整个 sudo 系统失效,所有人(包括管理员)都无法提权。所以不要直接编辑,用 visudo(visual sudo,安全编辑sudo配置)。

# 安全编辑 sudoers 文件
sudo visudo

# 检查语法是否有误而不打开编辑器
sudo visudo -c

visudo 会在保存前做语法检查。语法不对就拒绝保存,这是保命设计。

推荐:在独立文件中配置

# 在 /etc/sudoers.d/ 下创建独立配置
sudo visudo -f /etc/sudoers.d/developers

用独立文件管理的好处:出错了删掉这个文件就行,不影响主 sudoers 文件。我在生产环境从来不改主文件,全部用小文件管理。

sudoers 语法详解

最简单的授权

# 用户 zhangsan 可以执行所有命令
zhangsan ALL=(ALL:ALL) ALL

格式解析(从左到右):

  • ·zhangsan:用户名或 %组名(%group)
  • ·第一个 ALL:适用于所有主机
  • ·(ALL:ALL):可以以任何用户和任何组的身份执行
  • ·最后一个 ALL:可以执行所有命令

授权执行特定命令

# zhangsan 只能用 apt 安装和更新软件
zhangsan ALL=(root) /usr/bin/apt update, /usr/bin/apt upgrade

# devops 组的成员只能管理 systemd 服务
%devops ALL=(root) /usr/bin/systemctl restart *, /usr/bin/systemctl status *, /usr/bin/systemctl start *, /usr/bin/systemctl stop *

这是 sudo 最有价值的地方。开发人员需要重启服务,给他重启服务的权限就好。不需要给他 root shell。

NOPASSWD:免密码执行

# zhangsan 执行这些命令不需要输入密码
zhangsan ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx

NOPASSWD(no password,免密码)要慎用。如果攻击者拿下了 zhangsan 的账户,可以直接重启 Nginx 服务。权衡是:频繁操作(如服务启停)可以加 NOPASSWD,高危操作(如改密码、装包)一定要密码。

限制命令参数

# 只能执行命令,不能传任意参数
zhangsan ALL=(root) /usr/sbin/useradd

# 精确到参数
zhangsan ALL=(root) /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root

感叹号 ! 是取反。上面这条权限让 zhangsan 可以改任何人的密码,除了 root。这个设计很精妙:给运维人员改普通用户密码的权限,但 root 密码只有管理员自己能改。

# 更严格的限制:只能重启特定的服务
zhangsan ALL=(root) /usr/bin/systemctl restart nginx, /usr/bin/systemctl restart php*-fpm

* 通配符在这里匹配版本号,php7.4-fpm 和 php8.1-fpm 都匹配。

命令别名

# 在 /etc/sudoers 中定义别名
Cmnd_Alias SERVICES = /usr/bin/systemctl restart *, /usr/bin/systemctl status *, /usr/bin/systemctl start *, /usr/bin/systemctl stop *

# 然后给组授权
%devops ALL=(root) SERVICES

Cmnd_Alias(command alias,命令别名)让配置更清晰。多条相关命令组合成一个有意义的别名。

用户别名和主机别名

# 用户别名
User_Alias DEVELOPERS = zhangsan, lisi, wangwu

# 主机别名(多服务器场景)
Host_Alias WEBSERVERS = web01, web02, web03

# 组合使用
DEVELOPERS WEBSERVERS=(root) /usr/bin/systemctl restart nginx

日志审计:谁用sudo干了什么

sudo 默认记录所有执行日志。排查谁干了什么坏事时,这就是铁证。

# 查看 sudo 日志
sudo journalctl -t sudo --since "1 day ago"

# 或者查看 /var/log/auth.log
sudo grep sudo /var/log/auth.log | tail -20

# 或者配置专门的 sudo 日志文件
# 在 /etc/sudoers 中设置:
Defaults logfile=/var/log/sudo.log

有一次排查事故,发现有人凌晨3点执行了 sudo rm -rf /tmp/*。查看 sudo 日志,锁定是某位同事的 session 过期后自动重播了旧命令。有了日志才能快速定位问题。

常见踩坑

1. 用户不在 sudo 组

# 把用户加入 sudo 组(Debian/Ubuntu)
sudo usermod -aG sudo zhangsan

# 把用户加入 wheel 组(CentOS/RHEL)
sudo usermod -aG wheel zhangsan

Ubuntu 和 CentOS 用的 sudo 组名不同,这是跨平台运维的常见陷阱。

2. 环境变量不继承

# sudo 默认会重置 PATH,你的自定义命令可能找不到
sudo echo $PATH
# 输出简化的安全PATH

# 保留环境变量
sudo -E env "PATH=$PATH" your_command

-E(preserve environment,保留环境变量)在你需要特定环境变量时很有用。但注意这可能有安全隐患。

3. 通配符安全风险

# 看似安全的通配符,其实攻击者可以传入 --help 之类的参数
zhangsan ALL=(root) /usr/bin/rm /var/log/*.log

# 更好的做法:用 sudo 包装脚本
zhangsan ALL=(root) /usr/local/sbin/cleanup-logs.sh

通配符看似优雅,但容易被绕过。安全做法是把需要执行的操作封装成 shell 脚本,然后只授权执行这个脚本。

安全提醒

sudo 不是日志审计的全部。 虽然 sudo 会记录执行记录,但如果攻击者用 sudo -i 拿到 root shell,后续操作都不会被 sudo 记录。要配合 auditd(linux审计系统)一起用。

别把 NOPASSWD 给 ALL 命令。 直接配置 zhangsan ALL=(ALL) NOPASSWD: ALL 等于把 root 密码告诉了他但写成了别名。他可以用 sudo su - 直接变成 root。

定期审计 sudoers 文件。 检查是否有离职人员的 sudo 权限没回收,是否有过于宽泛的授权。

# 列出所有用户可以执行的sudo命令
for user in $(cut -d: -f1 /etc/passwd); do echo "=== $user ===" && sudo -l -U $user 2>/dev/null; done

sudo 不是万能的。 CAP_SETUID(设置用户ID的能力)权限相关的问题,sudo 处理不了。复杂的权限场景考虑用 SELinux(安全增强式Linux)或 AppArmor。

sudo 的精髓是给用户刚刚好的权限,不多也不少。配置好的 sudo 规则能让开发人员和运维人员各司其职,不用共享 root 密码,出事也能追溯到人。

E N D

运维少年 · 科技观察

最新文章

随机文章