Skip to content

ACL 访问控制权限

字数: 4727 字 时长: 18 分钟

在 Linux 系统中,传统的权限控制基于三种身份与三种权限的组合:

  • 三种身份指的是文件所有者、所属群组和其他用户;
  • 三种权限则是读(r)、写(w)和执行(x)。

然而在实际应用场景里,这种基于三种身份的权限管理模式常常捉襟见肘。以某企业内部协作场景为例:

公司服务器上有一个 /shared-projects 目录,存放着研发部门的重要项目资料。部门主管作为目录所有者,需具备 rwx 全权限;研发团队成员加入 dev-team 组,作为属组拥有 rwx 权限;其他部门员工则应完全禁止访问,即权限设为 ---。​

某天,一位来自合作公司的技术顾问 guest_tech 需要临时查阅该目录中的部分文档。他仅需 rx 权限,以便浏览和进入目录,但不能赋予 w 权限,避免误操作修改文件。若将其设为目录所有者,会挤占主管权限;加入 dev-team 组,又因组权限为 rwx 而存在风险;若调整「其他用户」权限为 r-x,则所有非研发部门人员都能访问,显然都不可行。​

此时,Linux 系统中的 ACL 便派上用场。ACL 突破传统权限模型限制,允许为单一用户或用户组单独设置文件访问权限。针对 guest_tech 顾问的需求,通过 ACL 权限控制,可直接为其账户分配 r-x 权限,精准满足临时协作需求,同时保障目录整体安全性。这意味着,在 Linux 权限管理中,除了传统的「三种身份 + 三种权限」模式,ACL 提供了更灵活、更精细的权限控制方案。

setfacl 命令

setfacl 是 Linux 系统中用于设置文件和目录 ACL(访问控制列表)权限的核心命令。与传统的 chmod 相比,ACL 允许对特定用户或用户组设置更精细的权限,这些权限可以独立于传统的 rwx 权限模型。

shell
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限制特定用户 / 组的最大有效权限(实际权限 = 用户权限 ∩ 掩码)。
  1. 为用户 consultant 设置 r-x 权限:

    shell
    setfacl -m u:consultant:r-x /project
  2. 为组 developers 设置 rw- 权限:

    shell
    setfacl -m g:developers:rw- /project
  3. 为目录 /project 设置默认 ACL 规则,使得新创建的文件和子目录自动继承这些规则:

    shell
    setfacl -d -m u:consultant:r-x /project
  4. 删除用户 consultant 的 ACL 规则:

    shell
    setfacl -x u:consultant /project
  5. 删除 /project 的所有非默认 ACL 规则,恢复到默认状态:

    shell
    setfacl -b /project
  6. 递归地为目录 /project 及其所有子目录和文件设置 ACL 规则:

    shell
    setfacl -R -m u:consultant:r-x /project

可以结合之前参考的例子,设置一个具体的 ACL,服务器上的 /shared-projects 目录需满足以下权限要求:

  • 部门主管(supervisor):作为目录所有者,拥有完全控制权限(rwx)。
  • 研发团队(dev-team):所属组,成员需具备读写执行权限(rwx)。
  • 其他部门员工:包括外部顾问,默认无任何访问权限(---)。

合作公司技术顾问 guest_tech 需临时访问该目录,要求:

  • 仅允许浏览目录内容(r)和进入目录(x),禁止写入(w)。
  • 不能通过传统权限(所有者、所属组、其他用户)实现,需借助 ACL(访问控制列表)。

这里就可以通过 ACL 为 guest_tech 单独设置权限,不影响现有传统权限体系,例如:

  1. 环境初始化

    创建用户和组:

    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
  2. 使用 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
  3. 验证 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
  4. 权限回收(项目结束后)

    删除 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(用于新创建的文件 / 目录)。

shell
getfacl [选项] 文件/目录
选项描述
-a显示所有 ACL 规则(默认选项)。
-e显示有效权限(Effective Permissions),即实际生效的权限。
-t显示文件类型(如d表示目录,-表示普通文件)。
-R递归(Recursive)显示目录及其子目录和文件的 ACL 规则。
-n不解析用户和组的名称,直接显示用户 ID 和组 ID。
-p显示权限时,不显示文件名。
-c不显示注释信息,仅显示规则。
-k不显示默认 ACL 规则。

例如,查看 /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
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 授予 读和执行权限(无写权限):

shell
[root@localhost ~]# setfacl -m u:guest_tech:r-x /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
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/ 文件权限:

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::---

在没有设置默认 ACL 之前,先创建目录和文件:

shell
[root@localhost ~]# mkdir /shared-projects/acl_dir
[root@localhost ~]# touch /shared-projects/acl_file
shell
[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:

shell
[root@localhost ~]# setfacl -d -m u:guest_tech:r-x /shared-projects
  • -d:表示设置默认 ACL(仅对新创建的文件或子目录生效)。
  • -m u:guest_tech:r-x:为用户 guest_tech 设置读执行权限(r-x)。
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::---
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 规则)。

新文件

例如,创建一个新文件:

shell
[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_fileother 权限也会直接继承为 ---

shell
[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 规则)。

例如,创建一个新子目录:

shell
[root@localhost ~]# mkdir /shared-projects/def_dir
shell
[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):

shell
[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:

shell
[root@localhost ~]# setfacl -k /shared-projects
shell
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 设置:

shell
[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::---
shell
[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):

shell
[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:

shell
[root@localhost ~]# setfacl -b /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::---

可以看到,所有 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)操作,最终的实际权限是用户或组的权限与掩码的交集

text
实际生效的权限 = 「特定用户/组的权限」 ∩ 掩码的权限
  • 如果掩码是 r-x,那么用户或组的权限最多只能是 r-x,即使它们被赋予了 rwx 权限。
  • 如果掩码是 rwx,那么用户或组的权限将不受限制。
  • 若掩码为 r--,则所有用户和组的写权限和执行权限都会被完全禁用。

可以通过 setfacl 命令可以手动设置掩码:

shell
setfacl -m mask::rwx file

如果没有手动设置掩码,会自动创建掩码。当添加或修改特定用户或组权限时,掩码会自动更新为所有非所有者权限的并集

text
掩码 = 用户权限 ∪ 组权限 ∪ 所属组默认权限
  • 用户权限:所有通过 setfacl -m u:username:rwx 设置的特定用户权限。
  • 组权限:所有通过 setfacl -m g:groupname:rwx 设置的特定组权限。
  • 所属组默认权限:文件基本权限中的组权限(如 group::r-x)。
  • 文件所有者的权限(user::rwx)和其他用户的权限(other::r--)不参与掩码计算。

假设一个文件的初始权限只有基本的 rwx(无 ACL):

shell
[root@localhost ~]# getfacl acl_mask.txt 
# file: acl_mask.txt
# owner: root
# group: root
user::rw-
group::r--
other::r--

例如,为用户 eva 设置读写权限:

shell
[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 设置读和执行权限:

shell
[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-xrwx = r-x