LInux | sudo 与 su 操作

sudo 与 su 操作手册

目录

  1. sudoers 配置
  2. sudo 常用操作
  3. sudo 安全机制
  4. sudo 高级用法
  5. 安全规范
  6. 故障排查
  7. 同类工具对比
  8. 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。支持以下类型:

  1. 短主机名 / FQDN

    sudoers 复制代码
    test    web01=(ALL:ALL) NOPASSWD: /usr/bin/systemctl restart nginx
  2. 单个 IP

    sudoers 复制代码
    test    192.168.1.10=(ALL:ALL) NOPASSWD: /usr/bin/systemctl restart nginx
  3. CIDR 网段

    sudoers 复制代码
    test    192.168.1.0/24=(ALL:ALL) NOPASSWD: /usr/bin/systemctl restart nginx
  4. Host_Alias

    sudoers 复制代码
    Host_Alias WEBS = web01, web02, web03, 192.168.1.10, 192.168.1.11
    test    WEBS=(ALL:ALL) NOPASSWD: /usr/bin/systemctl restart nginx
  5. Netgroup(NIS/域环境,前缀 +)

    sudoers 复制代码
    test    +webservers=(ALL:ALL) NOPASSWD: /usr/bin/systemctl restart nginx
  6. 取反 !

    sudoers 复制代码
    test    ALL,!web03=(ALL:ALL) NOPASSWD: /usr/bin/systemctl restart nginx
  7. 逗号分隔主机列表

    sudoers 复制代码
    test    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。处理方式:

  1. 调用绝对路径
  2. sudo -E
  3. 修改 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 安全规范

  1. 遵循最小权限,避免 NOPASSWD: ALL、ALL 全权限
  2. SSH 配置 PermitRootLogin no,禁止 root 直接密码登录
  3. 定期审计 sudo 日志
  4. 保持 /etc/sudoers 权限 440
  5. 自动化、cron 场景注释 Defaults requiretty
  6. 脚本禁止明文写入密码
  7. 及时升级 sudo 软件包,修复漏洞
  8. 多主机场景使用堡垒机集中审计
  9. 周期性清理失效权限、离职用户规则

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 问题处理方案(侵入性升序)

  1. 单次传递 PATH
bash 复制代码
sudo env PATH="$PATH" my_command
sudo env PATH="$PATH" env | grep ^PATH
  1. 调用绝对路径
bash 复制代码
sudo $(which my_command)
  1. 软链接至 secure_path 目录
bash 复制代码
sudo ln -s /usr/local/bin/cmd /usr/sbin/cmd
  1. 修改 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
  1. sudo -i,使用 root 登录环境
  2. env_keep 保留 PATH(存在劫持风险,不推荐常规使用)
sudoers 复制代码
Defaults env_keep += "PATH"
  1. 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