刚接触 Linux 的时候,很多人都会被 /etc/passwd、/etc/shadow、/etc/group 这几个文件,还有 ls -l 里那一堆 rwxr-xr-x 搞得云里雾里。其实这套东西的逻辑并不复杂,理清楚"谁是谁、谁属于谁、谁能干什么"这三个问题,基本就掌握了一大半。
这篇文章分成两部分:
第一部分讲清楚基础的四块内容——用户档案、密码、组、文件权限;
第二部分补充一些实际运维中绕不开、但入门教程经常漏讲的内容,比如 umask、SUID/SGID、ACL,以及企业环境里用户身份到底是怎么被识别和认证的。
第一部分:基础四件套
一、每个用户的"身份证":/etc/passwd
系统里的每一个用户,都会在 /etc/passwd 里留一条记录:
cat /etc/passwd
格式是用冒号隔开的七列,比如:
root:x:0:0:root:/root:/bin/bash
用户名
密码占位符:永远是
x,真正的密码不存在这里(下面会讲)UID(用户编号):系统内部真正认的是这个数字,
root固定是0GID(主组编号):这个用户默认所属的组
用户信息备注
家目录:
root是/root,普通用户一般是/home/用户名登录 Shell:如果是
/sbin/nologin,说明这个账号不允许登录,通常是系统内部服务专用的账号
关于 UID 的编号范围,0 永远是 root,这个是固定的;但"系统账号用 1~999、普通用户从 1000 开始"只是很多发行版的默认惯例,具体范围其实由发行版和 /etc/login.defs 里的配置决定,不同环境可能不完全一样,不建议当成写死的规则去记。
记住一句话:passwd 存的是用户的"户口信息",不存真密码。
二、真正的密码藏在这里:/etc/shadow
/etc/shadow 只有 root 能读,安全性更高,格式是九列:
root:$6$aHtE6jAFkMG...:18000:0:99999:7:::
用户名
密码哈希值:这里更准确的说法是"哈希"而不是"加密"。Linux 并不会把密码"加密后存起来、需要时再解密",而是通过哈希算法(配合随机 salt)把密码变成一段不可逆的字符串存起来,登录时用同样的算法处理输入的密码,比对哈希结果是否一致。前缀
$6$一般代表用的是 SHA-512 算法。这一列如果是!!,表示从未设置过密码;开头是!,表示账号被锁定上次改密码的日期:从 1970-01-01 起算的天数
密码最短使用天数:
0表示不限制密码最长使用天数:默认
99999,相当于永不过期过期前提醒天数:默认 7 天
密码过期后的宽限天数
账号失效日期:空着表示一直有效
保留字段
一句话总结:passwd 负责"你是谁",shadow 负责"你的密码哈希和有效期"。
三、"部门"是怎么划分的:/etc/group
组的信息存在 /etc/group,格式是四列:
root:x:0:
组名
组密码占位符:真正的组密码在
/etc/gshadow,实际生产环境基本用不到GID
附加成员列表:把这个组当"兼职组"的用户(逗号分隔)。主组是这个组的用户不会出现在这一列
新手最容易搞混的概念——主组 vs 附加组:
主组:每个用户创建时都会分配一个主组(默认是和用户名同名的私有组),只能有一个。
附加组:主组权限不够用时,再把用户加进别的组,一个用户可以有多个附加组。
四、文件到底谁能读、谁能改:目录文件属性
ls -l
看到类似这样一行:
-rw-r--r-- 1 root root 1.3K Feb 10 20:30 anaconda-ks.cfg
依次是:文件类型+权限位、硬链接数、属主、属组、大小、修改时间、文件名。
重点看第一段的 10 个字符:
- rw- r-- r--↑ ↑ ↑ ↑类型 属主 属组 其他人
第 1 位是文件类型:
| 符号 | 含义 |
|---|---|
- | 普通文件 |
d | 目录 |
l | 软链接 |
b | 块设备文件 |
c | 字符设备文件 |
p | 管道文件 |
s | 套接字文件 |
后 9 位是权限,三个一组分别对应属主(u)、属组(g)、其他人(o),每组内是读(r)写(w)执行(x)。数字对照表:
| 权限 | 二进制 | 数字 |
|---|---|---|
--- | 000 | 0 |
--x | 001 | 1 |
-w- | 010 | 2 |
-wx | 011 | 3 |
r-- | 100 | 4 |
r-x | 101 | 5 |
rw- | 110 | 6 |
rwx | 111 | 7 |
比如 755,就是"属主可读可写可执行、属组和其他人可读可执行",程序、脚本、目录都很常用这个组合(脚本能不能真正跑起来,还要看解释器、noexec 挂载参数、SELinux 等因素,属于更进阶的话题)。
一个容易理解偏的地方:目录的 x 到底是什么权限。
严格来说,目录的 x 表示的是能不能"穿越/搜索"这个目录,而不只是简单等同于"能不能 cd 进去"。举个例子:
chmod 111 dir
这时候你不能 cd dir,也不能 ls dir 列出目录内容,但如果你已经知道目录里有个文件叫 test.txt,并且这条路径上其它权限也允许,你依然可以:
cat dir/test.txt
也就是说,x 权限控制的是"能否穿过这个目录去访问里面的东西",r 权限控制的是"能否列出目录里都有什么",两者是分开生效的。
判断权限时到底看哪一组? 系统的判断顺序是这样的:
用户访问文件 │ ▼是不是 owner(属主)? │ │ 是 否 │ ▼按属主权限 是不是 group(属组)成员? │ │ 是 否 │ │ 按属组权限 按其他人权限
注意:只要你是文件的属主,系统就按属主权限判断,不会再往下看你是不是属组成员——哪怕属主权限比属组权限还严格,也是这样。
第二部分:光看这四张表还不够——实际运维会用到的内容
五、命令要对应到操作:useradd / passwd / groupadd / usermod
前面讲的四个文件,都是靠这几个命令去增删改的:
useradd -m alice # 创建用户,-m 表示同时创建家目录passwd alice # 给用户设置密码groupadd eda # 创建一个组usermod -aG eda alice # 把 alice 加入 eda 附加组id alice # 查看用户的 UID/GID/所在组groups alice # 查看用户所在的所有组
这里有一个运维中非常容易踩坑的地方,一定要区分清楚:
usermod -G eda alice # 危险!会覆盖 alice 原有的所有附加组,只保留 edausermod -aG eda alice # 安全,在原有附加组基础上追加 eda
-G 不加 -a 会把用户原来所在的其它附加组全部清空,只留下新指定的这个组——这在生产环境里是个经典的"手滑事故",一定要养成习惯:加组永远用 -aG。
六、chmod / chown / chgrp:怎么改权限和归属
chmod 755 test.sh # 用数字方式一次性设置权限chmod u+x test.sh # 只给属主加执行权限chmod g-w test.sh # 去掉属组的写权限chown alice test.txt # 改属主chown alice:eda test.txt # 同时改属主和属组chgrp eda test.txt # 只改属组
数字方式(如 755)和符号方式(如 u+x)各有用处:数字方式适合"一次性覆盖设置",符号方式适合"只微调某一部分权限"。
七、umask:为什么新建文件默认就是 644,目录默认是 755
这是很多入门内容会漏掉、但非常基础的一环。执行:
umask
常见输出是 0022。它决定了新建文件和目录时默认会"减掉"哪些权限。
逻辑是这样的:
普通文件的理论最高权限是
666(Linux 出于安全考虑,新建文件默认不给可执行权限,即使 umask 是 0 也一样)目录的理论最高权限是
777
然后用 umask 的值去"扣掉"对应的权限位:
文件: 666umask:022------------结果: 644目录: 777umask:022------------结果: 755
这就是为什么大多数系统里 touch 出来的文件默认是 644,mkdir 出来的目录默认是 755。
umask 的值也会影响协作场景。比如共享目录场景下:
umask 002:属组默认有写权限,适合一个组里的人需要互相修改彼此新建的文件(比如共享工程目录)umask 027:属组只有读权限、其他人完全没权限,更保守,适合对权限要求更严格的环境
八、SUID / SGID / Sticky Bit:三个特殊权限位
除了 r/w/x,Linux 还有三个"特殊权限",ls -l 里会体现在权限位的特殊符号上。
SUID(属主位上出现 s):
-rwsr-xr-x
设置方式:
chmod u+s file
作用:程序运行时,会以文件属主的身份权限去执行,而不是运行它的那个用户的权限。最经典的例子就是 passwd 命令本身:
ls -l /usr/bin/passwd
普通用户执行 passwd 修改自己的密码,本质是在改 /etc/shadow,而这个文件普通用户是没有写权限的——之所以能改成功,就是因为 passwd 命令带了 SUID,执行时临时"借用"了 root 的权限。
SGID(属组位上出现 s):
对文件:chmod g+s file,作用和 SUID 类似,但借用的是属组的权限。
对目录:chmod g+s project/ 更常用,作用是——这个目录里新建的文件/子目录,会自动继承目录本身的属组,而不是继承创建者当前的主组。这在团队共享目录里特别实用:
mkdir /eda/projectchgrp eda /eda/projectchmod 2775 /eda/project # 2 就是 SGID 位
设置好之后,团队里任何人在这个目录下新建文件,属组都会自动是 eda,不需要每次手动 chgrp。
Sticky Bit(其他人位上出现 t):
ls -ld /tmpdrwxrwxrwt
典型场景就是 /tmp 这种所有人都能写的公共目录。加了 Sticky Bit 之后,即使某个用户对目录有写权限,也只能删除自己创建的文件,不能删除别人的文件,避免了公共目录被人乱删东西。
九、当传统权限不够用:ACL
owner / group / other 这套三层权限模型,遇到"一份文件要给不同的人分配不同权限"时就不够用了。比如:
张三需要读写,李四只能只读,同组的其他人完全不能写。
这种诉求靠传统的 rwx 是表达不出来的,这时候就要用 ACL(访问控制列表):
setfacl -m u:zhangsan:rw project # 给张三单独设置读写权限setfacl -m u:lisi:r project # 给李四单独设置只读权限setfacl -m g:eda:rwx project # 给 eda 组设置读写执行getfacl project # 查看当前的 ACL 设置
用了 ACL 之后,getfacl 的输出里会多一行 mask,很多人第一次看到会困惑:
group::rwxmask::r-x
明明 group 显示的是 rwx,为什么实际生效的却像是 r-x?这是因为 mask 定义了 ACL 生效的权限上限——最终生效的权限,是 ACL 具体条目和 mask 取交集的结果。所以用了 ACL 之后,改权限不能只看某一行,还要留意 mask 有没有把它"限制"住了。
十、往深一层想:Linux 内核认的其实不是"用户名"
前面一直在说"用户""组",但有一点值得点破:
用户名(alice) ↓UID(1001) ↓GID(1001) + 附加组(2000, 3000...)
Linux 内核层面真正识别的是数字 UID/GID,不是字符串"用户名"。 用户名只是给人看的一层"翻译"。执行:
id alice
会看到类似:
uid=1001(alice) gid=1001(alice) groups=1001(alice),2000(eda),3000(dv)
这个概念在跨主机场景(比如 NFS 共享目录)里特别重要——如果两台机器上同一个 UID 对应的用户名不一样,文件权限判断依然是按 UID 数字来的,很容易出现"看起来是别人的文件,其实 UID 是我"这种情况。
那这层"翻译"是怎么完成的呢?靠的是 NSS(Name Service Switch)。系统怎么把 alice 翻译成 UID、去哪里查这个映射关系,是由 /etc/nsswitch.conf 决定的:
passwd: files sssgroup: files sssshadow: files
也就是说,执行 id alice 时,系统会按配置的顺序去查:先查本地的 /etc/passwd(files),如果配置了 sss,还会去问 SSSD 服务,SSSD 背后可能连着 LDAP 或者 AD 域——这也是企业环境里"域账号"能直接在 Linux 上登录的原理。也就是说,一个用户信息不一定只存在于本机的 /etc/passwd 里,入门时了解这一点,遇到"明明加了用户,怎么查不到"这类问题时会更容易排查方向。
十一、身份查询和身份认证是两回事:NSS vs PAM
很容易把这两件事搞混,简单区分一下:
NSS 解决的问题是:"这个用户是谁?UID/GID 是多少?属于哪些组?"——纯粹是查信息。
PAM(可插拔认证模块)解决的问题是:"这个用户的身份认证能不能通过?"——涉及密码校验、登录策略等。
以 SSH 登录为例,大致流程是:
ssh 客户端 │ ▼sshd │ ▼PAM(依次经过 auth → account → password → session 几个阶段) │ ├── 可能连接 SSSD ├── SSSD 再连接 LDAP / AD / Kerberos ▼认证通过,允许登录
理解了这一层,就能明白为什么有的环境改了密码策略是改 PAM 配置,而查用户信息又是另一套 NSS 的逻辑——这是两个独立的子系统,配合起来完成"登录"这件事。
十二、sudo:不是"变成 root",而是"按策略执行指定命令"
很多人对 sudo 的理解停留在"让普通用户临时变成 root",但更准确的理解是:sudo 是按照预先定义好的策略,允许某个用户以指定身份执行指定的命令,不一定是变成 root,也不一定能执行所有命令。
策略配置在 /etc/sudoers(推荐用 visudo 编辑,避免语法错误导致文件报废)以及 /etc/sudoers.d/ 目录下的独立文件里,比如:
alice ALL=(root) /usr/bin/systemctl restart xxx
这一行的意思是:alice 只被允许以 root 身份执行这一条特定命令,而不是拥有 root 的全部权限。
常见用法:
sudo -l # 查看自己被允许执行哪些 sudo 命令sudo -i # 切换为 root 的登录 shell 环境sudo -u oracle command # 以 oracle 用户身份(而不是 root)执行命令
最后提一句:生产环境里通常不建议这样配置:
alice ALL=(ALL) NOPASSWD: ALL
这等于完全放开了权限限制,也不需要输密码验证,一旦账号被盗用风险很大。合理的做法是按最小权限原则,只开放必要的命令。
最后,把整条逻辑串起来
/etc/passwd:系统里有哪些用户,UID、主组、家目录、能不能登录。/etc/shadow:密码哈希、有效期怎么管。/etc/group:用户怎么分组,方便批量授权。文件权限(rwx):具体到某个文件,属主/属组/其他人分别能做什么。
umask / SUID / SGID / Sticky Bit:权限是怎么"默认生成"的,以及几个特殊场景下的权限位。
ACL:当传统三层权限不够精细时的补充方案。
UID/GID + NSS:Linux 内核真正认的是数字,用户名只是"翻译层",这层翻译可能来自本地文件,也可能来自 LDAP/AD。
PAM + sudo:身份查询之外,"认证"和"提权"分别是怎么一回事。


网友留言: