Linux 用户组与文件权限

LinuxBeginner
立即练习

简介

Linux 是一种多用户操作系统。每个进程和文件都属于某个用户,每个用户都有一个主组,还可以加入任意数量的附加组。身份、所有权和权限位共同决定谁可以读取、修改、执行或进入某个资源。

在本实验中,你将使用专用练习账户搭建一个小型团队环境。你将创建用户、管理组成员关系、保护文件、检查账户锁定状态,使用 umask 控制默认权限,并配置带粘滞位和 setgid 的目录。所有操作都在实验环境中完成,不会改变默认的 labex 登录路径。

检查身份并创建练习用户

在本步骤中,你将检查当前身份,并创建一个用于权限练习的独立账户。Linux 使用用户名和数字用户 ID(UID)表示用户,同时记录主组 ID(GID)以及用户所属的附加组。

首先确认当前 shell 的身份:

whoami

输出应为 labex。接着显示此账户关联的 UID、主组和附加组:

id

具体数字 ID 可能不同,但输出会使用 uidgidgroups 标出这些信息。

创建账户会修改系统文件,因此需要管理员权限。sudo 的含义是「以超级用户身份执行」:它会先检查当前账户是否有权限,然后以提升后的权限运行后面的命令。只对确实需要管理权限的命令使用 sudo,并在按下回车键前完整阅读命令。

下面的 useradd 命令使用了三个选项:

  • -m 创建主目录。
  • -U 创建一个与用户名相同的主组。
  • -s /bin/bash 将 Bash 设置为该账户的登录 shell。

创建名为 jack 的练习用户:

sudo useradd -m -U -s /bin/bash jack

检查新账户及其主目录:

id jack
ls -ld /home/jack

id 输出应显示 jack 同时作为用户名和主组名。目录列表应显示 /home/jack 已存在,并且所有者和所属组为 jack:jack

管理附加组

在本步骤中,你将创建团队组,并把用户加入附加组。用户的主组通常会成为新建文件的所属组。附加组则用于授予用户对其他共享资源的访问权限。

创建名为 developers 的组:

sudo groupadd developers

usermod -aG 选项表示「追加到附加组」。其中 -a 很重要:如果不使用它,-G 可能会替换用户现有的附加组成员关系。将 jack 加入 developerssudo

sudo usermod -aG developers,sudo jack

同时将 labex 加入 developers。当前 shell 不会立即获得新的组身份;你将在最后一个步骤中安全地刷新它。

sudo usermod -aG developers labex

检查两个账户:

groups jack
groups labex

第一条命令的输出应包含 jackdeveloperssudo。第二条命令的输出应包含 developers。加入 sudo 后,经过身份验证的账户可以请求提升权限;该权限只能授予可信的管理员。

控制文件所有权和权限

在本步骤中,你将为团队报告设置指定的所有者、所属组和权限模式。长格式列表会先显示文件类型,随后显示分别对应所有者、所属组和其他用户的三组权限。

在项目目录中创建一个空报告文件:

touch /home/labex/project/secure-report.txt

使用 chownuser:group 格式同时修改所有者和所属组:

sudo chown jack:developers /home/labex/project/secure-report.txt

设置权限模式 640

sudo chmod 640 /home/labex/project/secure-report.txt

在数字表示法中,读取权限为 4,写入权限为 2,执行权限为 1。因此:

  • 所有者的 6 表示可读和可写(4 + 2)。
  • 所属组的 4 表示只读。
  • 其他用户的 0 表示没有访问权限。

检查结果:

ls -l /home/labex/project/secure-report.txt
stat -c 'owner=%U group=%G mode=%a' /home/labex/project/secure-report.txt

稳定的 stat 字段应报告 owner=jack group=developers mode=640

检查并修改账户锁定状态

在本步骤中,你将练习临时锁定和解锁专用账户。Linux 会将密码哈希和账户状态存储在 /etc/shadow 中。密码字段开头的 ! 表示密码身份验证已锁定。

实验环境已创建名为 contractor 的练习账户。只显示其密码字段的第一个字符,避免输出密码哈希本身。从左到右阅读这条管道命令:getent shadow contractor 获取该账户的 shadow 记录;第一个 cut 使用 : 作为分隔符并选择第 2 个字段;第二个 cut 保留该字段的第 1 个字符:

sudo getent shadow contractor | cut -d: -f2 | cut -c1

初始字符通常应为 $,这是现代密码哈希格式的开头。使用 usermod -L 锁定账户:

sudo usermod -L contractor

再次检查第一个字符:

sudo getent shadow contractor | cut -d: -f2 | cut -c1

现在应为 !。使用 usermod -U 解锁账户,并确认 ! 已消失:

sudo usermod -U contractor
sudo getent shadow contractor | cut -d: -f2 | cut -c1

在本场景中,contractor 已离开团队。最后再次锁定该账户,同时保留其文件:

sudo usermod -L contractor

锁定密码身份验证不会删除账户,也不会删除其主目录,并且不一定会终止现有会话。这与删除用户不同;当需要保留文件供后续检查时,锁定账户非常有用。

使用 Umask 控制默认权限

在本步骤中,你将使用 umask 控制 shell 创建新文件和目录时要移除的权限位。程序通常以普通文件最大模式 666 和目录最大模式 777 开始。掩码 027 会移除所属组的写权限,以及其他用户的全部权限。

为实验创建工作区:

mkdir -p /home/labex/project/umask-demo

保存当前掩码,以便稍后恢复。语法 $(command) 称为命令替换:shell 会运行括号中的命令,并将整个表达式替换为该命令的输出。赋值语句会把结果保存到 original_umask 中;和其他 shell 赋值一样,= 两侧不能有空格。

original_umask=$(umask)

应用掩码 027,然后创建一个文件和一个目录:

umask 027
touch /home/labex/project/umask-demo/private-note.txt
mkdir /home/labex/project/umask-demo/private-dir

检查生成对象的数字权限模式:

stat -c '%a %n' /home/labex/project/umask-demo/private-note.txt /home/labex/project/umask-demo/private-dir

文件的权限模式应为 640,目录的权限模式应为 750。文件不会自动获得执行权限。恢复 shell 原来的掩码:

umask "$original_umask"

修改 umask 只会影响之后创建的对象,不会改写现有对象的权限。

使用粘滞位保护共享目录

在本步骤中,你将配置一个公共投递箱,使所有人都能创建文件,但不能删除其他用户拥有的文件。普通模式 777 会授予所有用户对目录的完整访问权限。添加粘滞位后,目录中的删除规则会发生变化。

创建共享目录并设置模式 1777。开头的 1 用于启用粘滞位。

mkdir /tmp/shared-dropbox
chmod 1777 /tmp/shared-dropbox

使用 sudo -u,分别以两个练习账户的身份创建一个文件:

sudo -u jack touch /tmp/shared-dropbox/jack-note.txt
sudo -u contractor touch /tmp/shared-dropbox/contractor-note.txt

现在让 jack 尝试删除 contractor 的文件:

sudo -u jack rm /tmp/shared-dropbox/contractor-note.txt

这次失败是预期结果。你应看到 Operation not permitted,并且 contractor 的文件仍然存在。检查目录:

ls -ld /tmp/shared-dropbox

权限字符串应以小写 t 结尾,例如 drwxrwxrwt。小写 t 表示粘滞位和其他用户的执行权限都已设置。大写 T 表示已设置粘滞位,但对应的执行权限未设置。

配置 Setgid 团队目录

在本步骤中,你将准备一个私有协作目录。对目录设置 setgid 后,新创建的子对象会继承该目录的所属组,而不是创建者的主组。这样可以让团队文件始终关联到同一个共享组。

创建目录:

mkdir /home/labex/project/team-share

jack 设置为所有者,将 developers 设置为所属组:

sudo chown jack:developers /home/labex/project/team-share

设置模式 2770。开头的 2 用于启用 setgid;770 授予所有者和所属组完整访问权限,同时拒绝其他用户访问。

sudo chmod 2770 /home/labex/project/team-share

检查结果:

ls -ld /home/labex/project/team-share
stat -c 'owner=%U group=%G mode=%a' /home/labex/project/team-share

长格式列表应在所属组的执行权限位置显示 s,例如 drwxrws---。小写 s 表示 setgid 和所属组执行权限都已启用。大写 S 表示已设置 setgid,但所属组执行权限缺失。

Setuid 会在所有者执行权限位置显示 s,它是另一种特殊权限位,常见于经过严格控制的系统可执行文件。阅读权限时要能识别它,但不要将其添加到任意程序上。

刷新组成员关系并验证继承效果

在本步骤中,你将在子 shell 中激活 developers 成员关系,并验证 setgid 会控制新文件的所属组。将用户加入 /etc/group 不会更新已经运行的 shell 的附加组。

启动一个以 developers 为活动组的子 shell:

newgrp developers

命令提示符可能会刷新。你仍然是 labex 用户,但子 shell 现在将 developers 作为有效组。确认这两个身份:

id

在 setgid 目录中创建文件:

touch /home/labex/project/team-share/labex-note.txt

检查新文件:

stat -c 'owner=%U group=%G mode=%a' /home/labex/project/team-share/labex-note.txt

所有者应为 labex,所属组应为 developers。setgid 会继承所属组;文件的读写权限位仍取决于创建进程及其 umask

退出子 shell,返回原来的终端会话:

exit

子 shell 关闭后,该文件仍会保留。

总结

你练习了 Linux 系统使用的核心身份与访问模型:创建用户和团队组、管理附加组成员关系、分配所有权,并将数字权限模式转换为实际的访问规则。你还在不暴露密码哈希的情况下检查了账户锁定状态。

随后,你进一步学习了普通权限之外的机制:umask 控制默认权限,粘滞位保护公共目录中的文件,setgid 在私有协作目录中保持团队组所有权。最后,你使用 newgrp 刷新组成员关系,并验证了真实文件继承的所属组。