ACL 访问控制权限
字数: 4727 字 时长: 18 分钟
在 Linux 系统中,传统的权限控制基于三种身份与三种权限的组合:
- 三种身份指的是文件所有者、所属群组和其他用户;
- 三种权限则是读(
r
)、写(w
)和执行(x
)。
然而在实际应用场景里,这种基于三种身份的权限管理模式常常捉襟见肘。以某企业内部协作场景为例:
公司服务器上有一个 /shared-projects
目录,存放着研发部门的重要项目资料。部门主管作为目录所有者,需具备 rwx
全权限;研发团队成员加入 dev-team
组,作为属组拥有 rwx
权限;其他部门员工则应完全禁止访问,即权限设为 ---
。
某天,一位来自合作公司的技术顾问 guest_tech
需要临时查阅该目录中的部分文档。他仅需 r
和 x
权限,以便浏览和进入目录,但不能赋予 w
权限,避免误操作修改文件。若将其设为目录所有者,会挤占主管权限;加入 dev-team
组,又因组权限为 rwx
而存在风险;若调整「其他用户」权限为 r-x
,则所有非研发部门人员都能访问,显然都不可行。
此时,Linux 系统中的 ACL 便派上用场。ACL 突破传统权限模型限制,允许为单一用户或用户组单独设置文件访问权限。针对 guest_tech
顾问的需求,通过 ACL 权限控制,可直接为其账户分配 r-x
权限,精准满足临时协作需求,同时保障目录整体安全性。这意味着,在 Linux 权限管理中,除了传统的「三种身份 + 三种权限」模式,ACL 提供了更灵活、更精细的权限控制方案。
setfacl 命令
setfacl
是 Linux 系统中用于设置文件和目录 ACL(访问控制列表)权限的核心命令。与传统的 chmod
相比,ACL 允许对特定用户或用户组设置更精细的权限,这些权限可以独立于传统的 rwx
权限模型。
setfacl [选项] [权限规则] 文件/目录
常用选项 | 描述 |
---|---|
-m | 修改(Modify)ACL 规则,添加或修改指定的权限。 |
-x | 删除(eXclude)指定的 ACL 规则。 |
-d | 设置默认(Default)ACL 规则,这些规则会自动应用于目录中新建的文件和子目录。 |
-b | 删除(Bulk)所有非默认的 ACL 规则,恢复到默认状态。 |
-k | 删除默认 ACL 规则。 |
-R | 递归(Recursive)应用 ACL 规则到目录及其子目录和文件。 |
-n | 不修改文件的默认 ACL 规则。 |
-M | 从文件中读取 ACL 规则并应用。 |
-X | 从文件中读取 ACL 规则并删除匹配的规则。 |
权限规则类型:
规则类型 | 语法格式 | 示例 | 说明 |
---|---|---|---|
用户基本权限 | user:: 权限 | user::rwx | 文件所有者的权限(对应传统权限位中的第一组)。 |
特定用户权限 | u: 用户名:权限 | u:alice:r-- | 为用户 alice 设置独立权限,覆盖所属组权限。 |
组基本权限 | group:: 权限 | group::r-x | 文件所属组的权限(对应传统权限位中的第二组)。 |
特定组权限 | g: 组名:权限 | g:developers:rw- | 为组 developers 设置独立权限,即使该组不是文件的所属组。 |
其他用户权限 | other:: 权限 | other::--- | 其他用户的权限(对应传统权限位中的第三组)。 |
掩码规则 | m: 权限 | m:r-x | 限制特定用户 / 组的最大有效权限(实际权限 = 用户权限 ∩ 掩码)。 |
为用户
consultant
设置r-x
权限:shellsetfacl -m u:consultant:r-x /project
为组
developers
设置rw-
权限:shellsetfacl -m g:developers:rw- /project
为目录
/project
设置默认 ACL 规则,使得新创建的文件和子目录自动继承这些规则:shellsetfacl -d -m u:consultant:r-x /project
删除用户
consultant
的 ACL 规则:shellsetfacl -x u:consultant /project
删除
/project
的所有非默认 ACL 规则,恢复到默认状态:shellsetfacl -b /project
递归地为目录
/project
及其所有子目录和文件设置 ACL 规则:shellsetfacl -R -m u:consultant:r-x /project
可以结合之前参考的例子,设置一个具体的 ACL,服务器上的 /shared-projects
目录需满足以下权限要求:
- 部门主管(supervisor):作为目录所有者,拥有完全控制权限(
rwx
)。 - 研发团队(dev-team):所属组,成员需具备读写执行权限(
rwx
)。 - 其他部门员工:包括外部顾问,默认无任何访问权限(
---
)。
合作公司技术顾问 guest_tech
需临时访问该目录,要求:
- 仅允许浏览目录内容(r)和进入目录(x),禁止写入(w)。
- 不能通过传统权限(所有者、所属组、其他用户)实现,需借助 ACL(访问控制列表)。
这里就可以通过 ACL 为 guest_tech
单独设置权限,不影响现有传统权限体系,例如:
环境初始化
创建用户和组:
shell[root@localhost ~]# useradd supervisor [root@localhost ~]# useradd dev1 [root@localhost ~]# useradd dev2 [root@localhost ~]# useradd guest_tech
shell[root@localhost ~]# groupadd dev-team [root@localhost ~]# usermod -aG dev-team dev1 [root@localhost ~]# usermod -aG dev-team dev2
创建项目目录并设置权限:
shell[root@localhost ~]# mkdir /shared-projects [root@localhost ~]# echo "hello,acl" > /shared-projects/test.txt [root@localhost ~]# chmod 750 /shared-projects/ [root@localhost ~]# chown supervisor:dev-team /shared-projects [root@localhost ~]# ll -d /shared-projects drwxr-x---. 2 supervisor dev-team 22 Nov 18 09:42 /shared-projects
验证初始权限(此时,非
dev-team
成员无法访问该目录):shell[root@localhost ~]# su - guest_tech -c "ls /shared-projects" ls: cannot open directory '/shared-projects': Permission denied
使用 ACL 为
guest_tech
授权单独为
guest_tech
设置r-x
权限:shell[root@localhost ~]# setfacl -m u:guest_tech:r-x /shared-projects
验证 ACL:
shell[root@localhost ~]# getfacl /shared-projects getfacl: Removing leading '/' from absolute path names # file: shared-projects # owner: supervisor # group: dev-team user::rwx user:guest_tech:r-x group::r-x mask::r-x other::---
权限位显示
+
表示该目录存在 ACL:shell[root@localhost ~]# ll -d /shared-projects drwxr-x---+ 2 supervisor dev-team 22 Nov 18 09:42 /shared-projects
验证
guest_tech
的访问权限shell[root@localhost ~]# su - guest_tech -c "ls /shared-projects" test.txt
可以看到
guest_tech
可浏览目录,但是其他非授权用户被拒绝:shell[root@localhost ~]# useradd tom [root@localhost ~]# su - tom -c "ls /shared-projects" ls: cannot open directory '/shared-projects': Permission denied
权限回收(项目结束后)
删除
guest_tech
的 ACL 权限:shell[root@localhost ~]# setfacl -x u:guest_tech /shared-projects
shell[root@localhost ~]# getfacl /shared-projects getfacl: Removing leading '/' from absolute path names # file: shared-projects # owner: supervisor # group: dev-team user::rwx group::r-x other::---
getfacl 命令
getfacl
是 Linux 系统中用于查看文件或目录 ACL(访问控制列表)权限的命令。与传统的 ls -l 只能显示基础权限不同,getfacl 能展示完整的 ACL 规则,包括针对特定用户 / 组的扩展权限以及默认 ACL(用于新创建的文件 / 目录)。
getfacl [选项] 文件/目录
选项 | 描述 |
---|---|
-a | 显示所有 ACL 规则(默认选项)。 |
-e | 显示有效权限(Effective Permissions),即实际生效的权限。 |
-t | 显示文件类型(如d 表示目录,- 表示普通文件)。 |
-R | 递归(Recursive)显示目录及其子目录和文件的 ACL 规则。 |
-n | 不解析用户和组的名称,直接显示用户 ID 和组 ID。 |
-p | 显示权限时,不显示文件名。 |
-c | 不显示注释信息,仅显示规则。 |
-k | 不显示默认 ACL 规则。 |
例如,查看 /shared-projects 目录的 ACL 规则:
[root@localhost ~]# getfacl /shared-projects/
getfacl: Removing leading '/' from absolute path names
# file: shared-projects/
# owner: supervisor
# group: dev-team
user::rwx
group::r-x
other::---
getfacl: Removing leading '/' from absolute path names
:这是一条警告信息,表明getfacl
在处理路径时,自动去掉了路径前面的/
(绝对路径的根符号)。这只是一个提示,不会影响命令的执行结果。它只是告诉,getfacl
会将路径视为相对路径来处理。
这表明 /shared-projects/
目录的权限设置为 rwxr-x---
(对应数字权限 750),且未配置任何扩展 ACL 规则(即无特定用户 /
组的额外权限)。
在 getfacl
命令的输出中,user::
、group::
、other::
分别表示文件或目录的三种基本权限类型。如果为用户 guest_tech
授予 读和执行权限(无写权限):
[root@localhost ~]# setfacl -m u:guest_tech:r-x /shared-projects
[root@localhost ~]# getfacl /shared-projects
getfacl: Removing leading '/' from absolute path names
# file: shared-projects
# owner: supervisor
# group: dev-team
user::rwx
user:guest_tech:r-x
group::r-x
mask::r-x
other::---
可以看到多了一条 user:guest_tech:r-x
,表示用户 guest_tech
被授予了读和执行权限。
默认 ACL 规则
默认 ACL(访问控制列表)是 Linux 系统中针对目录的一种特殊权限设置。当为目录设置了默认 ACL 规则时,这些规则会自动应用于该目录中新创建的文件和子目录。换句话说,新创建的文件或子目录会继承目录的默认 ACL 规则,从而确保目录中的所有内容在权限管理上保持一致性。
默认 ACL 规则主要用于目录,而不是普通文件。它是一种「模板」权限设置,用于简化权限管理,避免每次创建新文件或子目录时都需要手动设置 ACL。
当为目录设置默认 ACL 时,如果未显式指定某些权限规则,系统会根据现有的传统权限模型(chmod
设置的权限)和已有的 ACL 规则自动推导出其他未显式指定的权限规则。
当前 /shared-projects/
文件权限:
[root@localhost ~]# getfacl /shared-projects/
getfacl: Removing leading '/' from absolute path names
# file: shared-projects/
# owner: supervisor
# group: dev-team
user::rwx
group::r-x
other::---
在没有设置默认 ACL 之前,先创建目录和文件:
[root@localhost ~]# mkdir /shared-projects/acl_dir
[root@localhost ~]# touch /shared-projects/acl_file
[root@localhost ~]# ll /shared-projects/ | grep "acl"
drwxr-xr-x. 2 root root 6 May 20 10:40 acl_dir
-rw-r--r--. 1 root root 0 May 20 10:40 acl_file
可以看到权限位末尾没有 +
,表示未启用 ACL 权限,权限完全由传统三组(所有者、所属组、其他用户)控制。此时新创建的子文件或子目录不会继承父目录的 ACL 权限(因为父目录尚未设置 ACL)。
然后为 /shared-projects
目录添加默认 ACL:
[root@localhost ~]# setfacl -d -m u:guest_tech:r-x /shared-projects
-d
:表示设置默认 ACL(仅对新创建的文件或子目录生效)。-m u:guest_tech:r-x
:为用户guest_tech
设置读执行权限(r-x
)。
[root@localhost ~]# getfacl /shared-projects
getfacl: Removing leading '/' from absolute path names
# file: shared-projects
# owner: supervisor
# group: dev-team
user::rwx
group::r-x
other::---
default:user::rwx
default:user:guest_tech:r-x
default:group::r-x
default:mask::r-x
default:other::---
在目录上设置的默认 ACL(带 default:
前缀的规则)仅对新文件或子目录生效,且具有以下行为差异:
- 新文件:继承默认 ACL 中的访问权限规则(去掉
default:
前缀),但不会拥有自身的默认 ACL(因为文件无法包含子文件或者目录)。 - 新子目录:不仅继承访问权限规则,还会自动生成完全相同的默认 ACL(即递归应用默认 ACL 规则)。
新文件
例如,创建一个新文件:
[root@localhost ~]# touch /shared-projects/def_file
[root@localhost ~]# ll /shared-projects/ | grep "def_filef"
-rw-r-----+ 1 root root 0 May 20 11:01 def_file
可以看到 other
的权限变为 ---
,这是因为父目录 /shared-projects
的默认 ACL 规则中,other
权限被设置为 ---
(无权限)。因此,新创建的文件 def_file
的 other
权限也会直接继承为 ---
。
[root@localhost ~]# getfacl /shared-projects/def_file
getfacl: Removing leading '/' from absolute path names
# file: shared-projects/def_file
# owner: root
# group: root
user::rw-
user:guest_tech:r-x #effective:r--
group::r-x #effective:r--
mask::r--
other::---
可以注意到 mask::r-x
变成了 mask::r--
,这是因为目录的 mask::r-x
表示「组和 guest_tech
用户可进入目录」,而文件继承此规则后,因「文件默认不可执行」,执行位被自动移除,变为 mask::r--
。
其中,#effective
表示某个权限的实际生效值。即使 ACL 中定义了某些权限,但由于掩码(mask)的限制,实际生效的权限可能会有所不同。#effective
提供了一个清晰的指示,说明实际生效的权限是什么。
user:guest_tech:r-x
的实际生效权限是#effective:r--
。group::r-x
的实际生效权限也是#effective:r--
。
这是因为文件的 mask
值是 r--
,而掩码的作用是限制所属组和 ACL 用户的最大有效权限。即使 ACL 中定义了 r-x
,但由于掩码的限制,实际生效的权限只能是 r--
。
新子目录
新子目录不仅会继承访问权限规则,还会自动生成完全相同的默认 ACL(即递归应用默认 ACL 规则)。
例如,创建一个新子目录:
[root@localhost ~]# mkdir /shared-projects/def_dir
[root@localhost ~]# getfacl /shared-projects/def_dir/
getfacl: Removing leading '/' from absolute path names
# file: shared-projects/def_dir/
# owner: root
# group: root
user::rwx
user:guest_tech:r-x
group::r-x
mask::r-x
other::---
default:user::rwx
default:user:guest_tech:r-x
default:group::r-x
default:mask::r-x
可以看到:
- 子目录继承了父目录的访问权限规则。
- 子目录也继承了父目录的默认 ACL 规则,确保其内部新创建的文件或子目录也会遵循相同的权限设置。
删除默认 ACL
删除默认 ACL 可以通过 setfacl
命令的 -k
和 -b
选项实现。
-k:
-k
选项用于删除目录的默认 ACL 规则,但不会影响当前目录的其他 ACL 规则。这意味着默认 ACL 被清除后,新创建的文件和子目录将不再继承任何默认 ACL 规则,而是遵循传统的 chmod
权限模型。
例如,目录 /shared-projects
的 ACL 如下(添加一个 ACL):
[root@localhost ~]# setfacl -m u:guest_tech:r-x /shared-projects
[root@localhost ~]# getfacl /shared-projects/
getfacl: Removing leading '/' from absolute path names
# file: shared-projects/
# owner: supervisor
# group: dev-team
user::rwx
user:guest_tech:r-x
group::r-x
mask::r-x
other::---
default:user::rwx
default:user:guest_tech:r-x
default:group::r-x
default:mask::r-x
default:other::---
有一个 ACL,还有一个默认 ACL,使用 -k
选项删除默认 ACL:
[root@localhost ~]# setfacl -k /shared-projects
getfacl: Removing leading '/' from absolute path names
# file: shared-projects/
# owner: supervisor
# group: dev-team
user::rwx
user:guest_tech:r-x
group::r-x
mask::r-x
other::---
可以看到,只有默认 ACL 被删除,而当前目录的 ACL 仍然保留,并且不会影响之前已经创建的文件或子目录的 ACL 设置:
[root@localhost ~]# getfacl /shared-projects/def_dir/
getfacl: Removing leading '/' from absolute path names
# file: shared-projects/def_dir/
# owner: root
# group: root
user::rwx
user:guest_tech:r-x
group::r-x
mask::r-x
other::---
default:user::rwx
default:user:guest_tech:r-x
default:group::r-x
default:mask::r-x
default:other::---
[root@localhost ~]# getfacl /shared-projects/def_file
getfacl: Removing leading '/' from absolute path names
# file: shared-projects/def_file
# owner: root
# group: root
user::rw-
user:guest_tech:r-x #effective:r--
group::r-x #effective:r--
mask::r--
other::---
-b:
-b
选项用于删除目录或文件的所有 ACL 规则,包括默认 ACL 和当前的 ACL 规则。使用 -b
选项后,目录或文件的权限将完全恢复到传统的 chmod
权限模型。
假设目录 /shared-projects 的 ACL 如下(添加一个默认 ACL):
[root@localhost ~]# setfacl -d -m u:guest_tech:r-x /shared-projects
[root@localhost ~]# getfacl /shared-projects/
getfacl: Removing leading '/' from absolute path names
# file: shared-projects/
# owner: supervisor
# group: dev-team
user::rwx
user:guest_tech:r-x
group::r-x
mask::r-x
other::---
default:user::rwx
default:user:guest_tech:r-x
default:group::r-x
default:mask::r-x
default:other::---
使用 -b
选项删除所有 ACL:
[root@localhost ~]# setfacl -b /shared-projects
[root@localhost ~]# getfacl /shared-projects/
getfacl: Removing leading '/' from absolute path names
# file: shared-projects/
# owner: supervisor
# group: dev-team
user::rwx
group::r-x
other::---
可以看到,所有 ACL 规则(包括默认 ACL 和当前的 ACL)都被删除,目录的权限恢复到传统的 chmod
权限模型。
区别总结:
选项 | 功能 | 影响范围 |
---|---|---|
-k | 删除默认 ACL | 仅删除目录的默认 ACL 规则,保留当前目录的其他 ACL 规则 |
-b | 删除所有 ACL | 删除目录或文件的所有 ACL 规则,包括默认 ACL 和当前的 ACL 规则 |
掩码
在 Linux 的 ACL(访问控制列表)中,掩码是一个非常重要的概念,它用于限制特定用户和组的实际有效权限。
掩码的限制范围明确指向两类主体:
- 特定用户(named user):通过
setfacl -m user:username:rwx
命令为非文件所有者设置的权限。 - 命名组(named group):通过
setfacl -m group:groupname:rwx
命令为特定组设置的权限。
掩码的作用是确保权限不会被过度扩展,从而增强系统的安全性。即使为某个用户或组设置了较高的权限,掩码会将实际生效的权限限制为掩码所允许的范围。掩码的作用可以简单地理解为一个「过滤器」。它会与用户或组的权限进行逻辑与(AND)操作,最终的实际权限是用户或组的权限与掩码的交集:
实际生效的权限 = 「特定用户/组的权限」 ∩ 掩码的权限
- 如果掩码是
r-x
,那么用户或组的权限最多只能是r-x
,即使它们被赋予了rwx
权限。 - 如果掩码是
rwx
,那么用户或组的权限将不受限制。 - 若掩码为
r--
,则所有用户和组的写权限和执行权限都会被完全禁用。
可以通过 setfacl
命令可以手动设置掩码:
setfacl -m mask::rwx file
如果没有手动设置掩码,会自动创建掩码。当添加或修改特定用户或组权限时,掩码会自动更新为所有非所有者权限的并集:
掩码 = 用户权限 ∪ 组权限 ∪ 所属组默认权限
- 用户权限:所有通过
setfacl -m u:username:rwx
设置的特定用户权限。 - 组权限:所有通过
setfacl -m g:groupname:rwx
设置的特定组权限。 - 所属组默认权限:文件基本权限中的组权限(如
group::r-x
)。 - 文件所有者的权限(
user::rwx
)和其他用户的权限(other::r--
)不参与掩码计算。
假设一个文件的初始权限只有基本的 rwx(无 ACL):
[root@localhost ~]# getfacl acl_mask.txt
# file: acl_mask.txt
# owner: root
# group: root
user::rw-
group::r--
other::r--
例如,为用户 eva
设置读写权限:
[root@localhost ~]# setfacl -m u:eva:rw- acl_mask.txt
[root@localhost ~]# getfacl acl_mask.txt
# file: acl_mask.txt
# owner: root
# group: root
user::rw-
user:eva:rw-
group::r--
mask::rw-
other::r--
mask::rw-
:掩码自动创建,值为rw-
∪r--
=rw-
。
再为组 team
设置读和执行权限:
[root@localhost ~]# setfacl -m g:team:r-x acl_mask.txt
[root@localhost ~]# getfacl acl_mask.txt
# file: acl_mask.txt
# owner: root
# group: root
user::rw-
user:eva:rw-
group::r--
group:team:r-x
mask::rwx
other::r--
mask::rwx
:掩码值为rw-
(用户eva
)、r--
(所属组)和r-x
(组team
)的并集。
掩码权限限制 ACL 中用户或组的最大可用权限,确保权限不会超过文件的所属组基本权限范围,而实际权限还需要和掩码权限进行逻辑与操作:
- 用户
eva
的实际权限:rw-
∩rwx
=rw-
- 组
team
的实际权限:r-x
∩rwx
=r-x