这是我踩过最"玄学"的坑之一:明明把用户加进 sudo 组了,sudo 还是报 user is not in the sudoers file。
现象
$ sudo apt update
dsh is not in the sudoers file. This incident will be reported.
但查一下,用户明明已经在组里了:
$ id dsh
uid=1000(dsh) gid=1000(dsh) groups=1000(dsh),27(sudo) # ← 有 sudo 组!
$ getent group sudo
sudo:x:27:dsh # ← 也确实在
系统记录里在,实际却不生效——这就是它"玄学"的地方。
真正的原因
关键在于:查看权限时,要分"系统记录的"和"当前会话持有的"。
$ id dsh # 查"系统记录"(读配置文件)→ 有 sudo
$ id # 查"当前会话"(读进程凭证)→ 没有 sudo
因为 Linux 进程在创建那一刻就把用户组快照写进了凭证里(struct cred)。之后你改 /etc/group,已经存在的会话完全不知道。
用户组变更,只对"新登录的会话"生效。
怎么解
方法 1:重新登录(最常用)
exit # 退出
ssh user@服务器 # 重新登录 —— 新会话就带上新组了
方法 2:用 newgrp 切换(不退出)
newgrp sudo # 启动一个带 sudo 组的新 shell
方法 3:su - 重新加载
su - $USER
更隐蔽的情况:长连接池
我遇到的真实场景更绕:SSH 客户端有连接池,一直复用同一条老连接。你"重新连接"看起来是新会话,其实池子里还是那个老会话——怎么试都不生效。
# 排查思路:换一条全新的连接试试
ssh -o ControlMaster=no -o ControlPath=none user@服务器 id
教训:长连接虽然快,但会掩盖环境变更。
排查诡异问题时,第一步永远是——换个干净会话再试。
排查诡异问题时,第一步永远是——换个干净会话再试。
一张排查清单
| 检查项 | 命令 | 看什么 |
|---|---|---|
| 系统记录 | id 用户名 | 组里有没有 |
| 当前会话 | id | 实际拿到的组 |
| 组配置 | getent group sudo | 成员列表 |
| sudo 规则 | sudo -l | 你能执行什么 |
总结
id和id 用户名看的不是一回事- 组变更需要新会话才生效
- 长连接池会让"重新登录"变成假动作
- 排查时先排除环境问题,再怀疑配置