外观
访问控制列表(ACL)详解
访问控制列表(ACL,Access Control List)是文件系统层的细粒度权限:在「属主、属组、其他人」三类之外,可以给任意指定的用户或组单独加权限或禁止。OMV 的 ACL 对话框同时也是修改文件属主、属组和基本权限位的入口。读完这篇,你会知道什么时候该用它、怎么在对话框里安全操作,以及权限被改乱之后怎么恢复。
什么时候需要 ACL
适合用 ACL 的场景:
- 同一个组里要区别对待,比如
users组里的某个孩子只读,其他人读写。 - 限制要对 SFTP、NFS、容器也生效。第 1 层「共享权限」做不到,见 三层权限。
- 子目录的权限要和上级不一样。
- 用户很多的小团队。官方文档的说法是,用户列表很长时 ACL 更合适。
不需要 ACL 的场景:家庭使用、用户少、能用「用户组 + 目录权限位」解决的。官方文档明确说,ACL 不推荐普通家庭用户使用。用得不熟,很容易把原本简单的权限搅乱。
开始之前
- 文件系统要支持 POSIX ACL:EXT4、XFS、Btrfs、JFS、F2FS 支持;NTFS、FAT、exFAT 不支持,访问控制列表按钮是灰的。ZFS 需要数据集开启 POSIX ACL 属性,见 ZFS 插件。
- 读过 三层权限,知道 ACL 是第 3 层。
- 先备份目标目录现有的 ACL,见下文「备份和恢复 ACL」。
- 暂停正在写这个目录的程序,尤其是容器。
ACL 对话框
打开 存储器 → 共享文件夹(Storage → Shared Folders),选中共享文件夹,点击工具栏里的 访问控制列表(Access control list)图标按钮。
| 字段 | 说明 |
|---|---|
| 名称(Name) | 当前共享文件夹,不可修改 |
| 相对路径(Relative path) | 要操作的路径,默认 /,即共享文件夹的根。可以通过浏览选择子目录,下方各项会读出该目录当前真实的 ACL |
| 取代(Replace) | 默认勾选。「取代现存所有权限」:先清除该路径上现有的全部扩展 ACL,再按下面的内容重新写入 |
| 递归(Recursive) | 默认不勾选。「将权限应用到文件与子文件夹」:对路径下所有文件和子目录执行同样的操作 |
| 所有者(Owner)和 权限 | 文件属主及其权限 |
| 用户组(Group)和 权限 | 文件属组及其权限 |
| 其它(Others)和 权限 | 其他所有人的权限。提示文字写着包括匿名 FTP 用户 |
| 用户/组 权限(User/Group permissions) | 表格,一行一个用户或组,列出名称、ID、类型、系统账户(System account)和权限 |
所有者、用户组、其它这几项,以及下面的表格,打开对话框或切换相对路径时,都是从目录当前的真实状态读出来的。所以保存前先看清读出的值是不是你想要的,保存会把整套值(包括没改动的)重新写一遍。
「所有者、用户组、其它」三行的权限下拉有 8 档,对应 rwx 三个位的组合:读 = 4,写 = 2,执行 = 1。对目录来说,读是列出里面有什么,写是新建、删除、重命名,执行是进入。所以实际常用的只有三档:读/写/执行(7)、读/执行(5)、无(0)。
表格里的权限按钮是 读/写(对应 7)、只读(对应 5,即读加执行)、禁止读写(对应 0),和第 1 层的三个按钮名字一样,但这里写进的是文件系统。再点一次已选中的按钮,就取消这一行,也就是不为这个用户或组写条目。表格里包含系统用户和系统组,users 也在其中。
表格上还有 复制权限(Copy permissions)图标按钮:把第 1 层的共享权限整套拷进表格。它会先把表格里所有行清成「未设置」,再按共享权限填入,所以点它之前,先想清楚表格里原有的内容还要不要。复制后还要点 保存(Save)才会生效。
一个完整的例子
目标:共享文件夹 family 里,孩子 kid1 只读,users 组里的其他人照常读写。
- 先备份当前的 ACL,见下文。
- 打开
family的 ACL 对话框,相对路径 保持/。 - 保持 取代 勾选,递归 先不勾选,只改目录本身。
- 上面的所有者、用户组、其它三行保持对话框读出来的值。
- 在表格里找到 kid1,点 只读。
- 点击 保存。保存会在后台运行,完成后弹出通知。这一步直接修改文件系统,不产生待应用的配置更改,所以不需要再点黄色提示条上的 应用(Apply)。
有了命名的用户或组条目,OMV 会同时写入「访问 ACL」和「默认 ACL」,所以之后在这个目录里新建的文件和子目录会自动继承这条规则。
这样改的只是目录本身。已经存在的文件和子目录不会跟着变,要让它们生效就得勾选 递归。递归的后果见下面的警告。
递归加取代会改写整棵目录树,而且没有撤销键
- 影响范围:所选路径的属主、属组、权限位和 ACL。勾选 递归 后,路径下每个文件和每个子目录都被改写,取代 还会清掉它们原有的全部扩展 ACL。文件内容不会被删除,但原有的权限设计会丢失,设错了可能让服务和容器读写失败,或让不该访问的人看到数据。
- 同一套权限位会同时用在文件和目录上。递归应用「读/写/执行」,所有普通文件都会被加上执行位。
- 前置条件:已经用
getfacl -R备份了现有 ACL;先在测试共享文件夹上演练过;暂停了正在写这个目录的程序;不是系统盘、Docker 数据目录或容器的持久化数据目录。官方 wiki 对重置权限的警告也是如此,这些目录改权限可能让系统或容器无法使用。 - 回退:用备份恢复,见下文「备份和恢复 ACL」。没有备份时,可以用 resetperms 插件 重置回默认状态,但它会把所有文件的属主改成
root:users,原有的细分设计无法找回。
先在子目录上试,再扩大范围:备份之后,用 相对路径 选一个小的子目录,勾选 递归 保存,确认结果符合预期(尤其留意文件有没有被加上执行位),再对更大的范围操作。
命令行里的大写 X
如果你熟悉命令行,setfacl -R -m u:<用户名>:rX <路径> 里的大写 X 表示「只给目录或本来就可执行的文件加执行位」(来自 setfacl 手册页),能避免普通文件被递归地变成可执行。OMV 的 ACL 对话框用的是数字权限,没有这个区分。同样,先在测试目录上试,再用到真实数据。
备份和恢复 ACL
下面的命令在 OMV 的 shell(SSH 或本机控制台,root 身份)里运行。getfacl 是只读命令;setfacl --restore 会写入,所以只在需要回退时才用。
备份:
sh
cd /
getfacl -R <共享文件夹的绝对路径> > <备份文件>getfacl 默认去掉路径开头的 /,备份文件里记的是相对路径,所以备份和恢复都要先 cd /。绝对路径可以在共享文件夹列表里点复制图标得到。<备份文件> 放在共享文件夹之外,文件很多时它的体积不小,别塞满系统盘。
恢复:
sh
cd /
setfacl --restore=<备份文件>根据 setfacl 手册页,--restore 会按备份还原 ACL,备份里有属主、属组注释时也会尝试还原属主和属组,并按备份还原 setgid 等特殊位。它还原的是备份时的状态,备份之后新建的文件不在其中。
演练:真实数据前,新建一个测试共享文件夹 acltest,放几个文件和子目录,依次做这些事:备份,用对话框递归加取代地改一遍,用 getfacl 和 ls -l 看变化,用备份恢复,再看一次,确认和修改前一致。这一步没做过,就不要对真实数据递归。
权限被理乱后怎么恢复
按从稳妥到粗暴的顺序:
- 有备份:用上面的
setfacl --restore恢复。 - 想回到 OMV 的默认状态:用 omv-extras 的 resetperms 插件(它是插件,不是 OMV 核心功能,见 小工具合集)。它会递归地把属主和属组改成
root:users,把目录权限设成你选的值(要恢复默认就选「管理员:读/写,用户:读/写,其它:只读」),文件权限则去掉执行位(例如 775 对应文件 664),并且可以选择清除 ACL。它会覆盖所有文件的属主,所以不适合有各自属主的数据,更不能用在容器数据目录和 Docker 目录上。 - 只想清掉 ACL、保留属主和基本权限:
setfacl -R -b <路径>会清除所有扩展 ACL,保留属主、属组和其他人三类基本权限。它是递归的,同样要先备份、先演练。 - 只有个别子目录乱了:在对话框里用 相对路径 选到那个子目录单独处理。
检查结果
在 OMV 的 shell 里用只读命令看 ACL 是否符合预期:
sh
getfacl <共享文件夹的绝对路径>例子(具体数值以你的输出为准):
text
# file: srv/dev-disk-by-uuid-<UUID>/family
# owner: root
# group: users
# flags: -s-
user::rwx
user:kid1:r-x
group::rwx
mask::rwx
other::---
default:user::rwx
default:user:kid1:r-x
default:group::rwx
default:mask::rwx
default:other::---user::rwx、group::rwx、other::---就是对话框上面三行的所有者、用户组、其它。user:kid1:r-x是你加的命名条目。内核检查时,命名用户条目先于组条目,所以即使 kid1 在users组里,也按这条的只读处理。mask::是命名条目和属组条目的权限上限;如果某条权限比 mask 大,getfacl会在后面标注#effective:和实际生效的权限。default:开头的是默认 ACL,决定新建的文件和子目录继承什么。flags: -s-里的s是 setgid。
然后用 kid1 的账号从客户端连上,确认只能读不能写,其他用户不受影响。
常见问题
访问控制列表按钮是灰的。 文件系统不支持 POSIX ACL,比如 NTFS、FAT、exFAT。
设置了 ACL,用户还是写不了。 依次看:第 1 层共享权限(有没有「只读」或没授权)、SMB 共享有没有勾「只读」、路径上更上一级目录有没有挡住(namei -l)、getfacl 里有没有 #effective: 标注。
递归之后,文件都变成可执行了。 数字权限同时用在文件和目录上,这是预期行为。用 resetperms 把文件权限恢复,或者按备份恢复,下次用 X 的命令行方式。
新建的文件没有继承 ACL。 先看 getfacl 里有没有 default: 条目。通过 SMB 创建文件时,权限还受共享的 继承 ACLs(Inherit ACLs)和 继承权限(Inherit permissions)选项影响,见 SMB 进阶。
ACL 和共享权限哪个优先。 两者是不同的层,结果是交集。想从症状入手排查,见 权限错误:Permission denied。
参考资料
- OMV 官方文档:Access Control List (ACL)
- OMV 源码:
ShareMgmt::getFileACL、setFileACL(对话框实际执行的chown和setfacl) - Linux 手册页:setfacl(1)、getfacl(1)、acl(5)
- omv-extras wiki:Reset Permissions 插件