导读:当传统的
chmod 744无法满足“让 A 用户只读、B 用户读写、其他人无权限”这类复杂需求时,ACL(访问控制列表)就是你的答案。本文将深入剖析 ACL 的原理、用法及其在生产环境中的最佳实践。
1. 引言:传统权限模型的局限
Linux 传统的 UGO(User-Group-Other)权限模型简单高效,但在以下场景中明显力不从心:
| 场景 | 传统 UGO 的困境 | ACL 解决方案 |
|---|---|---|
| 多团队协作 | 一个文件只能属于一个组 | 可为多个用户/组分别设置权限 |
| 临时授权 | 需将用户加入组,事后忘记移除 | 单独为用户添加 ACL,可随时撤销 |
| 不同权限级别 | 只能设置单一组权限 | 不同用户/组可有不同读写执行组合 |
| 默认权限继承 | 依赖 umask,无法精细控制 | 可设置默认 ACL,新文件自动继承 |
核心价值:ACL(Access Control List)在传统 UGO 模型之上,为每个文件/目录增加了一个扩展权限列表,允许为任意多个用户或组设置独立权限。
2. ACL 的核心概念
2.1 ACL 的组成元素
每个 ACL 条目(Access Control Entry, ACE)包含三部分:
| 组成 | 说明 | 示例 |
|---|---|---|
| 主体类型 | 用户、组、掩码、默认 | user, group, mask, default |
| 主体名称 | 具体的用户名或组名 | alice, developers |
| 权限 | r(读)、w(写)、x(执行) | rwx, r-x, r-- |
2.2 三种 ACL 类型
| 类型 | 含义 | 作用对象 |
|---|---|---|
| 访问 ACL | 控制特定用户/组对该文件的访问 | 已存在的文件/目录 |
| 默认 ACL | 指定新建文件/目录继承的权限 | 仅作用于目录 |
| 掩码 ACL | 限制 ACL 条目的最大有效权限 | 所有命名用户/组 |
graph TD
A[目录 /data] -->|设置| B[默认 ACL]
B -->|新文件继承| C[子文件]
B -->|新目录继承| D[子目录]
D -->|继承| E[子目录的默认 ACL]
2.3 权限检查顺序
当进程访问一个设置了 ACL 的文件时,内核按以下顺序检查权限:
1. 进程 UID 是否匹配文件 owner?
└─ 是 → 使用 owner 权限
└─ 否 ↓
2. 是否有匹配进程 UID 的命名用户 ACL?
└─ 是 → 使用该 ACL 权限(受 mask 限制)
└─ 否 ↓
3. 进程 GID 是否匹配文件的 owning group 或命名组 ACL?
└─ 是 → 使用匹配组中最宽松的权限(受 mask 限制)
└─ 否 ↓
4. 使用 other 权限
3. 基础操作命令
3.1 查看 ACL
# 查看文件的 ACL 设置
getfacl file.txt
# 递归查看目录及子文件
getfacl -R /data/project
# 不显示注释(便于脚本处理)
getfacl --omit-header file.txt
# 查看当前目录的 ACL(. 表示当前目录)
getfacl .
输出示例:
$ getfacl /data/shared
# file: data/shared
# owner: root
# group: root
user::rwx
user:alice:rw-
user:bob:r--
group::r-x
mask::rw-
other::---
default:user::rwx
default:user:alice:rw-
default:group::r-x
default:mask::rwx
default:other::---
3.2 设置 ACL
# 为特定用户添加权限
setfacl -m u:alice:rw file.txt
# 为特定组添加权限
setfacl -m g:developers:rx /data/project
# 移除特定用户的 ACL
setfacl -x u:alice file.txt
# 移除所有扩展 ACL(恢复传统权限)
setfacl -b file.txt
# 递归设置目录 ACL(已有文件会继承吗?见下文陷阱)
setfacl -R -m u:alice:rw /data/project
3.3 默认 ACL(目录专用)
# 设置默认 ACL:新文件自动继承
setfacl -m d:u:alice:rw /data/project
# 同时设置访问 ACL 和默认 ACL
setfacl -m u:alice:rw -m d:u:alice:rw /data/project
# 移除默认 ACL
setfacl -k /data/project
关键点:默认 ACL 只影响之后在该目录下创建的文件/目录,对已存在的子文件/目录无效。
4. 掩码(Mask)机制
4.1 掩码的作用
掩码(mask)是 ACL 中的一个特殊条目,它限制所有命名用户、命名组和 owning group 的最大有效权限。
# 查看掩码(输出中的 mask 行)
getfacl file.txt
示例:
$ getfacl file.txt
user::rw-
user:alice:rwx # 本想给 rwx
group::r--
mask::r-- # 但掩码限制为 r--
other::---
# 实际上 alice 的有效权限是 r--(受 mask 限制)
4.2 掩码的自动计算
当使用 setfacl -m 添加 ACL 时,系统会自动重新计算掩码:将所有 ACL 条目的权限做“按位或”运算。
# 假设已有 ACL:alice=rw, bob=r
# 掩码会被计算为 rw(rw | r = rw)
# 手动设置掩码
setfacl -m mask::rx file.txt
4.3 掩码的最佳实践
| 场景 | 建议 |
|---|---|
| 不希望掩码自动变化 | 先手动设置掩码,再添加用户 ACL |
| 确保掩码不限制权限 | 设置 mask::rwx 然后添加具体权限 |
| 脚本自动化 | 每次修改后检查掩码,必要时显式设置 |
# 安全添加 ACL 的脚本模式
setfacl -m mask::rwx /data/share
setfacl -m u:alice:rw /data/share
setfacl -m u:bob:r /data/share
# 此时掩码仍为 rwx(不会降级)
5. ACL 的继承机制
5.1 文件与目录继承规则
| 父目录设置 | 新建文件继承 | 新建子目录继承 |
|---|---|---|
u:alice:rw |
不继承 | 不继承 |
d:u:alice:rw |
复制为 u:alice:rw |
复制为 d:u:alice:rw |
d:g:dev:rx |
复制为 g:dev:rx |
复制为 d:g:dev:rx |
d:mask::rw |
复制为 mask::rw |
复制为 d:mask::rw |
5.2 递归设置 vs 继承
# 递归修改:影响已存在的子文件/目录
setfacl -R -m u:alice:rw /data/project
# 默认 ACL:只影响未来的子文件/目录
setfacl -m d:u:alice:rw /data/project
两者结合是最佳实践:
# 同时处理已存在和未来文件
setfacl -R -m u:alice:rw /data/project
setfacl -m d:u:alice:rw /data/project
6. 备份与恢复
6.1 备份 ACL
# 备份单个文件的 ACL
getfacl file.txt > file.acl
# 递归备份目录的 ACL(含子文件)
getfacl -R /data/project > project_acl.bak
6.2 恢复 ACL
# 恢复单个文件
setfacl --restore=file.acl
# 注意:恢复文件必须包含路径信息
# getfacl 输出的第一行是 # file: /path/to/file
跨系统恢复的注意事项:
| 问题 | 解决方案 |
|---|---|
| 路径不同 | 手动编辑 .acl 文件或使用 sed 替换路径 |
| 用户/组不存在 | 先创建用户/组,恢复时添加 --skip-no-user |
# 跳过目标系统上不存在的用户/组
setfacl --restore=project_acl.bak --skip-no-user
7. 进阶实战场景
7.1 场景一:多团队共享目录
需求:/data/share 目录,alice(研发)可读写,bob(运维)只读,其他研发成员可读写,其他运维成员只读。
# 创建组
groupadd devops
groupadd ops
# 将用户加入组
usermod -aG devops alice
usermod -aG ops bob
# 设置目录权限和 ACL
mkdir -p /data/share
chown root:devops /data/share
chmod 770 /data/share # 本组(devops)rwx
# 为运维组添加读权限
setfacl -m g:ops:rx /data/share
# 为特定用户设置权限
setfacl -m u:alice:rwx /data/share # alice 读写执行
setfacl -m u:bob:r-x /data/share # bob 只读执行
7.2 场景二:临时授权且自动过期
需求:审计员需要临时读取 /var/log 日志,7 天后自动失效。
# 创建审计专用账号
useradd auditor
# 添加 ACL
setfacl -m u:auditor:r-x /var/log
# 设置 cron 任务自动清理
(crontab -l 2>/dev/null; echo "0 0 * * 0 setfacl -x u:auditor /var/log") | crontab -
7.3 场景三:Web 上传目录的精细控制
需求:/var/www/uploads 目录,用户上传的文件自己可改,其他用户只读。
mkdir -p /var/www/uploads
chown www-data:www-data /var/www/uploads
# 默认 ACL:新文件使用 rw-r-----(用户自己读写,同组只读)
setfacl -m d:u::rwx /var/www/uploads
setfacl -m d:g::r-x /var/www/uploads
setfacl -m d:o::--- /var/www/uploads
setfacl -m d:mask::rwx /var/www/uploads
# sticky bit:防止用户删除非自己创建的文件
chmod +t /var/www/uploads
7.4 场景四:邮件目录的多用户访问
需求:用户 alice 的邮件目录,需要临时允许 bob 读取。
# 检查传统权限是否允许
chmod 755 /home/alice/Maildir
setfacl -m u:bob:rx /home/alice/Maildir
setfacl -R -m u:bob:r /home/alice/Maildir/cur # 新邮件目录
8. 性能与兼容性
8.1 文件系统支持
| 文件系统 | ACL 支持 |
|---|---|
| ext2/ext3/ext4 | ✅ 需挂载时启用 acl 选项 |
| XFS | ✅ 默认支持 |
| Btrfs | ✅ 默认支持 |
| ZFS | ✅ 默认支持 |
| tmpfs | ✅ 默认支持 |
| NFS | ⚠️ 取决于服务端和客户端配置 |
启用 ext4 的 ACL:
# 修改 /etc/fstab
/dev/sda1 /data ext4 defaults,acl 0 1
# 重新挂载
mount -o remount,acl /data
8.2 与备份工具的关系
| 工具 | ACL 支持 | 需要额外参数 |
|---|---|---|
tar |
✅ 支持 | --acls 参数 |
rsync |
✅ 支持 | -A 或 --acls |
cp |
⚠️ 部分支持 | -a 或 --preserve=all |
rsync 版本注意 |
⚠️ 不同版本 ACL 保存能力有差异 | 测试后再投入生产 |
# tar 备份时保留 ACL
tar --acls -czf backup.tar.gz /data/project
# rsync 同步保留 ACL
rsync -avA /data/project user@backup:/backup/
8.3 与版本控制工具(Git)
Git 不支持记录 ACL。将 ACL 配置脚本纳入仓库管理:
# 仓库中保存 setup-acl.sh
#!/bin/bash
setfacl -R -m u:alice:rwx /var/www/project
setfacl -R -m g:devops:rx /var/www/project
9. 常见陷阱与排查
9.1 陷阱一:递归设置不影响已存在文件
# 错误认知:设置了目录的默认 ACL,已存在的子文件就有了权限
setfacl -m d:u:alice:rw /data/project # 只影响未来文件!
# 正确做法:先递归添加 ACL
setfacl -R -m u:alice:rw /data/project
setfacl -m d:u:alice:rw /data/project
9.2 陷阱二:掩码“吃掉”了权限
# 症状:明明设置了 alice:rwx,实际只有 r--
$ getfacl file.txt
user:alice:rwx
mask::r--
# 有效权限 = alice:rwx & mask:r-- = r--
# 解决:重置掩码
setfacl -m mask::rwx file.txt
9.3 陷阱三:FTP/SFTP 客户端不保留 ACL
# 症状:通过 FTP 上传的文件没有 ACL
# 解决方案
# 1. 使用 scp/rsync 替代 FTP
# 2. 服务器端设置目录默认 ACL
setfacl -m d:u:alice:rw /incoming
9.4 陷阱四:ACL 条目顺序敏感
ACL 条目的顺序影响 getfacl 的输出,但不影响内核的权限检查顺序。内核按以下固定顺序检查:
- owner
- 命名用户
- owning group 或命名组
- other
9.5 排查命令汇总
# 检查文件是否设置了 ACL
ls -l file.txt
# 输出中权限位后的 '+' 表示有扩展 ACL
# 查看详细信息
getfacl file.txt
# 检查文件系统是否支持 ACL
mount | grep -w "acl"
# 查看内核是否启用 ACL 支持
grep ACL /boot/config-$(uname -r)
10. 最佳实践总结
10.1 核心原则
| 原则 | 说明 |
|---|---|
| 最小权限 | 只授予完成工作所需的最小权限 |
| 默认 ACL 优先 | 目录应优先使用默认 ACL 而非递归设置 |
| 组优于用户 | 优先使用组 ACL,避免用户 ACL 膨胀 |
| 定期审计 | getfacl -R /important > acl_backup.txt 定期备份 |
10.2 权限设计决策树
graph TD
A[需要设置权限] --> B{是否只为 owner/group/other?}
B -->|是| C[使用传统 chmod]
B -->|否| D{需要几个额外主体?}
D -->|少量| E[使用命名用户/组 ACL]
D -->|大量| F[考虑新建专用组]
C --> G[传统 UGO 模式]
E --> H[ACL 扩展模式]
F --> G
10.3 常用命令速查
| 操作 | 命令 |
|---|---|
| 查看 ACL | getfacl <file> |
| 添加用户权限 | setfacl -m u:alice:rw <file> |
| 添加组权限 | setfacl -m g:dev:rx <dir> |
| 移除用户 | setfacl -x u:alice <file> |
| 移除所有扩展 | setfacl -b <file> |
| 设置默认 ACL | setfacl -m d:u:alice:rw <dir> |
| 递归修改 | setfacl -R -m u:alice:rw <dir> |
| 备份 ACL | getfacl -R <dir> > backup.acl |
| 恢复 ACL | setfacl --restore=backup.acl |
10.4 检查清单
部署 ACL 前,确认以下事项:
- 文件系统挂载时启用了 ACL(
mount | grep acl) - 备份策略包含了 ACL(tar
--acls/ rsync-A) - 已设置默认 ACL 的目录,同时处理了已存在的子文件
- 掩码(mask)未意外限制所需权限
- ACL 变更已通过版本控制记录(如
setup-acl.sh脚本)
ACL 是传统权限模型的自然扩展,而不是替代。在绝大多数场景下,传统的 UGO + umask 仍是最简洁的选择。当需求超出传统模型时,ACL 提供了精细化的解决方案,但也要清醒地认识到:权限越精细,管理复杂度越高。在生产环境中,应先问自己“传统 chmod 真的不够用吗?”,确认后再引入 ACL。
原文 https://blog.csdn.net/2301_79518550/article/details/147806368