封面来源:https://www.ninjaone.com/wp-content/uploads/2024/03/N1-0921-Linux-Administration-and-User-Management-blog-image-1.png

请注意:该部分难度较大,涉及到修改系统内的配置文件,因此需要你有较强的理解并使用英语的能力。在继续阅读之前请三思。

引言

在前面 2 篇同名文章中,我们介绍了 Linux 系统是如何实现用户与权限控制的。那么,在某些情况下,就像之前文章里面提到的那样——如果想要更精细的权限管理,建议使用 umask 命令或访问控制列表(Access Control Lists, ACLs)。那么,要怎么精细设置用户权限,以及什么是 ACL 呢?下面我们一一介绍。

提权

这部分内容非常简单,只有两部分:临时提权和永久提权。

临时提权使用的是 sudo 命令,加在所有命令的开头,可以让当前用户在某个时间段(一般是 10-15 分钟)执行一般只有 root 才能执行的命令。

永久提权只有 su 命令(不带任何参数和用户名),可以从当前用户直接切换到 root. 但是在退出(无论是 exit 还是直接关闭窗口)后,会立即回到当前用户。所以这不是永久提权了个寂寞吗

我们可以使用 sudo -l 命令来查看用户的权限。

以 root 身份为某个用户授权

是的,你没听错!在 Linux 内我们可以直接以 root 身份为某个用户授权

具体来说,我们先要切换到 root 用户,再编辑 /etc/sudoers 文件,然后在 root 下面一行加入用户名配置

假如说我们有一个叫做 zhangsan 的用户(请先创建该用户),那么编辑的内容就像这样:

你可能会发现,每一行对应 4 个(用空格或制表符隔开的,除了第二个和第三个)字段。每一个字段代表的意思是:

  • 第一个:用户名。就是该规则适用的用户

  • 第二个:主机。表示该用户可以通过哪些主机登录来使用 root 权限的命令。当然,在大多数简单的网络环境中,这个一般指的是这一台计算机或者服务器。

  • 第三个:身份。表示用户可以被允许切换成哪个用户的身份来执行命令(ALL) 表示 可以切换成系统中的任何用户。这个字段的格式通常是 (user:usergroup).

  • 第四个:命令。表示该规则允许用户执行哪些命令

注意,最后一个如果填写 ALL 就是使该用户可以执行系统内的所有命令(但是需要输入密码),而我们这里用户 zhangsan 使用的是 NOPASSWD 标签,意思是执行它后面的这些命令(例如 /usr/sbin/reboot)是不需要输入密码的

为了方便大家理解,我们可以对比一下普通用户的配置:

  • %ubuntudev ALL=(ALL) ALL

    • 含义:属于 ubuntudev 用户组的所有成员,可以从任何主机,以任何用户身份,运行任何命令。

  • trixie ALL=(ALL) /usr/bin/apt

    • 含义:用户 trixie 可以从任何主机,以任何用户身份,但只能运行 /usr/bin/apt 这个命令。

ACL 设置

相比于之前我们使用的 chmod(也叫 UGO 权限设置),访问控制列表(ACL)允许我们为任何一个用户(无论是在组内还是组外,请先检查系统里面有没有这个用户)或者用户组单独设置对某个文件/目录的权限,而不受其主组或其他组的限制。

ACL 操作有下面 3 种:获取,设置,删除。命令格式如下:

getfacl [filename]
setfacl [option] [u(ser)/g(roup):user/groupname:permission] [filename]

其中,filename 可以是相对路径或是绝对路径。(如果该参数是目录,则必须在前面参数的开头加上 d:

获取 ACL

getfacl 可以用来获取一个文件或目录所具有的 ACL. 例如,在一个 CentOS 10 Stream 上:

它表示的意思是:

  • 文件名为 testACL.txt

  • 所有者为 centos

  • 所在用户组为 centos

  • 所有者权限为 rw

  • 所在用户组权限为 r(仅读取)

  • 其他用户权限为 r(仅读取)

设置 ACL

如果要更加精细的设置 ACL,则应该使用 setfacl 命令。

例如,我们有 centos(管理员)和 testuser 两个用户,现在要设置位于 /home 目录下为用户 centos 所有的文件 testacl.sh 的权限(默认为 rwxr--r--),使得除了 centos 仅有 testuser 能够读写并且执行该文件。

可以这样设置:

setfacl -m u:testuser:rwx /home/testacl.sh
# you can also use relative paths

这样一来,它的权限就是这样的(如有可能,请先更改文件的所有者及用户组):

我们可以看到,在 user 那边,只有名为 testuser 的用户能够执行这个 script 脚本。这样我们就实现了精确到用户的权限控制。

此时,如果用 ls -l testacl.sh 查看 testacl.sh 的权限,你应该会发现在正常的权限后面,出现了一个 +

这表示该文件有额外的权限(你也会注意到,原来用于组权限的位置被我们新加入的额外用户权限所占据)。

设置额外的组权限和上面同理,这里就不过多展开了。

setfacl 里出现的 o 是干什么的?

我猜你可能是想问这个:

setfacl -m o::rw /home/testacl.sh

这里的 o 指的是其他用户(就是 UGO 权限里面我们经常提到的)。

接着看后面,用户/组名称并没有指定,这说明所有的其他用户(无论所属的用户组如何)都有读写权限,这同样适用于组的 ACL

删除 ACL

删除 ACL 还是使用 setfacl 命令。但是,该情境下需要使用的选项和之前不同,是 -x-b.

使用 -x 选项时,表示删除某个文件的 ACL,用法和之前的 -m 选项几乎一样。唯一的区别在于,它不需要指定权限(你都删除了还要指定什么呢)。例如:

setfacl -x u:testuser /home/testacl.sh
# To delete ACL of user testuser
# You CANNOT delete permissions for other users

使用 -b 选项时,表示删除所有设定的 ACL,也就是使用原来的 UGO 权限。

特殊权限

Linux 的特殊权限分传统特殊权限文件系统特殊属性两种:

传统特殊权限

占用基础权限的执行位(x),通过符号(st)或数字(421)表示,优先级高于普通权限。

  • SUID

  • SGID

  • Sticky Bit(粘滞位)

文件系统特殊属性

属于底层文件系统级别权限,优先级高于基础权限和传统特殊权限,一般来说任何用户(即使是 root)都不能对其进行修改

  • chattr

  • lsattr

另一个是进程掩码 umask.

具体可以参考这篇文章:

https://jishuzhan.net/article/1993625834809262081

传统特殊权限

SUID

SUID 允许用户在执行带有该权限的文件时,临时获得该文件所有者的权限,完成后收回。例如:

chmod u+s trixie.sh
# Or: chmod 4755 trixie.sh

运行结果如下:

我们可以看到 trixie.sh 的背景颜色变成了红色,并且用户的基本权限变为 rws,这说明该文件已经具有 SUID,其他用户运行时,能够以 root 身份运行该文件。

SGID

SGID 和 SUID 类似,它可以使用户在进行下面的操作时获得对应的权限:

  • 新建目录时,新的目录将会直接继承上级目录的所有权限(可用于团队共享目录)

  • 执行可执行文件时,用户将会临时获得该文件所属用户组的权限

要为可执行文件或目录添加 SGID,需要用到 chmod 命令和 2 作为八进制数值模式的 SGID 权限。例如:

chmod 2755 trixie.sh
# Or: chmod g+s trixie.sh

结果如下:

现在 trixie.sh 的背景变成了橙色,并且组的基本权限为 rwxr-sr-x,说明该文件已经具有 SGID,其他用户运行时,能够以组内用户的身份运行该文件。

Sticky Bit

和前面 2 个权限不同的是,Sticky Bit 仅能对目录有效。它限制该目录下的文件只能被文件/目录的所有者以及 root 删除或改动。对于其他用户,无论其是否有 w 权限,均不能修改或删除。

同样的,要实现这个效果也是要用 chmod 命令的,但需要 t 作为权限控制字符或 1 作为八进制数值模式的首要权限。

例如:

chmod o+t testdir
# Or:
chmod 1755 testdir

文件系统特殊属性

lsattr 的作用是查看文件的特殊属性,用法如下:

lsattr [filename]

非常简单。

下面我们重点讲一下 chattr.

chattr 的作用是设置文件的特殊属性,在使用时,是必须要 root 权限的。它的格式如下:

chattr [+=-][property] [filename]

下面是两个我们最常用的属性(property):

属性

释义

作用对象

i (immutable)

文件/目录不可被修改、重命名或删除

文件/目录

a (append)

文件只能在末尾追加新内容(多用于日志)

文件

例如使用 i 属性:

chattr +i newbie.sh

结果就像这样:

权限掩码 umask

umask 直接决定了一个文件创建时的默认权限中,有哪些是不被允许的。

举个例子:某被封的大 V 在直播中经常提到“苹果商店”“苹果房子”,其实“苹果商店”指的是山姆会员店(Sam's Club)。山姆会员店的规则是:只有会员可以进入,非会员免进。这样一来,所有在“会员”这个组里面的用户就有进入并购物的权利,而非会员(近似相当于其他用户,无不良引导)则必须止步,也就是说我们只需要考虑非会员所不能拥有的权利和即使是会员也不能有的权限(例如随意搬弄货架扰乱购物秩序等)。因此,我们可以得出结论:非会员不能“进入”“购物”以及“改变货架位置”,会员不能“改变货架位置”。这就是我们所说的权限掩码 umask.

回到正题,我们如何获取系统内默认的 umask?其实不难,只需要 umask 就可以了:

这表示组和其他用户默认不能有写入执行文件的权利。(但目录默认是有执行权限的)

如果要临时修改 umask 值呢?直接在 umask 后面接你想要的权限掩码(注意不要写反了!不是权限代码):

umask 000
mkdir testdir
touch testfile
ll -d testdir testfile

结果如下:

这个权限其实是相当的危险的!因为这里我用的是虚拟机和 Live CD,因此不会对系统造成实质性的损害,在实际的生产环境中,这是绝对不被允许的!因为此时任何人都能对文件进行改动,如果有人搞破坏,很有可能造成巨额的经济损失。

总结

这一部分我们具体阐述了Linux的高级权限管理。核心在于提权,主要方法是为用户配置sudo权限,使其能执行 root 命令。为实现更精细的权限控制,我们引入了ACL,可为特定用户/组设置独立权限。随后我们讲解了特殊权限:SetUID、SetGID 和 Sticky Bit,用于处理执行时权限继承和共享目录安全;以及使用 chattr 设置的文件特殊属性,提供防删除等底层保护。所有这些权限的默认起点都由 umask 决定,它通过屏蔽特定权限位来设定新文件的初始权限。

C/C++ 新人开发者,主攻 UE5,业余 Linux 运维