Linux权限
前言
“Permission denied”—— 每一个 Linux 用户都曾面对过的“拦路虎”。这不仅仅是一条错误信息,更是通往理解 Linux 安全核心的大门。Linux 作为一个多用户操作系统,其精髓就在于如何通过权限系统,清晰地界定“谁”可以对“什么文件”做“什么事”。
用户和用户组
主组与附加组
一个用户可以属于 一个主用户组 (Primary Group) 和 **多个附加用户组 (Supplementary/Secondary Groups)**。
- 主用户组:用户创建文件时,文件的默认所属组就是这个组。每个用户必须有且只有一个主用户组。
- 附加用户组:用户为了获得访问其他资源的权限而加入的组。比如,为了能运行
docker命令,需要将用户加入docker组。
如何查看?
最简单直接的命令是 id。
1 | # 查看当前登录用户的组信息 |
示例输出及解读:
1 | $ id arthur |
uid=1001(arthur): 用户的ID和名称。gid=1001(arthur): 主用户组的ID和名称。这里用户的名称和主组的名称相同,这是一种常见的配置(称为 User Private Group)。groups=...: 用户所属的所有组列表,包括主组和所有附加组。1001(arthur): 他的主组。27(sudo): 他是一个附加组成员,因此他可以使用sudo命令。998(docker): 他也是docker组的附加组成员,因此他可以直接运行docker相关命令。
如果你只想看组名列表,可以使用
groups命令:$ groups arthurarthur : arthur sudo docker
用户组下的用户
要知道一个特定的组里有哪些成员,我们可以查询 /etc/group 文件。
方法一:使用 getent 命令 (推荐)
getent 命令可以从系统数据库中获取条目,比直接 grep 文件更可靠。
1 | # 查看 sudo 组的成员 |
示例输出:
1 | sudo:x:27:arthur,bob |
这表示 sudo 组的 GID 是 27,的成员列表里有 arthur 和 bob。
方法二:直接搜索 /etc/group 文件
1 | grep '^sudo:' /etc/group |
输出结果和上面类似。
注意:一个用户的主组关系是在
/etc/passwd文件中定义的,/etc/group的成员列表里只显示作为附加组加入的用户。getent会综合考虑这两种情况,所以结果更全面。
用户组类型
我们可以分为两大类:
系统用户组 (System Groups)
这些组通常在安装操作系统或特定软件(如数据库、Web服务器)时自动创建,用于权限管理,不代表真实的人。
- 数量:一个最小化的服务器可能有几十个,一个功能齐全的桌面系统可能有上百个。
- 常见名称示例:
root: 超级管理员组。sudo或wheel: 允许其成员使用sudo提升权限的组。adm: 用于系统监控,其成员可以读取很多日志文件。www-data(Debian/Ubuntu) 或apache(CentOS/RHEL): Web 服务器(如 Nginx, Apache)运行所使用的组。网页文件通常需要授权给这个组。docker: 允许其成员在没有sudo的情况下运行 Docker 命令。mysql,postgres: 数据库服务使用的组。systemd-journal,systemd-network:systemd核心服务使用的组。
用户用户组 (User Groups)
这些组通常是管理员为了管理真实用户而创建的。
User Private Group (UPG) 模式:
- 这是现在绝大多数 Linux 发行版的默认策略。当你创建一个新用户(如
adduser arthur),系统会自动创建一个同名的组arthur,并将作为该用户的主组。 - 好处:默认情况下,用户创建的文件权限是
644(rw-r–r–),所有者是arthur,所属组也是arthur。因为组里只有他自己,所以文件默认是私有的,非常安全。当需要协作时,再把他加入到一个共享的附加组(比如developers)中。
- 这是现在绝大多数 Linux 发行版的默认策略。当你创建一个新用户(如
共享组模式:
- 在一些老系统或特定环境中,可能会创建一个像
users这样的通用组,所有普通用户的主组都是users。这种模式现在不太常见,因为不利于文件隐私和权限隔离。
- 在一些老系统或特定环境中,可能会创建一个像
如何查看系统上所有的组?
你可以直接查看 /etc/group 文件。
1 | # 使用 less 分页查看所有组 |
你会看到一个长长的列表,大部分都是你可能不认识的系统组。
添加/移除组成员
gpasswd (group password) 是一个专门用来管理 /etc/group 的工具,在添加/移除组成员时语法非常清晰。
将用户加入组 (Add)
语法:
1 | sudo usermod -aG <组名> <用户名> |
1 | sudo gpasswd -a <用户名> <组名> |
示例:
同样是将用户 arthur 加入 docker 组。
1 | sudo gpasswd -a arthur docker |
输出会是:Adding user arthur to group docker
从组中移除用户 (Remove)
这是 gpasswd 的优势所在,语法非常直观。
语法:
1 | sudo gpasswd -d <用户名> <组名> |
示例:
现在我们想把 arthur 从 docker 组中移除。
1 | sudo gpasswd -d arthur docker |
输出会是:Removing user arthur from group docker
验证:
再次使用 id arthur 查看,你会发现 docker 组已经从他的 groups 列表中消失了
权限的基础:所有权 (Ownership)
在 Linux 中,每个文件和目录都有一个“身份标签”,定义了谁是主人。这个身份由三部分组成:
- **用户 (User)**:文件的所有者。通常是创建该文件的用户。
- **用户组 (Group)**:一个用户的集合。文件可以被分配给一个用户组,组内的所有用户都可能拥有特定权限。这对于团队协作非常有用。
- **其他人 (Others)**:既不是文件所有者,也不属于文件所在用户组的任何其他用户。
可以通过 ls -l 命令来查看文件的所有权信息:
1 | $ ls -l my_file.txt |
核心权限位:r, w, x
ls -l 命令输出的开头部分 -rw-r--r-- 就是权限的直观表示。分为 4 个部分:
| 部分 | 字符 | 含义 |
|---|---|---|
| 第 1 位 | - |
代表文件类型(- 是普通文件, d 是目录, l 是链接等) |
| 第 2-4 位 | rw- |
用户 (User) 的权限 |
| 第 5-7 位 | r-- |
用户组 (Group) 的权限 |
| 第 8-10 位 | r-- |
其他人 (Others) 的权限 |
这里的 r, w, x 分别代表三种基本权限:
- 读 (Read -
r):- 对于文件: 可以读取文件的内容 (例如
cat,less,cp)。 - 对于目录: 可以列出目录中的文件和子目录列表 (例如
ls)。
- 对于文件: 可以读取文件的内容 (例如
- 写 (Write -
w):- 对于文件: 可以修改文件的内容 (例如
vim,echo >)。 - 对于目录: 可以在目录中创建、删除、重命名文件或子目录 (例如
touch,rm,mv)。注意:删除一个文件需要其所在目录的w权限,而不是文件本身的w权限。
- 对于文件: 可以修改文件的内容 (例如
- 执行 (Execute -
x):- 对于文件: 可以将文件作为程序来运行 (例如
./my_script.sh)。 - 对于目录: 可以进入该目录 (例如
cd)。这是访问目录下任何内容的前提。
- 对于文件: 可以将文件作为程序来运行 (例如
🔑 关键点:一个目录的
x权限至关重要。即使你有目录下某个文件的r权限,如果没有该目录的x权限,你甚至无法进入目录来访问那个文件。
修改权限:chmod 命令
chmod (change mode) 是我们用来修改文件或目录权限的命令。有两种使用方式:符号模式和八进制模式。
符号模式 (Symbolic Mode)
这种方式非常直观,易于理解。
- 操作对象:
u(user),g(group),o(others),a(all, 即 ugo) - 操作符:
+(添加权限),-(移除权限),=(精确设置权限) - 权限:
r,w,x
示例:
1 | # 给用户添加执行权限 |
八进制模式 (Octal Mode)
这种方式更快捷,是系统管理员和脚本中的常用方法。将权限用数字表示:
r= 4w= 2x= 1-= 0
将每组(用户、用户组、其他人)的权限数字相加,得到一个三位数的八进制代码。
常见组合:
| 数字 | 权限 (rwx) |
含义 |
|---|---|---|
7 |
rwx (4+2+1) |
读、写、执行 |
6 |
rw- (4+2+0) |
读、写 |
5 |
r-x (4+0+1) |
读、执行 |
4 |
r-- (4+0+0) |
只读 |
0 |
--- (0+0+0) |
无任何权限 |
示例:
chmod 755 my_directory:7(rwx): 用户拥有所有权限。5(r-x): 用户组可以读取和进入目录。5(r-x): 其他人可以读取和进入目录。- (这是目录和脚本的常用权限)
chmod 644 my_file.txt:6(rw-): 用户可以读写。4(r--): 用户组只读。4(r--): 其他人只读。- (这是普通文件的常用权限)
chmod 777 sensitive_data: 危险! 任何人都有权读、写、执行。请极度谨慎使用。
改变身份:chown 和 chgrp
chown(change owner): 用来改变文件或目录的所有者(用户和用户组)。chgrp(change group): 用来单独改变文件或目录的用户组。
示例:
1 | # 将文件所有者改为 alice |
-R或--recursive选项非常强大,表示对目录内的所有文件和子目录都执行相同操作。
特殊权限 setuid, setgid, sticky bit
除了基本的 rwx,Linux 还提供了三种特殊的权限位。
SUID (Set User ID)
- 表现形式: 在用户执行位上显示为
s(或S),例如rwsr-xr-x。 - 作用: 当一个设置了 SUID 的可执行文件被运行时,该进程将以文件所有者的权限来运行,而不是以执行者的权限。
- 经典案例:
/usr/bin/passwd命令。普通用户执行passwd时,需要修改/etc/shadow这个 root 用户才能写入的文件。passwd命令的所有者是 root 且设置了 SUID,所以任何用户运行时,都临时获得了 root 权限来修改密码文件。 - 设置方法:
chmod u+s filename或chmod 4755 filename。
SGID (Set Group ID)
- 表现形式: 在用户组执行位上显示为
s(或S),例如rwxr-sr-x。 - 作用:
- 对文件: 与 SUID 类似,运行时进程将获得文件所属用户组的权限。
- 对目录 (更常用): 在一个设置了 SGID 的目录中创建的任何新文件或子目录,其用户组将自动继承该父目录的用户组,而不是创建者的默认用户组。这对于团队共享文件夹非常有用!
- 设置方法:
chmod g+s dirname或chmod 2775 dirname。
Sticky Bit (粘滞位)
- 表现形式: 在其他人执行位上显示为
t(或T),例如rwxrwxrwt。 - 作用: 只对目录有效。在一个设置了粘滞位的目录中,即使用户对该目录有写权限,他也只能删除或重命名自己拥有的文件,而不能删除或重命名其他用户的文件。
- 经典案例:
/tmp目录。所有用户都可以在/tmp中创建文件,但粘滞位确保了你不能删除别人的临时文件。 - 设置方法:
chmod +t dirname或chmod 1777 dirname。
总结
- 最小权限原则: 只给予用户完成任务所需的最小权限。
- 默认权限:
755适用于目录和可执行文件,644适用于普通文件。 - 谨慎使用
777: 避免使用chmod 777,会带来巨大的安全风险。 - 理解
x对目录的意义: 无法cd进一个目录,十有八九是x权限问题。 - 善用
SGID: 在团队协作目录上设置SGID可以极大地方便文件管理。
为服务创建专用的、权限受限的系统用户
创建一个名为 navidrome 的系统用户,不能登录,并且没有家目录。
1 | sudo useradd --system --shell /sbin/nologin --no-create-home navidrome |
sudo: 需要管理员权限。useradd: 创建用户的命令。--system: 告诉系统这是一个服务/系统账户。--shell /sbin/nologin: 禁止登录。--no-create-home: 不要在/home下创建navidrome目录。navidrome: 新用户的名字。