Linux运维9 min read次阅读

Linux 用户、组与权限:ACL 和 sudo 该用在哪

权限问题的标准解法是 chmod 777,然后问题解决,然后没人再管。这事的麻烦在于:三个月后另一个人也遇到"没权限",也 777,最后整个数据目录对所有人可写,谁删的你都查不出来。

Linux 权限其实就三层,搞清楚之后大部分问题有更干净的解法。

基础:rwx 到底是谁的

ls -l /data/app.log
# -rw-r--r-- 1 appuser appgroup 1024 Sep  8 10:00 /data/app.log
# ↑  ↑  ↑  ↑              ↑
# |  |  |  |              └─ 所属组
# |  |  |  └── 其他人(other)权限 r--
# |  |  └───── 组(group)权限 r--
# |  └──────── 属主(user)权限 rw-
# └─────────── 文件类型 - 普通文件 d 目录 l 链接

目录的 rwx 含义和文件不一样,这点常混淆:

权限 文件 目录
r 能读内容 能列出里面有什么(ls
w 能改内容 在里面增/删/改名(不看文件本身权限)
x 能执行 进入cd

倒数第二条最容易踩:能不能删一个文件,取决于它所在目录有没有 w,和文件自己的权限无关。所以共享目录要给粘滞位(下面说)。

umask:新建文件的默认权限

umask            # 看当前,常见 022 或 002
umask 0027       # 临时改

算法:文件满权限 666、目录 777,减去 umask。

  • umask 022 → 文件 644(rw-r--r--)、目录 755
  • umask 027 → 文件 640、目录 750(组内可读写,其他人不给)
  • umask 077 → 文件 600、目录 700(只有自己)

多人协作的共享目录,把用户的 umask 设成 002,组才有写权限,否则 A 建的文件 B 改不了。写进 /etc/profile~/.bashrc 持久化。

注意:umask 减出来的权限不会自动给 x。文件本来就没执行位,只有程序编译或 chmod +x 才有。

三个特殊位

chmod u+s file    # setuid:执行时以文件属主身份运行
chmod g+s dir     # setgid:目录里新建的文件自动继承目录的组
chmod +t dir      # 粘滞位:只有文件属主能删自己的文件
  • setuid:典型是 /usr/bin/passwd,普通用户执行它改 /etc/shadow,靠的就是运行时临时拿到 root 身份。看到不该有 s 位的文件要警惕,这是提权的常见入口:

    find / -perm -4000 -type f 2>/dev/null    # 找出所有 setuid 文件
    
  • setgid(目录上):共享目录必备。设了之后,任何人在这个目录里建的文件,组都自动是目录的组,不会出现"A 建的文件组是 A,B 访问不了"的情况。

    mkdir /data/shared
    chgrp devteam /data/shared
    chmod 2775 /data/shared      # 2 就是 setgid
    
  • 粘滞位/tmp 就是 drwxrwxrwt。所有人可写,但只能删自己的文件。共享目录必须有它,否则任何人都能删别人的东西。

    chmod 1777 /data/shared      # 1 是粘滞位
    

    组合起来共享目录常用 chmod 3775(setgid + 粘滞位)。

什么时候该用 ACL

rwx 只能控制"属主/组/其他"三类人。要给第四个人单独开权限,或者给多个组不同权限,基础位就无能为力了——这时候上 ACL。

# 给用户 alice 单独加读写(不影响其他人)
setfacl -m u:alice:rw /data/report.csv

# 给组加
setfacl -m g:ops:rwx /data/deploy/

# 让目录里新建的文件也继承(d: 前缀 = default)
setfacl -m d:u:alice:rw /data/shared/

# 查看
getfacl /data/report.csv

# 删除某条
setfacl -x u:alice /data/report.csv

# 清空所有 ACL
setfacl -b /data/report.csv

开了 ACL 后 ls -l 的权限位末尾会多个 +

-rw-rw-r--+ 1 appuser appgroup 1024 Sep  8 10:00 report.csv
#        ↑ 有 ACL

ACL 的取舍:灵活,但增加理解成本——别人 ls 看到 rw-r--r-- 以为 alice 不能写,实际 ACL 里给了。所以能用"建个组、把人加进去、用 setgid 共享目录"解决的,优先用组,ACL 留给临时授权和特殊例外。

还有一个坑:ACL 在部分老的文件系统或挂载选项下不生效,用之前先确认:

mount | grep -w /    # ext4/xfs 默认都支持
tune2fs -l /dev/sda1 | grep acl    # ext 系列看 Default mount options

备份时也要注意,tar 默认不带 ACL,得加 --aclsrsync-A

sudo:别直接给 ALL

# /etc/sudoers 或 /etc/sudoers.d/xxx(用 visudo 编辑!)
# visudo 会检查语法,直接 vi 改错了可能把自己锁在门外

几种写法:

# 完全放开(只有你自己用的机器才这么干)
alice   ALL=(ALL) ALL

# 免密完全放开 —— 等于把 root 给他
alice   ALL=(ALL) NOPASSWD: ALL

# 只允许特定命令(推荐)
alice   ALL=(ALL) /usr/bin/systemctl restart nginx, /usr/bin/systemctl status nginx

# 只允许以某个用户身份跑
bob     ALL=(appuser) /opt/app/bin/deploy.sh

# 用别名管理一组命令
Cmnd_Alias NGINX_CMD = /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx
%webteam ALL=(ALL) NOPASSWD: NGINX_CMD       # % 表示组

命令要写绝对路径。写 systemctl 而不是 /usr/bin/systemctl,用户可以放一个同名脚本在 PATH 前面绕过限制。

NOPASSWD 慎用:给了免密等于这台机器对该用户的相关权限完全开放。CI/CD 场景确实需要,但要配合 sudo -l 定期审计。

看看自己有什么权限:

sudo -l        # 列出当前用户能跑的命令

一个常见的排查顺序

"Permission denied" 的时候按这个查:

id                        # 1. 我是谁,在哪些组
ls -ld /path/to/dir       # 2. 目标目录的权限和属主(注意是目录不是文件)
ls -l  /path/to/file      # 3. 文件本身
getfacl /path/to/file     # 4. 有没有 ACL
namei -l /path/to/file    # 5. 逐级看路径上每一层——最常被忽略
mount | grep <挂载点>      # 6. 是不是 ro 挂载、nosuid、noexec

第 5 步最关键:/a/b/c.txt 要能访问,/a/a/b 每一层都必须至少有 x 权限。很多人只查了文件本身,卡在中间某层目录上。

还有个容易忘的:改了用户所属的组,要重新登录才生效

usermod -aG docker alice    # -a 是追加,漏了会覆盖掉原有附加组!
newgrp docker               # 不想重登的话用这个临时切
id alice                    # 确认

usermod -G(没有 -a)会把用户从其他附加组里踢掉,这是个能让人瞬间失去 sudo 权限的操作,务必用 -aG

几个建议

  • 服务进程用独立的系统用户跑,别用 root;useradd -r -s /sbin/nologin appuser
  • 共享目录:组 + setgid + 粘滞位,比 ACL 清爽
  • 定期 find / -perm -4000 和审计 sudo -l,权限 creep 是慢慢发生的
  • 给出去的权限记在文档里,人离职的时候才知道要回收什么
分享:

评论区