13.3 主机的细部权限规划:ACL 的使用

第五章开始,我们就一直强调 Linux 的权限概念是非常重要的! 但是传统的权限仅有三种身份 (owner, group, others) 搭配三种权限 (r,w,x) 而已,并没有办法单纯的针对某一个使用者或某一个群组来设置特定的权限需求,例如前一小节最后的那个任务! 此时就得要使用 ACL 这个机制啦!这玩意挺有趣的,下面我们就来谈一谈:

13.3.1 什么是 ACL 与如何支持启动 ACL

ACL 是 Access Control List 的缩写,主要的目的是在提供传统的 owner,group,others 的 read,write,execute 权限之外的细部权限设置。ACL 可以针对单一使用者,单一文件或目录来进行 r,w,x 的权限规范,对于需要特殊权限的使用状况非常有帮助。

那 ACL 主要可以针对哪些方面来控制权限呢?他主要可以针对几个项目:

  • 使用者 (user):可以针对使用者来设置权限;
  • 群组 (group):针对群组为对象来设置其权限;
  • 默认属性 (mask):还可以针对在该目录下在创建新文件/目录时,规范新数据的默认权限;

也就是说,如果你有一个目录,需要给一堆人使用,每个人或每个群组所需要的权限并不相同时,在过去,传统的 Linux 三种身份的三种权限是无法达到的, 因为基本上,传统的 Linux 权限只能针对一个用户、一个群组及非此群组的其他人设置权限而已,无法针对单一用户或个人来设计权限。 而 ACL 就是为了要改变这个问题啊!好了,稍微了解之后,再来看看如何让你的文件系统可以支持 ACL 吧!

  • 如何启动 ACL

事实上,原本 ACL 是 unix-like 操作系统的额外支持项目,但因为近年以来 Linux 系统对权限细部设置的热切需求, 因此目前 ACL 几乎已经默认加入在所有常见的 Linux 文件系统的挂载参数中 (ext2/ext3/ext4/xfs等等)!所以你无须进行任何动作, ACL 就可以被你使用啰!不过,如果你不放心系统是否真的有支持 ACL 的话,那么就来检查一下核心挂载时显示的信息吧!

[root@study ~]# dmesg | grep -i acl
[    0.330377] systemd[1]: systemd 208 running in system mode. (+PAM +LIBWRAP +AUDIT
+SELINUX +IMA +SYSVINIT +LIBCRYPTSETUP +GCRYPT +ACL +XZ)
[    0.878265] SGI XFS with ACLs, security attributes, large block/inode numbers, no
debug enabled

瞧!至少 xfs 已经支持这个 ACL 的功能啰!

13.3.2 ACL 的设置技巧: getfacl, setfacl

好了,既然知道我们的 filesystem 有支持 ACL 之后,接下来该如何设置与观察 ACL 呢? 很简单,利用这两个指令就可以了:

  • getfacl:取得某个文件/目录的 ACL 设置项目;
  • setfacl:设置某个目录/文件的 ACL 规范。

先让我们来瞧一瞧 setfacl 如何使用吧!

  • setfacl 指令用法介绍及最简单的“ u:帐号:权限 ”设置
[root@study ~]# setfacl [-bkRd] [{-m|-x} acl参数] 目标文件名
选项与参数:
-m :设置后续的 acl 参数给文件使用,不可与 -x 合用;
-x :删除后续的 acl 参数,不可与 -m 合用;
-b :移除“所有的” ACL 设置参数;
-k :移除“默认的” ACL 参数,关于所谓的“默认”参数于后续范例中介绍;
-R :递回设置 acl ,亦即包括次目录都会被设置起来;
-d :设置“默认 acl 参数”的意思!只对目录有效,在该目录新建的数据会引用此默认值

上面谈到的是 acl 的选项功能,那么如何设置 ACL 的特殊权限呢?特殊权限的设置方法有很多, 我们先来谈谈最常见的,就是针对单一使用者的设置方式:

# 1\. 针对特定使用者的方式:
# 设置规范:“ u:[使用者帐号列表]:[rwx] ”,例如针对 vbird1 的权限规范 rx :
[root@study ~]# touch acl_test1
[root@study ~]# ll acl_test1
-rw-r--r--. 1 root root 0 Jul 21 17:33 acl_test1
[root@study ~]# setfacl -m u:vbird1:rx acl_test1
[root@study ~]# ll acl_test1
-rw-r-xr--+ 1 root root 0 Jul 21 17:33 acl_test1
# 权限部分多了个 + ,且与原本的权限 (644) 看起来差异很大!但要如何查阅呢?

[root@study ~]# setfacl -m u::rwx acl_test1
[root@study ~]# ll acl_test1
-rwxr-xr--+ 1 root root 0 Jul 21 17:33 acl_test1
# 设置值中的 u 后面无使用者列表,代表设置该文件拥有者,所以上面显示 root 的权限成为 rwx 了!

上述动作为最简单的 ACL 设置,利用“ u:使用者:权限 ”的方式来设置的啦!设置前请加上 -m 这个选项。 如果一个文件设置了 ACL 参数后,他的权限部分就会多出一个 + 号了!但是此时你看到的权限与实际权限可能就会有点误差! 那要如何观察呢?就通过 getfacl 吧!

  • getfacl 指令用法
[root@study ~]# getfacl filename
选项与参数:
getfacl 的选项几乎与 setfacl 相同!所以鸟哥这里就免去了选项的说明啊!

# 请列出刚刚我们设置的 acl_test1 的权限内容:
[root@study ~]# getfacl acl_test1
# file: acl_test1   <==说明文档名而已!
# owner: root       <==说明此文件的拥有者,亦即 ls -l 看到的第三使用者字段
# group: root       <==此文件的所属群组,亦即 ls -l 看到的第四群组字段
user::rwx           <==使用者列表栏是空的,代表文件拥有者的权限
user:vbird1:r-x     <==针对 vbird1 的权限设置为 rx ,与拥有者并不同!
group::r--          <==针对文件群组的权限设置仅有 r
mask::r-x           <==此文件默认的有效权限 (mask)
other::r--          <==其他人拥有的权限啰!

上面的数据非常容易查阅吧?显示的数据前面加上 # 的,代表这个文件的默认属性,包括文件名、文件拥有者与文件所属群组。 下面出现的 user, group, mask, other 则是属于不同使用者、群组与有效权限(mask)的设置值。 以上面的结果来看,我们刚刚设置的 vbird1 对于这个文件具有 r 与 x 的权限啦!这样看的懂吗? 如果看的懂的话,接下来让我们在测试其他类型的 setfacl 设置吧!

  • 特定的单一群组的权限设置:“ g:群组名:权限 ”
# 2\. 针对特定群组的方式:
# 设置规范:“ g:[群组列表]:[rwx] ”,例如针对 mygroup1 的权限规范 rx :
[root@study ~]# setfacl -m g:mygroup1:rx acl_test1
[root@study ~]# getfacl acl_test1
# file: acl_test1
# owner: root
# group: root
user::rwx
user:vbird1:r-x
group::r--
group:mygroup1:r-x  <==这里就是新增的部分!多了这个群组的权限设置!
mask::r-x
other::r--
  • 针对有效权限设置:“ m:权限 ”

基本上,群组与使用者的设置并没有什么太大的差异啦!如上表所示,非常容易了解意义。不过,你应该会觉得奇怪的是, 那个 mask 是什么东西啊?其实他有点像是“有效权限”的意思!他的意义是: 使用者或群组所设置的权限必须要存在于 mask 的权限设置范围内才会生效,此即“有效权限 (effective permission)” 我们举个例子来看,如下所示:

# 3\. 针对有效权限 mask 的设置方式:
# 设置规范:“ m:[rwx] ”,例如针对刚刚的文件规范为仅有 r :
[root@study ~]# setfacl -m m:r acl_test1
[root@study ~]# getfacl acl_test1
# file: acl_test1
# owner: root
# group: root
user::rwx
user:vbird1:r-x        #effective:r-- <==vbird1+mask均存在者,仅有 r 而已,x 不会生效
group::r--
group:mygroup1:r-x     #effective:r--
mask::r--
other::r--

您瞧,vbird1 与 mask 的集合发现仅有 r 存在,因此 vbird1 仅具有 r 的权限而已,并不存在 x 权限!这就是 mask 的功能了!我们可以通过使用 mask 来规范最大允许的权限,就能够避免不小心开放某些权限给其他使用者或群组了。 不过,通常鸟哥都是将 mask 设置为 rwx 啦!然后再分别依据不同的使用者/群组去规范她们的权限就是了。

例题:将前一小节任务二中 /srv/projecta 这个目录,让 myuser1 可以进入查阅,但 myuser1 不具有修改的权力。答:由于 myuser1 是独立的使用者与群组,因此无法使用传统的 Linux 权限设置。此时使用 ACL 的设置如下:

# 1\. 先测试看看,使用 myuser1 能否进入该目录?
[myuser1@study ~]$ cd /srv/projecta
-bash: cd: /srv/projecta: Permission denied  <==确实不可进入!

# 2\. 开始用 root 的身份来设置一下该目录的权限吧!
[root@study ~]# setfacl -m u:myuser1:rx /srv/projecta
[root@study ~]# getfacl /srv/projecta
# file: srv/projecta
# owner: root
# group: projecta
# flags: -s-
user::rwx
user:myuser1:r-x  <==还是要看看有没有设置成功喔!
group::rwx
mask::rwx
other::---

# 3\. 还是得要使用 myuser1 去测试看看结果!
[myuser1@study ~]$ cd /srv/projecta
[myuser1@study projecta]$ ll -a
drwxrws---+ 2 root projecta 4096 Feb 27 11:29 .  <==确实可以查询文件名
drwxr-xr-x  4 root root     4096 Feb 27 11:29 ..

[myuser1@study projecta]$ touch testing
touch: cannot touch `testing': Permission denied <==确实不可以写入!

请注意,上述的 1, 3 步骤使用 myuser1 的身份,2步骤才是使用 root 去设置的!

上面的设置我们就完成了之前任务二的后续需求喔!这么简单呢!接下来让我们来测试一下,如果我用 root 或者是 pro1 的身份去 /srv/projecta 增加文件或目录时,该文件或目录是否能够具有 ACL 的设置? 意思就是说,ACL 的权限设置是否能够被次目录所“继承?”先试看看:

[root@study ~]# cd /srv/projecta
[root@study ~]# touch abc1
[root@study ~]# mkdir abc2
[root@study ~]# ll -d abc*
-rw-r--r--. 1 root projecta 0 Jul 21 17:49 abc1
drwxr-sr-x. 2 root projecta 6 Jul 21 17:49 abc2

你可以明显的发现,权限后面都没有 + ,代表这个 acl 属性并没有继承喔!如果你想要让 acl 在目录下面的数据都有继承的功能,那就得如下这样做了!

  • 使用默认权限设置目录未来文件的 ACL 权限继承“ d:[u|g]:[user|group]:权限 ”
# 4\. 针对默认权限的设置方式:
# 设置规范:“ d:[ug]:使用者列表:[rwx] ”

# 让 myuser1 在 /srv/projecta 下面一直具有 rx 的默认权限!
[root@study ~]# setfacl -m d:u:myuser1:rx /srv/projecta
[root@study ~]# getfacl /srv/projecta
# file: srv/projecta
# owner: root
# group: projecta
# flags: -s-
user::rwx
user:myuser1:r-x
group::rwx
mask::rwx
other::---
default:user::rwx
default:user:myuser1:r-x
default:group::rwx
default:mask::rwx
default:other::---

[root@study ~]# cd /srv/projecta
[root@study projecta]# touch zzz1
[root@study projecta]# mkdir zzz2
[root@study projecta]# ll -d zzz*
-rw-rw----+ 1 root projecta 0 Jul 21 17:50 zzz1
drwxrws---+ 2 root projecta 6 Jul 21 17:51 zzz2
# 看吧!确实有继承喔!然后我们使用 getfacl 再次确认看看!

[root@study projecta]# getfacl zzz2
# file: zzz2
# owner: root
# group: projecta
# flags: -s-
user::rwx
user:myuser1:r-x
group::rwx
mask::rwx
other::---
default:user::rwx
default:user:myuser1:r-x
default:group::rwx
default:mask::rwx
default:other::---

通过这个“针对目录来设置的默认 ACL 权限设置值”的项目,我们可以让这些属性继承到次目录下面呢! 非常方便啊!那如果想要让 ACL 的属性全部消失又要如何处理?通过“ setfacl -b 文件名 ”即可啦! 太简单了!鸟哥就不另外介绍了!请自行测试测试吧!

问:针对刚刚的 /srv/projecta 目录的权限设置中,我需要 1)取消 myuser1 的设置(连同默认值),以及 2)我不能让 pro3 这个用户使用该目录,亦即 pro3 在该目录下无任何权限, 该如何设置?答:取消全部的 ACL 设置可以使用 -b 来处理,但单一设置值的取消,就得要通过 -x 才行了!所以你应该这样作:

# 1.1 找到针对 myuser1 的设置值
[root@study ~]# getfacl /srv/projecta | grep myuser1
user:myuser1:r-x
default:user:myuser1:r-x

# 1.2 针对每个设置值来处理,注意,取消某个帐号的 ACL 时,不需要加上权限项目!
[root@study ~]# setfacl -x u:myuser1 /srv/projecta
[root@study ~]# setfacl -x d:u:myuser1 /srv/projecta

# 2.1 开始让 pro3 这个用户无法使用该目录啰!
[root@study ~]# setfacl -m u:pro3:- /srv/projecta

只需要留意,当设置一个用户/群组没有任何权限的 ACL 语法中,在权限的字段不可留白,而是应该加上一个减号 (-) 才是正确的作法!