sudo 与 su 操作手册
目录
- sudoers 配置
- sudo 常用操作
- sudo 安全机制
- sudo 高级用法
- 安全规范
- 故障排查
- 同类工具对比
- su、sudo 环境与 PATH 行为
1 sudoers 配置
sudo 的权限控制依托 /etc/sudoers,文件默认权限 440。
不直接使用 vi、vim 编辑,语法错误会造成 sudo 不可用;编辑统一使用 visudo,该工具内置语法校验。
bash
# 普通用户执行,需要已有 sudo 权限
sudo visudo
# root 直接执行
visudo
编辑完成,vi 模式下按 Esc,输入 :wq 保存退出。
存在语法错误时终端输出 syntax error,需要修正后重新保存。
1.1 sudoers 文件结构
文件分为 Defaults、用户权限、组权限三段。通用规则格式:
用户/组 主机 =(身份) 可执行命令
#为注释标记。
sudoers
# Defaults 段:全局行为控制
Defaults env_reset
Defaults mail_badpass
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Defaults timestamp_timeout=15
Defaults env_keep += "SSH_AUTH_SOCK"
# 用户权限规则
root ALL=(ALL:ALL) ALL
# 组权限规则,组名前缀 %
%wheel ALL=(ALL:ALL) ALL
%sudo ALL=(ALL:ALL) ALL
字段释义:
- 主机:规则生效主机范围
(ALL:ALL):可切换用户:可切换组ALL:代表全部命令
1.2 配置场景
1.2.1 授予完整 sudo 权限
方式一:加入系统授权组
bash
# Ubuntu
usermod -aG sudo test
# CentOS / RHEL
usermod -aG wheel test
方式二:直接写入 sudoers
sudoers
test ALL=(ALL:ALL) ALL
1.2.2 限定可执行命令
命令必须填写绝对路径,可携带参数实现精确匹配。
sudoers
test ALL=(ALL:ALL) /usr/bin/systemctl restart nginx, /sbin/ifconfig eth0, /sbin/ifup eth0
仅允许指定命令免密执行:
sudoers
deploy ALL=(ALL:ALL) NOPASSWD: /usr/bin/systemctl restart nginx
1.2.3 免密码授权
sudoers
# 全部命令免密
test ALL=(ALL:ALL) NOPASSWD: ALL
# 指定命令免密
test ALL=(ALL:ALL) NOPASSWD: /usr/sbin/reboot, /usr/bin/systemctl restart nginx
1.2.4 限定切换目标用户
sudoers
test ALL=(nginx:ALL) ALL
该配置下用户仅可切换至 nginx,无法切换至 root。
1.2.5 黑名单管控
! 标记禁止项;黑名单条目置于白名单之后,规则从上至下顺序匹配。
sudoers
%sudo ALL=(ALL:ALL) ALL, !/usr/bin/rm -rf *
test ALL=(ALL:ALL) ALL, !/usr/sbin/visudo
1.2.6 别名定义
别名名称使用大写,分为 User_Alias、Cmnd_Alias、Host_Alias。
sudoers
User_Alias OPS = user1, user2, user3
Cmnd_Alias PACKAGES = /usr/bin/apt, /usr/bin/yum, /usr/bin/dnf
Cmnd_Alias SERVICES = /usr/bin/systemctl, /usr/sbin/service
OPS ALL=(ALL:ALL) PACKAGES, SERVICES
1.3 主机字段匹配规则
主机字段在本机完成匹配,匹配对象为主机名、FQDN、IP。支持以下类型:
-
短主机名 / FQDN
sudoerstest web01=(ALL:ALL) NOPASSWD: /usr/bin/systemctl restart nginx -
单个 IP
sudoerstest 192.168.1.10=(ALL:ALL) NOPASSWD: /usr/bin/systemctl restart nginx -
CIDR 网段
sudoerstest 192.168.1.0/24=(ALL:ALL) NOPASSWD: /usr/bin/systemctl restart nginx -
Host_Alias
sudoersHost_Alias WEBS = web01, web02, web03, 192.168.1.10, 192.168.1.11 test WEBS=(ALL:ALL) NOPASSWD: /usr/bin/systemctl restart nginx -
Netgroup(NIS/域环境,前缀
+)sudoerstest +webservers=(ALL:ALL) NOPASSWD: /usr/bin/systemctl restart nginx -
取反
!sudoerstest ALL,!web03=(ALL:ALL) NOPASSWD: /usr/bin/systemctl restart nginx -
逗号分隔主机列表
sudoerstest web01,web02,192.168.1.20=(ALL:ALL) NOPASSWD: /usr/bin/systemctl restart nginx
主机名解析依赖 /etc/hosts 或 DNS,解析异常会造成匹配失败。
1.4 多主机部署方案
- 小规模集群:分发主 sudoers 文件,或在
/etc/sudoers.d/下放独立规则文件,使用 Ansible 推送 - 大规模域环境:LDAP 集中维护 sudoHost
推荐将自定义规则放入 /etc/sudoers.d/,不修改主文件,便于分发与回滚。
bash
visudo -f /etc/sudoers.d/90_custom_rules
模板:
sudoers
deploy web01,web02=(ALL:ALL) NOPASSWD: /usr/bin/systemctl restart nginx, /usr/bin/tar
配置完成后,切换对应用户执行 sudo -l 校验权限。
1.5 sudo 执行流程
#mermaid-svg-GODb4VugpWdzvx7p{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-GODb4VugpWdzvx7p .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-GODb4VugpWdzvx7p .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-GODb4VugpWdzvx7p .error-icon{fill:#552222;}#mermaid-svg-GODb4VugpWdzvx7p .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GODb4VugpWdzvx7p .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-GODb4VugpWdzvx7p .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GODb4VugpWdzvx7p .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GODb4VugpWdzvx7p .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-GODb4VugpWdzvx7p .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GODb4VugpWdzvx7p .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GODb4VugpWdzvx7p .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GODb4VugpWdzvx7p .marker.cross{stroke:#333333;}#mermaid-svg-GODb4VugpWdzvx7p svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GODb4VugpWdzvx7p p{margin:0;}#mermaid-svg-GODb4VugpWdzvx7p .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-GODb4VugpWdzvx7p .cluster-label text{fill:#333;}#mermaid-svg-GODb4VugpWdzvx7p .cluster-label span{color:#333;}#mermaid-svg-GODb4VugpWdzvx7p .cluster-label span p{background-color:transparent;}#mermaid-svg-GODb4VugpWdzvx7p .label text,#mermaid-svg-GODb4VugpWdzvx7p span{fill:#333;color:#333;}#mermaid-svg-GODb4VugpWdzvx7p .node rect,#mermaid-svg-GODb4VugpWdzvx7p .node circle,#mermaid-svg-GODb4VugpWdzvx7p .node ellipse,#mermaid-svg-GODb4VugpWdzvx7p .node polygon,#mermaid-svg-GODb4VugpWdzvx7p .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-GODb4VugpWdzvx7p .rough-node .label text,#mermaid-svg-GODb4VugpWdzvx7p .node .label text,#mermaid-svg-GODb4VugpWdzvx7p .image-shape .label,#mermaid-svg-GODb4VugpWdzvx7p .icon-shape .label{text-anchor:middle;}#mermaid-svg-GODb4VugpWdzvx7p .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-GODb4VugpWdzvx7p .rough-node .label,#mermaid-svg-GODb4VugpWdzvx7p .node .label,#mermaid-svg-GODb4VugpWdzvx7p .image-shape .label,#mermaid-svg-GODb4VugpWdzvx7p .icon-shape .label{text-align:center;}#mermaid-svg-GODb4VugpWdzvx7p .node.clickable{cursor:pointer;}#mermaid-svg-GODb4VugpWdzvx7p .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-GODb4VugpWdzvx7p .arrowheadPath{fill:#333333;}#mermaid-svg-GODb4VugpWdzvx7p .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-GODb4VugpWdzvx7p .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-GODb4VugpWdzvx7p .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GODb4VugpWdzvx7p .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-GODb4VugpWdzvx7p .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GODb4VugpWdzvx7p .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-GODb4VugpWdzvx7p .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-GODb4VugpWdzvx7p .cluster text{fill:#333;}#mermaid-svg-GODb4VugpWdzvx7p .cluster span{color:#333;}#mermaid-svg-GODb4VugpWdzvx7p div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-GODb4VugpWdzvx7p .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-GODb4VugpWdzvx7p rect.text{fill:none;stroke-width:0;}#mermaid-svg-GODb4VugpWdzvx7p .icon-shape,#mermaid-svg-GODb4VugpWdzvx7p .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GODb4VugpWdzvx7p .icon-shape p,#mermaid-svg-GODb4VugpWdzvx7p .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-GODb4VugpWdzvx7p .icon-shape .label rect,#mermaid-svg-GODb4VugpWdzvx7p .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GODb4VugpWdzvx7p .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-GODb4VugpWdzvx7p .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-GODb4VugpWdzvx7p :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 失败
成功
未授权
已授权
普通用户
输入命令
sudo
验证用户身份
验证结果
密码错误
退出
检查授权规则
授权结果
拒绝执行
以指定用户执行
返回结果
结束
1.6 sudoers 配置约束
- 命令使用绝对路径,带参数条目为精确匹配
- NOPASSWD 仅用于信任主体与自动化场景
- 别名统一大写
- 修改后执行
sudo -l验证
2 sudo 常用操作
通用语法:sudo [选项] 命令
2.1 切换 root shell
bash
sudo -i
sudo su -
sudo -s
exit
2.2 指定身份执行
bash
sudo -u nginx /usr/sbin/nginx
sudo -u www-data ls -l /var/www/html
sudo -u nginx whoami
2.3 查看权限清单
bash
sudo -l
2.4 密码缓存控制
bash
# 刷新缓存计时,重新校验密码
sudo -v
# 清除密码缓存
sudo -k
2.5 多条命令批量执行
bash
sudo bash -c 'apt update -y && apt upgrade -y && systemctl restart sshd'
2.6 保留环境变量
bash
sudo -E /usr/local/nginx/sbin/nginx -s reload
sudo -E env | grep PATH
3 sudo 安全机制
3.1 密码超时
默认 timestamp_timeout=15,单位分钟。
sudoers
Defaults timestamp_timeout=30
Defaults timestamp_timeout=0
Defaults timestamp_timeout=-1
- 0:每次调用均校验密码
- -1:永久缓存
3.2 审计日志
默认路径:
- CentOS / RHEL:
/var/log/secure - Ubuntu / Debian:
/var/log/auth.log
自定义日志配置:
sudoers
Defaults logfile="/var/log/sudo.log"
Defaults log_format="%u : %h : %t : %p : %m"
检索命令:
bash
grep sudo /var/log/secure
grep sudo /var/log/auth.log
tail -f /var/log/sudo.log
grep "rm -rf" /var/log/sudo.log
3.3 环境变量管控
sudoers
Defaults env_reset
Defaults env_keep += "SSH_AUTH_SOCK"
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
env_reset 开启时清理用户环境;secure_path 单独覆盖 PATH,防止路径劫持。
PATH 相关故障:程序不在 secure_path 内,sudo 提示 command not found。处理方式:
- 调用绝对路径
sudo -E- 修改 secure_path
4 高级用法
4.1 远端 SSH 提权执行
前置:SSH 免密通道。
sudoers
test ALL=(ALL:ALL) /usr/bin/ssh root@192.168.1.100
bash
sudo ssh root@192.168.1.100
sudo ssh root@192.168.1.100 'systemctl restart nginx'
4.2 自动化脚本
遵循最小权限,仅开放脚本所需命令免密:
sudoers
test ALL=(ALL:ALL) NOPASSWD: /usr/bin/systemctl restart nginx, /usr/bin/tar, /bin/rm
5 安全规范
- 遵循最小权限,避免
NOPASSWD: ALL、ALL全权限 - SSH 配置
PermitRootLogin no,禁止 root 直接密码登录 - 定期审计 sudo 日志
- 保持
/etc/sudoers权限 440 - 自动化、cron 场景注释
Defaults requiretty - 脚本禁止明文写入密码
- 及时升级 sudo 软件包,修复漏洞
- 多主机场景使用堡垒机集中审计
- 周期性清理失效权限、离职用户规则
6 故障排查
6.1 xxx is not in the sudoers file
用户未加入授权组、无匹配 sudoers 规则。
bash
su - root
usermod -aG sudo test
usermod -aG wheel test
visudo
test ALL=(ALL:ALL) ALL
修改后重新登录用户。
6.2 must have a tty to run sudo
sudoers 启用 requiretty,非交互式场景报错。
sudoers
# Defaults requiretty
6.3 unable to resolve host
/etc/hosts 缺少主机名映射,补充条目:
127.0.0.1 localhost linux-server
::1 localhost linux-server
6.4 command not found
- 程序未安装
- 程序路径不在 secure_path
- 未使用绝对路径
6.5 password incorrect
- 输入大小写、特殊字符错误
- 用户密码过期,
chage -l test查看,passwd test修改 - sudoers 语法错误,
visudo -c校验 - 用户名、组名拼写错误
6.6 sudo 整体失效
优先执行语法校验:
bash
visudo -c
- 可
su - root:root 登录后修复配置 - su 同样不可用:进入单用户模式修复
附加检查项:文件权限 440、包重装、磁盘空间、文件系统只读状态
6.7 修改密码后 sudo 验证失败
缓存旧密码,清除缓存:
bash
sudo -k
6.8 sudo 执行卡住
Ctrl+C终止进程- 检查系统负载
top - 检查日志文件写入权限
- SSH 远端执行添加
-t分配 TTY journalctl -u sudo查看日志
7 同类工具对比
7.1 su
原生切换用户工具;su - root 需要 root 密码;无细粒度权限控制,审计能力弱。适合单主机应急。
7.2 doas
OpenBSD 项目,配置简洁,体积更小;主流发行版不预装。
bash
apt install doas
yum install doas
配置文件 /etc/doas.conf
doas
permit test as root cmd nginx
7.3 pkexec
PolicyKit 组件,面向图形会话提权;服务器终端场景不适用。
bash
pkexec gedit /etc/hosts
8 su、sudo 环境与 PATH 行为
8.1 基础释义
- su:switch user,切换用户
- sudo:superuser do,以超级用户身份执行命令
-(su -):--login,登录式切换,加载目标用户配置,进入目标用户家目录-i(sudo -i):交互式登录 shell-s(sudo -s):启动 shell,不执行登录初始化
8.2 root 切换方式对比
| 命令 | 模式 | 工作目录 | 环境来源 | PATH 行为 | 需要 root 密码 |
|---|---|---|---|---|---|
su |
非登录 shell | 保持原目录 | 继承当前用户大部分环境变量;通常加载目标用户 ~/.bashrc |
保留原用户 PATH | |
su - / su -l / su - root |
登录 shell | /root |
加载 root 的 /etc/profile、~/.profile/~/.bash_profile,通常再 source ~/.bashrc |
使用 root 登录环境 PATH | |
sudo cmd |
sudo 单次执行 | 保持原目录 | 受 env_reset 限制,仅保留少量变量;可通过 env_keep / -E 保留指定变量 |
默认使用 secure_path |
|
sudo -i |
模拟 root 登录 shell | /root |
构造 root 登录环境,读取 root 登录配置文件 | 接近 root 登录 PATH,但可能受 secure_path 影响 |
|
sudo su - |
登录 shell | /root |
先通过 sudo 提权,再执行 su -,加载 root 登录配置 |
与 su - 基本一致 |
|
sudo -s |
非登录 root shell | 保持原目录(HOME 通常仍为调用者) | 受 sudoers 环境规则约束;通常只加载 root ~/.bashrc |
受 secure_path / env_reset 约束 |
注:
sudo su -与sudo -i最终都能获得 root 登录环境,但sudo -i更直接,只产生一层 sudo 进程;
sudo su -会先提权再调用su,属于冗余写法。
su系列需要知道 目标用户密码 ;sudo系列通常验证 当前用户密码 ,并依赖/etc/sudoers授权。sudo默认启用env_reset,并通过secure_path限制 PATH;这是sudo cmd找不到自定义命令的常见原因。- 生产环境建议优先使用
sudo/sudo -i,避免直接使用su或sudo su -,便于审计和权限控制。
退出命令统一为:
bash
exit
8.3 PATH 问题处理方案(侵入性升序)
- 单次传递 PATH
bash
sudo env PATH="$PATH" my_command
sudo env PATH="$PATH" env | grep ^PATH
- 调用绝对路径
bash
sudo $(which my_command)
- 软链接至 secure_path 目录
bash
sudo ln -s /usr/local/bin/cmd /usr/sbin/cmd
- 修改 secure_path(全局)
sudoers
Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
bash
echo 'Defaults secure_path="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin"' | sudo tee /etc/sudoers.d/custom_path
sudo -i,使用 root 登录环境- env_keep 保留 PATH(存在劫持风险,不推荐常规使用)
sudoers
Defaults env_keep += "PATH"
- shell 别名
bash
alias psudo='sudo env PATH="$PATH"'
psudo my_command
8.4 PATH 劫持原理
用户可控 PATH 中包含可写目录时,同名恶意程序会优先匹配并以 root 权限运行。secure_path 仅使用管理员管控目录,阻断该链路。
8.5 排查项
sudo -V | grep PATH查看 secure_path- 区分两类问题:sudo 程序检索失败、程序内部子进程 PATH 缺失
- 优先使用单次 env 传递或绝对路径,减少全局变更
如果你需要,我可以单独导出一份可直接打印的精简速查版(只保留表格、常用命令、故障清单)。
Reference
- command line - Environment variables when run with 'sudo' - Ask Ubuntu
https://askubuntu.com/questions/57915/environment-variables-when-run-with-sudo - linux - Why are PATH variables different when running via sudo and su? - Unix & Linux Stack Exchange
https://unix.stackexchange.com/questions/8646/why-are-path-variables-different-when-running-via-sudo-and-su - environment variables - Why does sudo change the PATH? - Stack Overflow
https://stackoverflow.com/questions/257616/why-does-sudo-change-the-path - How to make
sudopreserve $PATH? - Unix & Linux Stack Exchange
https://unix.stackexchange.com/questions/83191/how-to-make-sudo-preserve-path - linux - Why are PATH variables different when running via sudo and su? - Unix & Linux Stack Exchange
https://unix.stackexchange.com/questions/8646/why-are-path-variables-different-when-running-via-sudo-and-su - security - Which is the safest way to get root privileges: sudo, su or login? - Unix & Linux Stack Exchange
https://unix.stackexchange.com/questions/8581/which-is-the-safest-way-to-get-root-privileges-sudo-su-or-login - sudo 命令完全指南:从入门到精通
https://mp.weixin.qq.com/s/CbTSZvrDQzDiBrc6wE_2Yg