第17章:sudo 权限管理
14 分钟阅读
第十七章:sudo 权限管理
想象一下这个场景:你是公司大楼的物业经理,但不是老板。你有一把"万能钥匙",能在紧急情况下打开任何门——但平时你只能用自己家的钥匙。
这就是sudo!普通用户用它临时"升级"成root,干完活又自动降级回普通用户。
这一章,我们来聊聊为什么不要直接用root、怎么用sudo、以及sudo的配置大法。
17.1 为什么要用 sudo?直接用 root 的危险
直接用root有多危险?这么说吧——root权限就像一把上了膛的枪,走火就是命。
root 的三大原罪
1. 杀伤力太大
root可以rm -rf /——没错,这就是著名的"删库跑路"命令。如果你用root敲了这个,眼睛一闭,服务器就成空壳了。
| |
2. 没有问责机制
root做的任何操作,系统都记录为"root干的"。如果团队里有多个人用root,你根本不知道是谁误删了文件。
| |
3. 远程入侵等于全盘沦陷
如果有人破解了你的root密码,你的整个系统就像大门敞开的金库——想拿什么拿什么。
sudo 的四大好处
| sudo的好处 | 解释 |
|---|---|
| 最小权限原则 | 只给需要的命令授权,不多不少 |
| 操作可追溯 | 每次sudo都有日志,记录谁在什么时候干了什么 |
| 防误操作 | sudo通常要求输入自己的密码,不是root密码 |
| 团队协作友好 | 不同用户有不同的sudo权限,互不干扰 |
📊 root vs sudo 对比图
graph LR
A[root用户] --> B["🔴 危险<br/>权限太大<br/>无法追溯<br/>一失足成千古恨"]
C[普通用户 + sudo] --> D["🟢 安全<br/>按需授权<br/>操作日志<br/>密码保护"]
style A fill:#ff6b6b
style C fill:#51cf66最佳实践:永远不要直接登录root。用普通用户登录,日常操作用sudo临时提权,需要root时sudo -i切换到root shell。
17.2 sudo 命令使用
sudo的基本语法超级简单:sudo + 你想执行的命令
17.2.1 sudo + 命令 —— 最基本用法
| |
输入密码后,sudo会在一段时间内(默认15分钟)记住你验证过身份,这段时间内再次使用sudo不需要重新输入密码。
17.2.2 sudo -i —— 切换到 root
如果你要连续执行多个root命令,用sudo 命令一个一个敲太麻烦了,可以切换到root shell:
| |
17.2.3 sudo -s —— 保持当前用户环境
| |
| |
最直观的区别:
sudo -i之后敲pwd会看到/root、echo $HOME也是/root;sudo -s之后HOME往往还是/home/你的名字。所以想让 root 的命令找不到你的个人配置文件(更"干净"、更接近真正登录 root),用-i;想保留当前环境(比如沿用你的proxy、PATH设置),用-s。 安全提醒:sudo -s保留环境变量有风险——如果PATH里混入了当前用户可写的目录,root 执行命令时可能被"劫持"(这就是经典的PATH提权)。要精确控制保留哪些变量,用/etc/sudoers里的Defaults env_keep += "..."。
17.2.4 sudo 常用选项
| |
| |
17.3 /etc/sudoers 文件:sudo 配置
sudo的配置都存在/etc/sudoers文件里。这个文件极其重要,配置错了可能导致:
- 所有人都不能用sudo(系统管理灾难)
- 所有人都变成root(安全灾难)
17.3.1 格式:用户 主机=(用户) 命令
sudoers的基本格式是:
| |
解释一下:
- 用户:哪个用户可以使用sudo
- 主机:在哪台主机上可以用(通常用
ALL表示所有主机) - 目标用户:以哪个用户身份运行命令(通常用
ALL表示任意用户) - 目标组:以哪个组身份运行命令(通常省略)
- 命令:可以运行哪些命令(通常用
ALL表示所有命令)
17.3.2 %组名:用户组
用%组名表示一个用户组的成员:
| |
wheel还是sudo? 两个名字都是"管理员组",只是发行版传统不同:RHEL/CentOS/Fedora 用%wheel,Debian/Ubuntu 用%sudo。所以看到教程里写usermod -aG wheel 用户却在自己的 Ubuntu 上没反应,就是因为它该用sudo组。想知道自己系统上默认是哪个:grep -E '^%(wheel|sudo)' /etc/sudoers。
17.3.3 ALL=(ALL) ALL:所有命令
最常见的配置:
| |
这个配置的意思是:
longx—— 用户longxALL=(ALL)—— 可以在任何主机上,以任何用户身份ALL—— 运行任何命令
17.3.4 NOPASSWD:无密码
有些场景下,你可能想让某些命令不需要输入密码:
| |
免密sudo非常危险! 除非你有充分的理由,否则不要使用NOPASSWD: ALL。
17.3.5 sudoers 配置示例
| |
17.3.6 Defaults:全局行为调整
除了"谁能干什么",sudoers 里还有一类以 Defaults 开头的行,用来调整 sudo 的全局行为。几个最常用的:
| |
timestamp_timeout是安全与便利的平衡点:默认 15 分钟内免密,意味着只要你的终端被别人接管 15 分钟内的 sudo 就无需再输密码(这也是很多人不理解"我明明锁屏了怎么还被提权"的原因)。对高安全环境建议调小或设为 0。secure_path是默认开启的,它保证sudo 命令走的是系统标准路径;但注意它并不保护你在 sudo 命令行里主动写的相对路径(比如sudo ./script.sh依然会执行当前目录的脚本,而当前目录可能被普通用户写过)。
17.4 visudo 安全的编辑 sudoers
绝对不要直接用文本编辑器打开/etc/sudoers! 如果你保存的时候语法错误了,下次谁都可能用不了sudo——包括你自己!
正确做法是用visudo命令。
17.4.1 语法检查
| |
visudo会在你保存前检查语法:
- 如果语法正确,正常保存退出
- 如果语法错误,会报错并让你重新编辑:
| |
17.4.2 锁定文件
visudo 编辑时会自动给 sudoers 文件加锁,防止两个人同时编辑造成文件损坏(第一个人退出前,第二个人会看到"This file is busy, still try to open?“之类的提示)。
下面这条命令则和"锁定"无关——它是用来检查所有 sudoers 文件的语法:
| |
-c是 check(检查),不是查看锁定状态。改完 sudoers 想确认有没有写错,或者怀疑队友改坏了,跑一条sudo visudo -c就能一眼看出哪个文件第几行有问题。第 17.4 节前面说的"visudo 保存前自动检查语法"和这个是同一套检查逻辑。
17.4.3 在 sudoers.d 目录下添加独立配置
/etc/sudoers.d/目录是存放额外sudo配置的地方。好处是:
- 不污染主sudoers文件
- 可以单独管理不同用户/组的配置
- 出问题了可以快速禁用(移动文件即可)
| |
/etc/sudoers.d/目录下的文件命名有讲究:
- 文件名里不能含
.(点号),也不能以~结尾——sudo 会跳过这类文件(这是为了避免误读编辑器/包管理器产生的备份文件,比如zhangsan~、zhangsan.rpmnew) - 文件权限必须是
0440(属主 root,属组 root),否则 sudo 会直接忽略并报错 - 目录下文件按文件名字典序依次读取,所以可以用
10-、20-这样的前缀控制顺序 - 想临时禁用某个配置文件,最省事的做法是改名(比如
mv zhangsan zhangsan.disabled,因为带了点号,sudo 会跳过它),而不是往里加注释
| |
17.5 sudo -l 查看当前用户权限
想知道当前用户能sudo哪些命令?用-l选项:
| |
| |
-u和-U别搞反:小写-u 用户是"以这个用户的身份去运行命令”;大写-U 用户是"去看看这个用户被授权了哪些命令"。写成sudo -l -u zhangsan会变成"以 zhangsan 的身份列出权限"(普通用户下多半报权限不足)。
| |
17.6 sudo 日志:/var/log/auth.log
sudo的每次使用都会被记录下来。日志文件通常是:
- Debian/Ubuntu:
/var/log/auth.log - RHEL/CentOS/Fedora:
/var/log/secure - Arch Linux:
/var/log/auth.log或journalctl
查看sudo操作记录
| |
每条日志都记录了:
- 用户:谁执行的sudo
- 时间:什么时候
- TTY:从哪个终端
- PWD:执行时在哪个目录
- USER:以哪个用户身份运行
- COMMAND:执行了什么命令
journalctl 查看sudo日志(systemd系统)
| |
为什么
-u sudo是错的:-u过滤的是 systemd 服务单元(unit),而 sudo 只是普通命令,运行时并不存在sudo.service,所以journalctl -u sudo永远返回空。按"日志标签"过滤要用-t,按"产生的进程名"过滤用_COMM=。 另外在 logind/sudo 较新的版本里,Debian/Ubuntu 的 sudo 日志也可能已经进入 journal 而不再写/var/log/auth.log,所以两种查法都试一下。
📊 sudo日志分析示例
graph LR
A["sudo日志记录的内容"] --> B["谁?<br/>longx"]
A --> C["什么时候?<br/>Mar 23 12:00"]
A --> D["从哪登录?<br/>pts/0"]
A --> E["用什么身份?<br/>root"]
A --> F["干了什么?<br/>cat /var/log/auth.log"]
style A fill:#dfe6e9
style B fill:#ffeaa7
style C fill:#ffeaa7
style D fill:#ffeaa7
style E fill:#ff6b6b
style F fill:#51cf6617.7 sudo 实战配置案例
案例1:创建一个"不能删库跑路"的管理员
| |
⚠️ sudoers 的命令匹配是"按整行精确匹配"的:写
/usr/bin/systemctl restart意味着"只允许恰好执行这一条、且不带任何参数的命令",实际上根本没法用(真实命令总是带服务名)。所以要配合 通配符:/usr/bin/systemctl restart *。 但通配符也要小心——systemctl参数里的*覆盖面很广,而且systemctl能做的事远不止重启服务(它还能改单元文件、跑任意命令),放行systemctl几乎等价于放行 root。给运维人员开权限时,宁可放行具体的服务脚本(比如封装好的/usr/local/bin/restart-nginx.sh),也不要直接放行整个systemctl。
案例2:限制Web开发人员只能操作nginx
| |
为什么把
(www-data)改成了(root):systemctl是通过 D-Bus/Polkit 去指挥 PID 1 的,普通身份跑不起来。用(www-data)运行systemctl restart nginx通常会报Interactive authentication required或Access denied。要让systemctl真正生效,必须是以 root 身份执行。 这也带来一个现实问题:一旦放行systemctl restart nginx,就等于给了对方"以 root 身份执行 systemctl"的能力。更安全的替代方案是写一个只能干这一件事的脚本(里面硬编码好要重启的服务),然后只放行这个脚本。
案例3:sudo免密码的合理使用场景
| |
📊 sudo配置格式速查表
graph LR
S["一条 sudoers 规则"] --> U["谁:用户 / %组名"]
S --> H["在哪台机器:主机"]
S --> T["以谁的身份:(目标用户 : 目标组)"]
S --> C["能干什么:命令列表"]
S --> O["附加选项:NOPASSWD: / SETENV: / PASSWD:"]
style S fill:#ffeaa7
style O fill:#dfe6e9| 组成部分 | 含义 | 示例 |
|---|---|---|
| 用户 | 被授权的用户(或%组名表示组) | longx 或 %sudo |
| 主机 | 允许使用的主机 | ALL、192.168.1.100 |
| = 目标用户 | 以哪个用户身份运行 | (ALL)、(root)、(www-data) |
| :目标组 | 以哪个组身份运行 | :wheel(可选) |
| 命令 | 允许执行的命令 | ALL、/usr/bin/apt |
本章小结
本章我们学习了sudo权限管理:
🔑 核心知识点
为什么不用root:
- 杀伤力太大,误操作可能毁掉整个系统
- 没有操作追溯,出问题找不到责任人
- 远程入侵直接全盘沦陷
sudo基本用法:
sudo 命令:以root运行命令sudo -i:切换到root shellsudo -s:保持当前用户环境的root shellsudo -u 用户:以指定用户身份运行
sudoers配置格式:
- 基本格式:
用户 主机=(目标用户:目标组) 命令 %组名表示用户组ALL表示所有NOPASSWD表示免密(危险!慎用)
- 基本格式:
安全编辑sudoers:
- 必须用
visudo,不能用普通编辑器 - 改完用
sudo visudo -c检查语法 - 配置放在
/etc/sudoers.d/下更安全 - 命令匹配是"整行精确匹配",要放参数就得用
*;别轻易放行systemctl、apt这类"万能命令"
- 必须用
日志查看:
- Debian/Ubuntu:
/var/log/auth.log - RHEL/CentOS:
/var/log/secure - journalctl 用
-t sudo过滤(-u sudo是查不到的)
- Debian/Ubuntu:
常用 Defaults:
timestamp_timeout=N:N 分钟内免密(默认 15 分钟)log_output:记录 sudo 执行的命令输出,便于审计secure_path:强制使用系统标准 PATH
💡 记住这个原则
永远不要直接登录root。 用普通用户做事,需要权限时
sudo一下,这不仅是最佳实践,更是一种"操作系统礼仪"。