5.5 文件访问控制列表
不知道大家是否发现,前文讲解的一般权限、特殊权限、隐藏权限其实有一个共性—权限是针对某一类用户设置的。如果希望对某个指定的用户进行单独的权限控制,就需要用到文件的访问控制列表(ACL)了。通俗来讲,基于普通文件或目录设置ACL其实就是针对指定的用户或用户组设置文件或目录的操作权限。另外,如果针对某个目录设置了ACL,则目录中的文件会继承其ACL;若针对文件设置了ACL,则文件不再继承其所在目录的ACL。
为了更直观地看到ACL对文件权限控制的强大效果,我们先切换到普通用户,然后尝试进入root管理员的家目录中。在没有针对普通用户对root管理员的家目录设置ACL之前,其执行结果如下所示:
[root@linuxprobe ~]# su - linuxprobe
Last login: Sat Mar 21 16:31:19 CST 2017 on pts/0
[linuxprobe@linuxprobe ~]$ cd /root
-bash: cd: /root: Permission denied
[linuxprobe@linuxprobe root]$ exit
- setfacl命令
setfacl命令用于管理文件的ACL规则,格式为“setfacl [参数] 文件名称”。文件的ACL提供的是在所有者、所属组、其他人的读/写/执行权限之外的特殊权限控制,使用setfacl命令可以针对单一用户或用户组、单一文件或目录来进行读/写/执行权限的控制。其中,针对目录文件需要使用-R递归参数;针对普通文件则使用-m参数;如果想要删除某个文件的ACL,则可以使用-b参数。下面来设置用户在/root目录上的权限:
[root@linuxprobe ~]# setfacl -Rm u:linuxprobe:rwx /root
[root@linuxprobe ~]# su - linuxprobe
Last login: Sat Mar 21 15:45:03 CST 2017 on pts/1
[linuxprobe@linuxprobe ~]$ cd /root
[linuxprobe@linuxprobe root]$ ls
anaconda-ks.cfg Downloads Pictures Public
[linuxprobe@linuxprobe root]$ cat anaconda-ks.cfg
[linuxprobe@linuxprobe root]$ exit
是不是觉得效果很酷呢?但是现在有这样一个小问题—怎么去查看文件上有那些ACL呢?常用的ls命令是看不到ACL表信息的,但是却可以看到文件的权限最后一个点(.)变成了加号(+),这就意味着该文件已经设置了ACL了。现在大家是不是感觉学得越多,越不敢说自己精通Linux系统了吧?就这么一个不起眼的点(.),竟然还表示这么一种重要的权限。
[root@linuxprobe ~]# ls -ld /root
dr-xrwx—+ 14 root root 4096 May 4 2017 /root
2. getfacl命令
getfacl命令用于显示文件上设置的ACL信息,格式为“getfacl 文件名称”。Linux系统中的命令就是这么又可爱又好记。想要设置ACL,用的是setfacl命令;要想查看ACL,则用的是getfacl命令。下面使用getfacl命令显示在root管理员家目录上设置的所有ACL信息。
[root@linuxprobe ~]# getfacl /root
getfacl: Removing leading ‘/’ from absolute path names
file: root
owner: root
group: root
user::r-x
user:linuxprobe:rwx
group::r-x
mask::rwx
other::—
出现问题?大胆提问!
因读者们硬件不同或操作错误都可能导致实验配置出错,请耐心再仔细看看操作步骤吧,不要气馁~
Linux技术交流请加A群:560843(满),B群:340829(推荐),C群:463590(推荐),点此查看全国群。
*本群特色:通过口令验证确保每一个群员都是《Linux就该这么学》的读者,答疑更有针对性,不定期免费领取定制礼品。
5.6 su命令与sudo服务
各位读者在实验环境中很少遇到安全问题,并且为了避免因权限因素导致配置服务失败,从而建议使用root管理员来学习本书,但是在生产环境中还是要对安全多一份敬畏之心,不要用root管理员去做所有事情。因为一旦执行了错误的命令,可能会直接导致系统崩溃,这样一来,不但客户指责、领导批评,没准奖金也会鸡飞蛋打。但转头一想,尽管Linux系统为了安全性考虑,使得许多系统命令和服务只能被root管理员来使用,但是这也让普通用户受到了更多的权限束缚,从而导致无法顺利完成特定的工作任务。
su命令可以解决切换用户身份的需求,使得当前用户在不退出登录的情况下,顺畅地切换到其他用户,比如从root管理员切换至普通用户:
[root@linuxprobe ~]# id
uid=0(root) gid=0(root) groups=0(root)
[root@linuxprobe ~]# su - linuxprobe
Last login: Wed Jan 4 01:17:25 EST 2017 on pts/0
[linuxprobe@linuxprobe ~]$ id
uid=1000(linuxprobe) gid=1000(linuxprobe) groups=1000(linuxprobe) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
细心的读者一定会发现,上面的su命令与用户名之间有一个减号(-),这意味着完全切换到新的用户,即把环境变量信息也变更为新用户的相应信息,而不是保留原始的信息。强烈建议在切换用户身份时添加这个减号(-)。
另外,当从root管理员切换到普通用户时是不需要密码验证的,而从普通用户切换成root管理员就需要进行密码验证了;这也是一个必要的安全检查:
[linuxprobe@linuxprobe root]$ su root
Password:
[root@linuxprobe ~]# su - linuxprobe
Last login: Mon Aug 24 19:27:09 CST 2017 on pts/0
[linuxprobe@linuxprobe ~]$ exit
logout
[root@linuxprobe ~]#
尽管像上面这样使用su命令后,普通用户可以完全切换到root管理员身份来完成相应工作,但这将暴露root管理员的密码,从而增大了系统密码被黑客获取的几率;这并不是最安全的方案。
刘遄老师接下来将介绍如何使用sudo命令把特定命令的执行权限赋予给指定用户,这样既可保证普通用户能够完成特定的工作,也可以避免泄露root管理员密码。我们要做的就是合理配置sudo服务,以便兼顾系统的安全性和用户的便捷性。sudo服务的配置原则也很简单—在保证普通用户完成相应工作的前提下,尽可能少地赋予额外的权限。
sudo命令用于给普通用户提供额外的权限来完成原本root管理员才能完成的任务,格式为“sudo [参数] 命令名称”。sudo服务中可用的参数以及相应的作用如表5-7所示。
表5-7 sudo服务中的可用参数以及作用
参数 作用
-h 列出帮助信息
-l 列出当前用户可执行的命令
-u 用户名或UID值 以指定的用户身份执行命令
-k 清空密码的有效时间,下次执行sudo时需要再次进行密码验证
-b 在后台执行指定的命令
-p 更改询问密码的提示语
总结来说,sudo命令具有如下功能:
限制用户执行指定的命令:
记录用户执行的每一条命令;
配置文件(/etc/sudoers)提供集中的用户管理、权限与主机等参数;
验证密码的后5分钟内(默认值)无须再让用户再次验证密码。
当然,如果担心直接修改配置文件会出现问题,则可以使用sudo命令提供的visudo命令来配置用户权限。这条命令在配置用户权限时将禁止多个用户同时修改sudoers配置文件,还可以对配置文件内的参数进行语法检查,并在发现参数错误时进行报错。
只有root管理员才可以使用visudo命令编辑sudo服务的配置文件。
visudo: >>> /etc/sudoers: syntax error near line 111 <<<
What now?
Options are:
(e)dit sudoers file again
(x)it without saving changes to sudoers file
(Q)uit and save changes to sudoers file (DANGER!)
使用visudo命令配置sudo命令的配置文件时,其操作方法与Vim编辑器中用到的方法一致,因此在编写完成后记得在末行模式下保存并退出。在sudo命令的配置文件中,按照下面的格式将第99行(大约)填写上指定的信息:
谁可以使用 允许使用的主机=(以谁的身份) 可执行命令的列表
[root@linuxprobe ~]# visudo
96 ##
97 ## Allow root to run any commands anywhere
98 root ALL=(ALL) ALL
99 linuxprobe ALL=(ALL) ALL
在填写完毕后记得要先保存再退出,然后切换至指定的普通用户身份,此时就可以用sudo -l命令查看到所有可执行的命令了(下面的命令中,验证的是该普通用户的密码,而不是root管理员的密码,请读者不要搞混了):
[root@linuxprobe ~]# su - linuxprobe
Last login: Thu Sep 3 15:12:57 CST 2017 on pts/1
[linuxprobe@linuxprobe ~]$ sudo -l
[sudo] password for linuxprobe:此处输入linuxprobe用户的密码
Matching Defaults entries for linuxprobe on this host:
requiretty, !visiblepw, always_set_home, env_reset, env_keep=“COLORS
DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR LS_COLORS”, env_keep+=“MAIL PS1
PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE”, env_keep+=“LC_COLLATE
LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES”, env_keep+=“LC_MONETARY
LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE”, env_keep+=“LC_TIME LC_ALL
LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY”,
secure_path=/sbin:/bin:/usr/sbin:/usr/bin
User linuxprobe may run the following commands on this host:
(ALL) ALL
接下来是见证奇迹的时刻!作为一名普通用户,是肯定不能看到root管理员的家目录(/root)中的文件信息的,但是,只需要在想执行的命令前面加上sudo命令就可以了:
[linuxprobe@linuxprobe ~]$ ls /root
ls: cannot open directory /root: Permission denied
[linuxprobe@linuxprobe ~]$ sudo ls /root
anaconda-ks.cfg Documents initial-setup-ks.cfg Pictures Templates
Desktop Downloads Music Public Videos
效果立竿见影!但是考虑到生产环境中不允许某个普通用户拥有整个系统中所有命令的最高执行权(这也不符合前文提到的权限赋予原则,即尽可能少地赋予权限),因此ALL参数就有些不合适了。因此只能赋予普通用户具体的命令以满足工作需求,这也受到了必要的权限约束。如果需要让某个用户只能使用root管理员的身份执行指定的命令,切记一定要给出该命令的绝对路径,否则系统会识别不出来。我们可以先使用whereis命令找出命令所对应的保存路径,然后把配置文件第99行的用户权限参数修改成对应的路径即可:
[linuxprobe@linuxprobe ~]$ exit
logout
[root@linuxprobe ~]# whereis cat
cat: /usr/bin/cat /usr/share/man/man1/cat.1.gz /usr/share/man/man1p/cat.1p.gz
[root@linuxprobe ~]# visudo
96 ##
97 ## Allow root to run any commands anywhere
98 root ALL=(ALL) ALL
99 linuxprobe ALL=(ALL) /usr/bin/cat
在编辑好后依然是先保存再退出。再次切换到指定的普通用户,然后尝试正常查看某个文件的内容,此时系统提示没有权限。这时再使用sudo命令就可以顺利地查看文件内容了:
[root@linuxprobe ~]# su - linuxprobe
Last login: Thu Sep 3 15:51:01 CST 2017 on pts/1
[linuxprobe@linuxprobe ~]$ cat /etc/shadow
cat: /etc/shadow: Permission denied
[linuxprobe@linuxprobe ~]$ sudo cat /etc/shadow
root:
6
6
6GV3UVtX4ZGg6ygA6$J9pBuPGUSgZslj83jyoI7ThJla9ZAULku3BcncAYF00Uwk6Sqc4E36MnD1hLtlG9QadCpQCNVJs/5awHd0/pi1:16626:0:99999:7:::
bin::16141:0:99999:7:::
daemon::16141:0:99999:7:::
adm::16141:0:99999:7:::
lp::16141:0:99999:7:::
sync::16141:0:99999:7:::
shutdown::16141:0:99999:7:::
halt::16141:0:99999:7:::
mail::16141:0:99999:7:::
operator::16141:0:99999:7:::
games::16141:0:99999:7:::
ftp::16141:0:99999:7:::
nobody::16141:0:99999:7:::
………………省略部分文件内容………………
大家千万不要以为到这里就结束了,刘遄老师还有更压箱底的宝贝。不知大家是否发觉在每次执行sudo命令后都会要求验证一下密码。虽然这个密码就是当前登录用户的密码,但是每次执行sudo命令都要输入一次密码其实也挺麻烦的,这时可以添加NOPASSWD参数,使得用户执行sudo命令时不再需要密码验证:
[linuxprobe@linuxprobe ~]$ exit
logout
[root@linuxprobe ~]# whereis poweroff
poweroff: /usr/sbin/poweroff /usr/share/man/man8/poweroff.8.gz
[root@linuxprobe ~]# visudo
96 ##
97 ## Allow root to run any commands anywhere
98 root ALL=(ALL) ALL
99 linuxprobe ALL=NOPASSWD: /usr/sbin/poweroff
这样,当切换到普通用户后再执行命令时,就不用再频繁地验证密码了,我们在日常工作中也就痛快至极了。
[root@linuxprobe ~]# su - linuxprobe
Last login: Thu Sep 3 15:58:31 CST 2017 on pts/1
[linuxprobe@linuxprobe ~]$ poweroff
User root is logged in on seat0.
Please retry operation after closing inhibitors and logging out other users.
Alternatively, ignore inhibitors and users with ‘systemctl poweroff -i’.
[linuxprobe@linuxprobe ~]$ sudo poweroff