一、权限是什么?
Linux 是多用户多任务系统,文件权限决定了“谁能对文件做什么”。对运维和日常使用来说,理解权限是避免“Permission denied”的第一步,也是配置共享目录、保护敏感文件的基础。
权限模型分为三层:传统 UGO 权限(属主、属组、其他人)→ ACL 扩展权限(细粒度控制)→ 特殊权限位(如 setgid)。三层配合使用,基本能覆盖所有权限管理场景。
二、基础权限(UGO 模型)
1. 查看权限:ls -l
执行 ls -l 会看到类似这样的输出:
-rwxrw-r-- 1 alice devops 1024 Apr 16 10:00 script.sh
最前面的 10 个字符是关键,分成四组理解:
| 位置 | 示例 | 含义 |
|---|---|---|
| 第 1 位 | - | 文件类型:-普通文件、d目录、l符号链接、b块设备、c字符设备 |
| 第 2-4 位 | rwx | 属主权限(user) |
| 第 5-7 位 | rw- | 属组权限(group) |
| 第 8-10 位 | r-- | 其他人权限(others) |
每个权限位由 r(读)、w(写)、x(执行)组成,缺失用 - 表示。
对文件和目录的不同含义:
| 权限 | 对文件 | 对目录 |
|---|---|---|
r | 读取文件内容 | 列出目录内容(需同时有 x) |
w | 修改文件内容 | 在目录内创建/删除/重命名文件(需同时有 x) |
x | 执行文件(脚本/程序) | 进入目录、访问目录内文件的元数据 |
常见误区:给目录只加
r不加x,你依然无法ls进去,因为x是“通行证”。目录的w需要x配合才能生效。
2. 权限的数字表示(八进制)
r、w、x 分别对应数值 4、2、1,组合相加得到权限码:
| 权限 | 数值 |
|---|---|
rwx | 7 |
rw- | 6 |
r-x | 5 |
r-- | 4 |
-wx | 3 |
-w- | 2 |
--x | 1 |
--- | 0 |
一个完整的权限可以用三个数字表示:属主权限、属组权限、其他人权限。例如 755 表示 rwxr-xr-x。
3. 修改权限:chmod
# 符号方式
chmod u+x file.sh # 属主加执行
chmod g-w file.sh # 属组去掉写
chmod o=r file.sh # 其他人设为只读
chmod a+x script.sh # 所有人加执行
# 数字方式
chmod 755 script.sh # rwxr-xr-x
chmod 644 config.conf # rw-r--r--
4. 修改属主/属组:chown 和 chgrp
# 修改属主
chown alice file.txt
# 同时修改属主和属组
chown alice:devops file.txt
# 只修改属组
chgrp devops file.txt
普通用户只能将自己名下文件的属组改为自己所在的组,且必须是该组的成员。修改属主需要 root 权限。
5. 权限判断逻辑
当用户访问一个文件时,系统按以下顺序决定权限:
- 如果用户是文件的属主 → 应用属主权限。
- 否则,如果用户属于文件的属组(或文件所在组的成员) → 应用属组权限。
- 否则 → 应用其他人权限。
注意:只命中第一个符合条件的规则,不会叠加。如果用户既是属主又属于属组,只使用属主权限。
三、ACL(访问控制列表)—— 突破 UGO 限制
传统 UGO 权限只能指定一个属主、一个属组、一组其他人。现实场景中常常需要:
- 给特定用户(如
tempuser)单独的读写权限,但不希望他成为属主。 - 给多个不同组的成员不同权限。
- 让新建文件自动继承父目录的 ACL 规则。
ACL 就是用来解决这些问题的。
1. 查看 ACL
getfacl file.txt
输出示例:
# file: file.txt
# owner: alice
# group: devops
user::rw-
user:bob:r--
group::r--
mask::r--
other::---
2. 设置 ACL
# 给特定用户添加权限
setfacl -m u:bob:rwx file.txt
# 给特定组添加权限
setfacl -m g:project:r-x dir/
# 移除某条 ACL
setfacl -x u:bob file.txt
# 递归设置目录 ACL(新文件继承?需要配合默认 ACL)
setfacl -R -m u:bob:r-x dir/
3. 默认 ACL(继承)
对目录设置默认 ACL 后,目录内新建的文件/子目录会自动继承规则。
setfacl -m d:u:bob:r-x dir/ # 设置默认 ACL
setfacl -k dir/ # 移除默认 ACL
4. mask 概念(重要!)
ACL 引入了一个 mask 值,它表示“当前 ACL 条目的最大有效权限”。任何用户或组的实际权限不能超过 mask 的权限位。
查看 getfacl 输出中的 mask::r-x 这一行。如果 mask 是 r-x,即使某条 ACL 条目写着 rwx,实际生效的也是 r-x。
常见问题:用 chmod 修改文件权限时,可能会意外修改 mask。建议使用 setfacl -m mask:rwx file 来单独调整 mask。
个人习惯:每次设置 ACL 后,用
getfacl确认 mask 是否符合预期。如果发现权限不生效,优先检查 mask。
四、setgid —— 让目录内的新文件自动继承属组
setgid(Set Group ID)是一个特殊权限位,主要用于目录:当目录设置了 setgid,该目录下新建的文件/子目录会自动继承目录的属组,而不是继承创建者的默认属组。
这对于团队共享目录非常有用。
1. 设置 setgid
# 数字方式:在权限前面加 2
chmod 2775 shared_dir/
# 符号方式
chmod g+s shared_dir/
2. 查看 setgid
ls -l 中,属组的 x 位会变成 s(如果原来有执行权限)或 S(如果原来没有执行权限)。
drwxrwsr-x 2 alice devops 4096 Apr 16 10:00 shared_dir/
# ↑ 这个 s 表示 setgid 已设置
3. setgid 的效果
# 假设 shared_dir 属组为 devops,设置了 setgid
$ ls -ld shared_dir/
drwxrwsr-x 2 alice devops 4096 Apr 16 10:00 shared_dir/
# 用户 bob(属于 devops 组)在目录内新建文件
$ touch shared_dir/newfile.txt
$ ls -l shared_dir/newfile.txt
-rw-r--r-- 1 bob devops 0 Apr 16 10:01 newfile.txt
# ↑ 属组自动变成了 devops,而不是 bob 的默认组
这样,同组成员都能互相访问彼此新建的文件(前提是权限允许)。
注意:setgid 只影响新建的文件,已有文件的属组不会改变。
五、umask —— 新建文件/目录时的默认权限掩码
umask 决定了新创建文件或目录的默认权限。它不是一个权限设置,而是一个“减去”的值。
1. 规则
- 文件的默认基准权限是 666(
rw-rw-rw-)。 - 目录的默认基准权限是 777(
rwxrwxrwx)。 - 最终权限 = 基准权限 – umask 值(按位减去)。
常见 umask 值及效果:
| umask | 新文件权限 | 新目录权限 |
|---|---|---|
| 022 | 644(rw-r--r--) | 755(rwxr-xr-x) |
| 002 | 664(rw-rw-r--) | 775(rwxrwxr-x) |
| 077 | 600(rw-------) | 700(rwx------) |
2. 查看和设置 umask
# 查看当前 umask(数字形式)
umask
# 输出 022
# 设置 umask(临时,仅当前 shell)
umask 002
# 永久设置:写入 ~/.bashrc 或 /etc/profile
echo "umask 002" >> ~/.bashrc
个人习惯:在多用户协作的服务器上,我把 umask 设为
002,这样同组成员创建的文件默认可被组内其他人修改,减少权限问题。
六、综合案例:配置一个组内共享工作目录
需求:有一个项目组 proj,成员包括 alice、bob、carol。需要创建一个共享目录 /data/project,要求:
- 只有
proj组的成员可以进入和操作该目录。 - 目录内新建的文件/子目录自动继承
proj组,组成员可以互相编辑。 - 项目经理
alice拥有删除任意文件的权限,普通成员不能删除他人创建的文件(除非文件权限允许)。 - 临时成员
tempuser只有只读访问权限。
步骤 1:创建组和用户
# 创建组
groupadd proj
# 添加用户并加入组
useradd -G proj alice
useradd -G proj bob
useradd -G proj carol
useradd tempuser # 临时用户,不属于 proj 组
# 设置密码(略)
步骤 2:创建共享目录并设置基础权限
mkdir -p /data/project
chown root:proj /data/project # 属组设为 proj
chmod 2770 /data/project # 权限 2770:rwxrwx--- + setgid
2770:属主 root 有全部权限,属组 proj 有全部权限,其他人无权限。2(setgid):确保目录内新建文件的属组自动为proj。
检查:
ls -ld /data/project
# drwxrws--- 2 root proj 4096 Apr 16 10:00 /data/project
步骤 3:使用 ACL 添加临时用户的只读权限
setfacl -m u:tempuser:r-x /data/project
# 注意:对目录需要 r 和 x 才能进入和列出内容
步骤 4:给项目经理额外的删除权限(可选,因为已经是属组成员)
实际上 alice 作为 proj 组成员,已经有 rwx 权限,可以删除任意文件。但如果希望限制普通成员不能删除他人文件,可以调整 umask 和 ACL 的 mask,或者使用更细粒度的 ACL 对 alice 赋予特殊权限(但这里默认已经满足)。
更严格的场景:普通成员只能删除自己创建的文件。这需要依赖粘滞位(sticky bit),例如 /tmp 目录的 t 权限。可以在共享目录设置粘滞位:
chmod +t /data/project # 添加粘滞位,使得只有文件属主、目录属主、root 能删除文件
但粘滞位与 setgid 同时使用需要注意:chmod 3770 /data/project(3 = setgid + sticky)。
不过本案例不强制要求粘滞位,按需求灵活选择。
步骤 5:配置 umask 确保组成员默认可写
要求每个成员在自己的 shell 环境(或系统全局)设置 umask 为 002:
# 在 /etc/profile 或 /etc/bash.bashrc 中添加
if [ $UID -gt 199 ] && [ "`id -gn`" = "`id -un`" ]; then
umask 002
else
umask 022
fi
这样新文件权限为 664(rw-rw-r--),新目录权限为 775(rwxrwxr-x),组成员可互相修改。
步骤 6:验证
以 bob 身份登录,在 /data/project 中创建文件:
su - bob
cd /data/project
echo "hello" > bob.txt
ls -l bob.txt
# -rw-rw-r-- 1 bob proj 6 Apr 16 10:05 bob.txt
# ↑ 属组为 proj,组成员可写
以 alice 身份登录,尝试修改 bob.txt:
su - alice
echo "world" >> /data/project/bob.txt # 成功
以 tempuser 身份登录,尝试写文件:
su - tempuser
touch /data/project/temp.txt
# touch: cannot touch 'temp.txt': Permission denied
但可以读:
cat /data/project/bob.txt # 成功
配置完成。
七、速查表
| 操作 | 命令 |
|---|---|
| 查看权限 | ls -l |
| 修改权限(数字) | chmod 755 file |
| 修改权限(符号) | chmod u+x,g-w,o=r file |
| 修改属主 | chown alice file |
| 修改属组 | chgrp devops file |
| 查看 ACL | getfacl file |
| 设置 ACL(用户) | setfacl -m u:bob:rwx file |
| 设置 ACL(组) | setfacl -m g:proj:rx file |
| 设置默认 ACL(继承) | setfacl -m d:u:bob:rx dir/ |
| 移除 ACL | setfacl -x u:bob file |
| 设置 setgid(数字) | chmod 2775 dir |
| 设置 setgid(符号) | chmod g+s dir |
| 设置粘滞位 | chmod +t dir |
| 查看 umask | umask |
| 设置 umask | umask 002 |
八、个人经验总结
- 优先使用 UGO + setgid 解决大部分共享目录需求,ACL 作为补充(如给特定用户只读)。
- 不要滥用 ACL,它会让
ls -l无法完整显示权限,排查问题记得用getfacl。 - setgid 是共享目录的好帮手,配合 umask 002 可以省去大量
chgrp操作。 - mask 是个隐藏坑:如果 ACL 不生效,先检查 mask。
- 新文件权限异常:检查 umask 是否符合预期,尤其是不同用户的默认 umask 可能不同。