权限问题:Permission denied、sudo缺失

说白了,权限问题是初始化流程里遇到最多的异常。我几乎每次做新环境部署都要跟它打交道。你想想看,明明脚本写得没问题,一跑就报个"Permission denied",那种感觉——嗯,很熟悉。

这一节我们把权限问题的常见场景、排查思路、解决方案掰开揉碎讲清楚。先从最典型的场景说起。

常见场景:谁挡了你的路?

我遇到过以下几种情况,基本覆盖了90%的权限问题:

  • 文件或目录权限不对——脚本要写日志到 /var/log,但目录是 755,脚本用普通用户跑,写不进去。
  • 执行权限缺失——chmod 没给 x 位,直接执行脚本就报 Permission denied。
  • 用户不在 sudo 组——用户想用 sudo 但没权限,提示"is not in the sudoers file"。
  • sudoers 配置写错——语法错误导致所有 sudo 执行都挂掉。
  • SELinux / AppArmor 干扰——明明权限是 777,但 SELinux 上下文不对,照样拒绝。

你看,每个场景排查手段都不太一样。我最怕的是 SELinux,因为它报错不直观,经常被忽略。后面我们重点讲。

排查方法:先看错误,再动手

遇到 Permission denied,我个人的习惯是三步走:

  1. 确定错误发生的位置——是文件操作、网络端口绑定、还是执行命令?
  2. 查看当前身份和组——用 id 命令,确认 uid 和所属组。
  3. 检查目标权限——用 ls -l、stat 看 owner、group、mode。

举个例子,脚本报 "Permission denied" 不能写 /tmp/test.log:

# 先看当前用户
$ id
uid=1001(webapp) gid=1001(webapp) groups=1001(webapp)

# 再看目录权限
$ ls -ld /tmp
drwxrwxrwt 30 root root 4096 Apr  5 10:00 /tmp

# 哦,sticky bit 在 /tmp 上,但 webapp 用户不是 owner?
# 再检查 /tmp/test.log (如果存在)
$ ls -l /tmp/test.log
-rw-r--r-- 1 root root 0 Apr  5 10:05 /tmp/test.log

问题清楚了:文件属于 root,普通用户写不了。解决办法要么改 owner,要么改目录权限。但改 777?我劝你慎重。

sudo 缺失的排查

如果用户执行 sudo 报错 "user is not in the sudoers file",第一件事不是直接 visudo,而是确认用户是否在 wheel 或 sudo 组:

$ groups user1
user1 : user1 staff

没有 sudo 组,那就加进去:

# 切换 root 或用有 sudo 权限的用户
usermod -aG sudo user1

但这里有个坑——用户需要重新登录才生效。我曾经帮同事排查,他加完组还抱怨没用,结果发现他还在同一个 SSH 会话里。把用户踢出去重连就正常了。

sudoers 语法错误

这个最危险。如果直接 vim /etc/sudoers 手写,写错了会导致所有 sudo 都失效。我推荐用 visudo,它会在保存前做语法检查。举个例子,想给 deploy 用户免密执行 systemctl:

deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl

写错一个逗号、多一个空格,都可能报错。visudo 会提示 ">>> /etc/sudoers: syntax error",那时你能庆幸没直接保存。

SELinux 干扰

有些时候 ls -l 显示权限没问题,还是 Permission denied。那可能是 SELinux 在拦。先看状态:

$ getenforce
Enforcing

如果是 Enforcing,再用 audit2why 或看 /var/log/audit/audit.log。例如 Nginx 想读一个自定义目录下的文件,但 SELinux 上下文是 default_t 而不是 httpd_sys_content_t:

# 修复上下文
chcon -R -t httpd_sys_content_t /custom/webroot

或者用 semanage 做持久化。我一直建议在初始化阶段就定好 SELinux 策略,不要在运行时临时折腾。

解决方案速查表

现象 排查命令 常见解法
文件读写拒绝 ls -l, id chmod/chown 修改权限或属主
执行脚本拒绝 ls -l 看 x 位 chmod +x
sudo 报"not in sudoers" groups, sudo -l usermod -aG sudo 并重新登录
sudo 执行卡死/报语法错误 visudo -c 用 visudo 修复 /etc/sudoers
权限看似正确仍被拒 getenforce, audit2why 调整 SELinux 上下文或临时 setenforce 0 测试

避坑指南

我曾经帮一个团队排查线上故障,发现有人写了个脚本,里面直接 chmod 777 -R /。结果整个系统的 suid 位全被清掉了,所有普通用户都起不了 sudo。最后只能从备份恢复。我给大家的建议:永远不要用 777 解决问题,最多用 755 或 750,并且要指定目标路径。
一个实用技巧:如果你不确定某个文件到底卡在哪一层权限,可以用 namei -l /path/to/file 查看路径上每一段的权限。我经常用这个来排查"明明文件能读但打开报错"的诡异问题——往往是中间目录少了一个 x 权限。

权限问题排查流程图

下面这张图总结了我平时排查权限问题的核心逻辑。遇到 Permission denied,按这个流程走一遍,基本能定位。

权限问题排查流程 权限问题排查流程 遇到 Permission denied ls -l / stat 检查文件权限 用户是属主? 对比属主权限 (rwx) 检查其他用户/组权限 权限足够? 检查 SELinux / sudoers chmod/chown 修复 问题解决 * 先补权限,再测,不行则查 SELinux

写在最后

权限问题不复杂,但很琐碎。我的经验是:把检查步骤流程化,形成肌肉记忆。遇到 Permission denied,不做无头苍蝇,按上面的流程图走一遍,基本半小时内搞定。另外,记得把所有操作记录到文档,下次同样问题直接翻文档,不用重新想。

核心口诀:

  • 权限不够找自己(id)
  • 自己不对找文件(ls -l)
  • 文件对了还不行(SELinux)
  • sudo 不行查配置(visudo -c)