
Linux(五):用户管理
把 Linux 账户从「会跑 useradd」升级到能讲清楚的层次:/etc/passwd 与 /etc/shadow 的字段含义与联动、初始组与附加组的区别、sudo 的判定流程、useradd/usermod/passwd/chage/userdel 的完整生命周期,以及底下那一层 PAM 是怎么把这些黏在一起的。
如果你只是在自己的笔记本上用过 useradd 和 passwd,那大概率不需要考虑太多细节。但只要一台机器上有多个用户或者运行了多个服务,“用户管理”就不再只是简单的操作,而是整个安全模型的核心:它决定了谁能登录系统、进程写入文件时归属哪个 UID、哪些命令可以通过 sudo 提权到 root,以及被窃取的密码还能被利用多久。

本文会沿着一条主线完整讲解这个模型。首先从 /etc/passwd 和 /etc/shadow 的原始结构入手——毕竟这一领域的所有命令本质上都是围绕这两个文件进行修改;然后详细说明用户和组之间的关系(这也是初学者最容易混淆的部分);接着介绍用户生命周期管理的相关命令(如 useradd、usermod、passwd、chage、userdel),以及如何正确配置 sudo 和使用 visudo;最后深入探讨将认证、账户策略、密码规则和会话管理串联起来的 PAM 框架。
心智模型:账户就是几个文本文件里的一行#
在开始讨论具体命令之前,先来了解一下数据模型。Linux 的用户账户信息存储在三个简单的文本文件中,每个文件一行代表一个实体,字段之间用冒号分隔。
/etc/passwd—— 公开信息。每一行对应一个账户(包括人类用户和服务账户)。所有人都能读取,但只有 root 用户可以修改。/etc/shadow—— 敏感信息。每一行存储一个账户的密码哈希以及密码老化策略。只有 root 用户可以访问。/etc/group—— 每行代表一个用户组,末尾是一个逗号分隔的成员列表。
还有 /etc/gshadow(用于存储组密码和组管理员信息,实际很少使用)以及 /etc/skel(新用户家目录的模板目录)。

/etc/passwd 文件的七个字段从左到右依次是:
- username —— 登录名,在同一台主机上必须唯一。
- 密码占位符 —— 通常为
x,表示“实际的密码哈希存储在/etc/shadow中”。如果这里是一个*或空值,则表示该账户没有可用密码(这与“锁定”状态不同)。 - UID —— 用户的数字标识。内核只认这个数字,用户名只是为了方便人类识别。
0是超级用户 root,1–999保留给系统服务,1000+分配给人类用户(CentOS 6 及更早版本从500开始分配人类用户)。 - GID —— 用户的主组 ID。用户创建的新文件默认属于这个组。
- GECOS —— 最初是 General Electric Comprehensive Operating System 的全名字段,如今用来存储自由格式的注释信息。可以通过
chfn命令编辑。 - 家目录 —— 用户登录后的
$HOME路径。如果在使用useradd时加上-m参数,系统会从/etc/skel模板目录复制内容到这里。 - 登录 shell —— 用户认证成功后执行的程序。将其设置为
/sbin/nologin或/usr/sbin/nologin可以禁止交互式登录(这是服务账户的标准配置)。
对应的 /etc/shadow 文件中的每一行包含以下信息:密码哈希(前缀表示算法——$6$ 表示 SHA‑512,较新的 Debian/Ubuntu 默认使用 $y$ 表示 yescrypt,$1$ 表示 MD5,现代系统上不应该再看到这种算法)、上次修改密码的天数(自 1970-01-01 起计算),以及五个与密码老化相关的字段:min、max、warn、inactive、expire。如果哈希值前有 ! 或 *,则表示账户被锁定——账户存在,但任何密码都无法匹配。
切勿直接用普通文本编辑器修改这些文件。推荐使用
vipw和vigr,它们会正确地加锁(如/etc/passwd.lock和/etc/shadow.lock),避免在保存时与其他进程(如useradd)冲突导致文件损坏。更好的做法是使用封装好的高级命令。
用户、初始组、附加组#
这是许多教程容易混淆的地方。每个用户账户都有且仅有一个主组(记录在 /etc/passwd 文件中的 GID),以及零个或多个附加组(记录在 /etc/group 文件中,成员列表包含该用户的那些行)。

为什么要区分这两种组呢?
- 主组决定了文件的默认属组。比如,当用户
alice执行touch foo创建文件时,文件的属组会是她的主组(例如alice:alice)。此外,主组还决定了用户登录时内核为进程设置的egid。 - 附加组则用来赋予额外权限。如果把
alice添加到docker组,她就能访问 Docker 的套接字;如果加入sudo(Debian 系统)或wheel(RHEL 系统),她就能获得提权能力。但这些操作不会影响她创建文件时的默认属组。
一个常见的误解是:如果 alice 的主组名就是 alice,那么在 /etc/group 文件中 alice 对应的那一行里,你不会看到她的名字。这是因为主组的归属信息存储在 /etc/passwd 中,而不是 /etc/group。/etc/group 的成员列表只记录附加组成员。如果想查看完整的组信息(包括主组和附加组),可以直接询问内核:
| |
生命周期命令#
每个账户都会经历相同的五个阶段。每条命令只修改特定的文件子集,只要清楚每条命令的作用范围,恢复和审计就变得非常简单。

useradd —— 创建账户#
| |
以下是一些值得记住的关键参数:
| 参数 | 作用 |
|---|---|
-m | 创建用户的家目录,并将 /etc/skel 中的内容复制到其中。如果不加 -m,账户的 $HOME 会指向一个不存在的路径。 |
-s SHELL | 指定登录 shell,例如 /bin/bash、/bin/zsh,或者服务账户常用的 /sbin/nologin。 |
-g GROUP | 指定主组,默认会创建一个与用户名同名的组(GID 相同),这是现代发行版中常见的“用户私有组”模型。 |
-G g1,g2 | 指定附加组,多个组之间用逗号分隔,注意不要加空格。 |
-u UID | 指定 UID,常用于 NFS 共享文件系统场景,确保跨主机的文件归属一致。 |
-r | 创建系统用户,UID 在系统范围内,不参与密码老化,也不创建 /home 目录。 |
-c "..." | 设置 GECOS 字段(注释字段),通常用来描述用户信息。 |
两种常见用法示例:
| |
-M 表示不创建家目录,因为很多服务账户的状态数据存放在其他地方(如 /var/lib/<service>),并不需要单独的家目录。
usermod —— 修改现有账户#
使用 -G 参数时需要注意,它会完全替换现有的附加组列表。如果想追加组,必须使用 -aG:
| |
其他常用操作示例:
| |
锁定的账户仍然存在,文件归属也不会改变,管理员仍可以通过 su - alice 切换到该账户——只是无法通过密码认证登录。这种操作非常适合处理员工离职但其文件仍需保留一段时间的情况。
passwd 和 chage —— 密码管理与过期策略#
passwd 用于设置密码,而 chage 则用于定义密码的过期策略。
| |
chage -l 查看当前策略,chage 修改策略:
| |
需要注意的是,“最大密码使用期限”并不是许多人想象中的安全控制手段。根据 NIST SP 800-63B 的现代建议,不推荐对人类账户强制周期性更换密码,因为这往往会导致用户选择可预测的模式。这种策略更适合服务账户或合规性要求明确的场景。对于人类账户,应更多依赖多因素认证、密码长度和泄露检测机制。
userdel —— 删除账户的最佳实践#
| |
潜在风险:如果 alice 在 $HOME 之外还拥有文件,这些文件在账户删除后会变成“无主文件”,仅显示为一个裸 UID。如果后续创建的新账户分配了相同的 UID,这些文件会被新账户默默继承。避免这种情况需要依靠流程而非技术手段:
- 使用
usermod -L alice(或passwd -l alice)立即锁定账户,禁止进一步登录。 - 等待:让 cron 任务完成,活动的 shell 关闭,并完成文件归属的审计。
- 使用
find / -uid $(id -u alice) -print检查$HOME之外的文件归属,通过chown转移所有权或归档保存。 - 最后执行
userdel -r alice完全删除账户及其相关文件。
组管理#
| |
gpasswd 是专门用来管理 /etc/group 和 /etc/gshadow 文件的工具,相比直接用 usermod -G 操作这些文件更加安全可靠。此外,它还支持将组成员管理权限委派给非 root 用户,这就是所谓的“组管理员”功能的实际应用场景。
sudo:把一条命令变成 root#
直接以 root 用户登录系统是不推荐的,原因有二。首先,像 rm -rf / 这样的危险操作理应受到限制;其次,审计日志只会记录“root 做了某些事”,而在多人共享 root 密码的情况下,这种记录毫无意义。sudo 解决了这两个问题:每次执行命令时都会记录实际用户的身份,同时通过策略文件精确分配权限,不多不少刚刚好。

在 sudoers 文件中,每条规则需要在五个维度上匹配成功后,命令才能被执行:
| |
可以这样理解:“谁,在哪台机器上,能以谁的身份,带什么标签,执行哪些命令。”
编辑 sudoers 文件?用 visudo,别手贱#
| |
visudo 是专门用来编辑 sudoers 文件的工具,它会在保存时进行语法检查,确保配置文件的合法性。如果语法有问题,它会拒绝写入。而直接用 vim 修改 /etc/sudoers 是运维事故的经典案例之一——一旦配置出错,sudo 自己都无法解析配置文件,没有任何方法能修复,除非进入单用户模式。
更推荐使用 /etc/sudoers.d/ 目录下的 drop-in 文件(主配置文件中有一行 @includedir 指令加载这些文件)。相比单一的庞大文件,drop-in 文件更适合版本控制、打包管理和代码审查。
实际工作中常用的几种配置方式#
# 完全的 root 权限,需要输入密码。
alice ALL=(ALL:ALL) ALL
# 按组分配:wheel 组(RHEL)或 sudo 组(Debian)成员可获得 root 权限。
%wheel ALL=(ALL:ALL) ALL
# 精确限制:bob 只能重启 nginx,且无需密码。
bob ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx, \
/usr/bin/systemctl status nginx
# 使用别名让复杂策略更易读。
Cmnd_Alias NGINX_CTL = /usr/bin/systemctl restart nginx, \
/usr/bin/systemctl reload nginx, \
/usr/bin/systemctl status nginx
User_Alias ONCALL = alice, bob, carol
ONCALL ALL=(root) NOPASSWD: NGINX_CTL
一些不太直观但需要注意的规则:
- 命令列表必须使用绝对路径。例如,
bob ... NOPASSWD: nginx不仅无效,还可能带来安全隐患,因为用户可以通过修改$PATH让nginx指向其他程序。 - 如果不指定参数,命令会按前缀匹配。比如,
/usr/bin/systemctl restart nginx只允许这条具体命令,而/usr/bin/systemctl则允许 systemctl 的所有功能(包括poweroff)。 NOPASSWD:虽然方便,但也危险。建议仅用于非交互式自动化任务;对于人类用户,还是应该要求输入密码。Defaults requiretty(某些 RHEL 系统默认启用)会导致sudo在非 tty 环境下无法工作。为自动化账户单独添加一行Defaults:bot !requiretty即可解决。
sudo 启动时读取的文件顺序#
sudo 按以下顺序加载配置:先读取 /etc/sudoers,然后按字母顺序加载 /etc/sudoers.d/ 下的所有文件,接着解析用户组关系,最后应用 Defaults 配置。要查看某个用户的完整生效策略,可以用 sudo -ll,比手动分析配置文件更可靠。
su 和 sudo 的区别#
su - 会以目标用户的身份启动一个 shell(默认是 root),需要输入目标用户的密码;而 sudo 则是以另一个用户的身份运行某条命令,只需要输入你自己的密码。绝大多数情况下,sudo 是更好的选择:它的审计记录更详细,而且你永远不需要共享 root 密码。
PAM:所有这些东西底下的那一层#
无论是 sudo、sshd、login,还是 gdm、cron、su、passwd、crond,这些工具都不会自己去校验密码,而是把这项任务交给 PAM(Pluggable Authentication Modules)。PAM 是一组动态链接库(.so 文件),每个服务的配置都存放在 /etc/pam.d/ 目录下。理解 PAM 的工作机制,可以让你从“不知道为什么这个账号登不进去”的迷茫,迅速转变为五秒钟定位问题的高手。

一个 PAM 服务配置文件通常包含四个模块栈:
- auth —— 验证身份。
pam_unix.so检查/etc/shadow;pam_sss.so负责与 SSSD/LDAP/AD 交互;pam_google_authenticator.so提供 TOTP 双因素认证。 - account —— 即使密码正确,也需要判断账户是否允许当前登录。比如密码老化策略、
nologin标志、时间段限制、来源主机检查等。 - password —— 仅在修改密码时触发。
pam_pwquality.so检查密码强度,pam_pwhistory.so防止重复使用旧密码,最后由pam_unix.so写入新的密码哈希。 - session —— 登录成功后设置用户的工作环境。例如通过
pam_limits.so设置资源限制,pam_systemd.so创建 systemd 用户会话,pam_mkhomedir.so在首次登录时创建家目录,以及记录lastlog。
每行配置都有一个控制标志,用于决定该模块的结果如何影响整个栈的行为:
required—— 必须成功;如果失败,整个栈会标记为失败,但 PAM 仍会继续执行后续模块,目的是不让用户知道具体哪一步出了问题(这是为了防止信息泄露)。requisite—— 必须成功;一旦失败,立即终止整个栈的执行。sufficient—— 如果成功,并且前面没有required模块失败,则整个栈直接通过。optional—— 结果会被忽略,除非它是栈中唯一的模块。
举个实际例子——在 Debian 系统上启用强密码策略。编辑 /etc/pam.d/common-password 文件:
password requisite pam_pwquality.so retry=3 minlen=12 \
dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1 \
difok=4 enforce_for_root
password required pam_pwhistory.so remember=5 use_authtok
password [success=1 default=ignore] pam_unix.so obscure use_authtok yescrypt
这段配置的意思是:密码长度至少 12 个字符,必须包含至少一个数字、一个大写字母、一个特殊字符和一个小写字母(-1 表示“这一类至少满足一次”);新密码与旧密码相同的字符不能超过 4 个;记住最近 5 次的密码哈希,防止重复使用;最后用现代的 yescrypt 哈希算法存储密码。修改前,建议先用一个非 root 账户运行 passwd <自己> 测试一下,确认无误后再退出登录。
排查问题时,日志是最有力的工具:
| |
如果密码明明正确却仍然无法登录,通常是因为以下原因之一:账户被锁定(/etc/shadow 中密码哈希前有 !);shell 被设置为 /sbin/nologin;/etc/nologin 文件存在导致 pam_nologin 阻止所有登录;sshd_config 中配置了 AllowUsers 或 DenyUsers;或者密码已经超过了 inactive 时间限制。
几个现场常见的方案#
共享项目目录的配置#
目标:/srv/project 对 developers 组的所有成员可读写,对组外用户完全不可见。同时,确保在该目录下创建的新文件始终归属于 developers 组,避免同事之间因权限问题互相“锁死”。
| |
这里的 2770 中的 2 是目录的 SGID 位,它的作用是让新创建的文件继承目录的属组,而不是创建者的默认组。如果没有设置 SGID,当 alice(默认组为 alice)创建文件时,文件的属组会是 alice,导致 bob 无法编辑。
如果需要更精细的控制,比如“developers 组可写,但 carol 只读”,可以使用 POSIX ACL:
| |
正确配置服务账户#
| |
--system 选项会分配一个低于普通用户的 UID,并跳过密码老化设置。--user-group 会自动创建一个与用户名同名的组。--no-create-home 的原因是,我们希望通过 install 手动创建状态目录,并将权限固定为 0750。在 systemd 配置中,服务应以 User=myapp Group=myapp 的身份运行,这也是磁盘上唯一应该拥有该应用数据的用户身份。
分级管理 sudo 权限#
Cmnd_Alias READ_LOGS = /usr/bin/journalctl, /usr/bin/tail, /usr/bin/less
Cmnd_Alias NGINX_CTL = /usr/bin/systemctl restart nginx, \
/usr/bin/systemctl reload nginx, \
/usr/bin/systemctl status nginx
# 完全管理员权限
alice ALL=(ALL:ALL) ALL
# 值班人员:仅允许操作 nginx,无需密码(凌晨被叫起来处理问题时,不能因为输错密码耽误时间)
bob ALL=(root) NOPASSWD: NGINX_CTL
# 支持人员:允许查看日志,但需要密码
carol ALL=(root) READ_LOGS
从 CSV 文件批量创建用户#
| |
chpasswd 是处理批量更新密码的正确工具,它接受 user:password 格式的输入;而 passwd --stdin 仅适用于 RHEL 系统。chage -d 0 是一个小技巧,可以在不分配长期有效随机密码的情况下,强制用户首次登录时更改密码。
下一步#
本文已经完整介绍了操作模型的核心内容:文件结构、生命周期相关的命令、sudo 策略语言,以及 PAM 栈。接下来的两篇文章会在此基础上进一步展开:
- Linux 文件权限
—— 深入讲解
rwx权限、前面提到的共享目录用到的 SUID/SGID 位,以及 POSIX ACL 的使用。 - Linux 系统服务管理
—— 探讨 systemd 配置单元中
User=、Group=和DynamicUser=指令如何让传统的服务账户几乎不再必要。
还有一些值得参考的手册页和文档:man 5 sudoers、man 8 pam.d、man 5 shadow。如果你需要为多台主机(比如十几台以上)实现集中身份管理,还可以查阅 FreeIPA 和 SSSD 的官方文档。