1. 误删用户后的连锁反应:为什么基础命令反而最值得复盘
1.1 一次事故的完整经过
两三年前我接手一台存量服务器,运维交接文档里只写了“root随便用”。那天业务方要求清理一个已经离职的同事账号,我顺手敲了userdel testuser,没带任何参数,也没先查这个用户的家目录和计划任务。结果第二天业务方反馈:某个项目目录里的文件全部变成了一串数字属主,备份脚本也跑不动了,因为crontab文件跟着用户一起没了。
这就是Linux用户管理最容易被低估的地方——userdel删的不只是一个认证身份,还有该用户关联的定时任务、后台进程、文件属主关系。那次之后,我下定决心把所有用户与组相关的机制完整梳理了一遍,也养成了一个习惯:动手前先id、getent passwd、find / -user查清楚用户和文件的关系,再决定怎么处理。
1.2 基础命令不“基础”:从用户到权限的传递链
很多新手觉得用户管理无非是useradd、passwd、groupadd这三板斧,能加人能加组就行。但实际线上环境中,用户和组直接决定系统的安全边界:
- 内核不认“用户名”,只认数字UID和GID,用户名只是给人看的映射。
- 文件权限位的三个维度——属主、属组、其他用户——全部建立在用户和组的基础之上。
- 进程能不能读某个文件、能不能执行某个程序、能不能监听某个端口,最终都由启动它的用户身份决定。
sudo的授权规则、su的切换逻辑、systemd服务从哪个身份运行,全都依赖用户和组的解析。
也就是说,用户与组管理是整个Linux权限体系的底座。底座没打牢,上面堆再多防火墙规则和安全策略都是空中楼阁。
1.3 哪些场景下必须懂用户与组管理
我最常见的需求来自这几类场景:
| 场景 | 典型痛点 | 涉及的用户/组知识 |
|---|---|---|
| 多人共用一台服务器 | 权限混乱,A能改B的文件 | 附加组、文件属组、目录权限 |
| 应用服务独立部署 | 用root跑Web服务,被入侵即沦陷 | 最小权限用户、sudo授权 |
| 离职/转岗人员账号清理 | 删了用户但文件和任务残留 | userdel参数、find清理 |
| 日志和备份权限异常 | 脚本运行时没有写权限 | 有效组、目录组权限 |
| 新建项目协作目录 | 多人共享、跨组访问 | SGID、Sticky Bit、共享组设计 |
如果你正在管理Linux服务器,或者打算走运维、网工、嵌入式方向,这部分内容不是“会敲命令就行”,而是要理解命令背后的解析链路和文件结构。这篇博文我就从底层文件开始,把用户和组的全链路讲一遍。
2. 用户信息到底存在哪:/etc/passwd与/etc/shadow逐字段拆解
2.1 /etc/passwd七字段详解
在Linux里,用户信息主要存在两个文件中:/etc/passwd和/etc/shadow。我们先看/etc/passwd,它是所有用户都能读取的文本文件,每一行代表一个用户,用冒号分成7个字段。
root:x:0:0:root:/root:/bin/bash zhangsan:x:1000:1000:张三:/home/zhangsan:/bin/bash按顺序拆解:
| 字段 | 示例值 | 含义 |
|---|---|---|
| 登录名 | zhangsan | 用户登录时使用的名字,全系统唯一 |
| 密码占位 | x | 真正密码在/etc/shadow,这里只放占位符 |
| UID | 1000 | 用户的数字身份,内核识别用的是它 |
| GID | 1000 | 用户的初始组ID |
| 备注信息 | 张三 | 通常放姓名或联系方式,可以用usermod -c修改 |
| 家目录 | /home/zhangsan | 登录后的初始目录,存放个人配置 |
| 登录Shell | /bin/bash | 登录后启动的解释器,可以是/sbin/nologin |
这里有两个地方需要特别注意。
第一,密码字段是“x”不代表没有密码,而是密码已经被搬到了/etc/shadow中。老系统里这个字段可能直接存的是加密后的密码串,但权限控制较差的/etc/passwd能被所有用户读取,一旦拿到加密串就可以离线爆破,所以现代Linux统一把密码迁移到了root专属的/etc/shadow。
第二,登录Shell设置成/sbin/nologin的用户,不是“没有Shell”,而是“拒绝登录”。这个设计常用于系统服务账号,比如apache、mysql、nobody,它们需要以独立身份运行进程,但管理员不希望有人用这个账号直接SSH登录。服务账号家目录也常被设置为/或/var/empty。
2.2 /etc/shadow的加密字段与密码策略
/etc/shadow每行也分9个字段,但普通用户读不了,只有root或有sudo权限的账号能查看。
zhangsan:$6$rounds=656000$盐值$哈希值:19000:0:99999:7:0:19080:核心字段逐个说:
- 登录名:与
/etc/passwd对应。 - 加密密码:格式为
$算法$盐$哈希。$6$表示SHA-512算法,$y$是yescrypt,新系统更常用。这一串无法逆向破解,只能暴力猜测。 - 最后一次修改密码的天数:从1970-01-01起算,19000大概对应2022年左右。可以用
chage -l zhangsan查看可读时间。 - 最小修改天数:几天内禁止改密码。
- 最大修改天数:密码到期天数。
- 到期前警告天数:到期前几天提醒用户。
- 宽限期:到期后几天内仍可登录,但会强制要求改密。
- 过期时间:账号本身失效日期,到点直接不能登录。
- 保留字段:目前未使用。
这些字段平常不会直接改,都是用chage命令去调整。比如我之前给一个运维账号设置90天强制改密、提前7天警告,就用:
chage -M 90 -W 7 zhangsan如果需要“密码永不过期”,常见做法是:
chage -I -1 -M -1 -E -1 zhangsan三个-1分别表示:宽限期无限、最大期限无限、账号不过期。
2.3 UID与GID:数字身份才是内核真正认识的
很多初学者不理解为什么/etc/passwd里同时有用户名和UID。实际在Linux内部,所有与身份相关的判断全是看数字:
ls -l显示文件属主时,系统会拿文件里的UID去/etc/passwd里查用户名;查不到就显示一串数字。- 进程发出的所有权限请求,内核只认证进程的有效UID和GID。
- 网络文件系统NFS在跨服务器共享文件时,认的也是UID,而不是用户名。所以我在配置NFS时遇到过:服务器A的zhangsan UID是1000,服务器B的zhangsan UID是1001,两边目录共享后文件属主看着一样,实际却是两个人。
UID范围在不同发行版下有细微差别,但大体遵循:
| UID范围 | 说明 |
|---|---|
| 0 | root,超级用户 |
| 1-999 | 系统账号,用于服务进程 |
| 1000-65533 | 普通用户 |
| 65534 | nobody,通常用于匿名访问 |
| 65535 | 早期表示未知账号,少量系统使用 |
管理经验:给应用创建专用用户时,不要随手分配UID,最好固定重要的UID,配合rsync --numeric-ids或NFS这种跨机场景才不会乱。
2.4 用户家目录与登录Shell的默认值
useradd不指定参数时,会按照/etc/default/useradd和/etc/login.defs里的默认值创建家目录和Shell。我在一个最小化安装的CentOS系统上,新建用户后默认Shell经常是/bin/bash,但Ubuntu默认是/bin/sh,这个差异容易让脚本语法出问题——比如数组语法在sh下直接报错。
合理做法是显式指定Shell:
useradd -s /bin/bash zhangsan对于纯服务账号:
useradd -r -s /sbin/nologin -M myservice-r表示创建系统账号,-M表示不创建家目录。服务根本不需要家目录,给它创建一个反而留下不必要的文件位置,清理时还容易漏。
3. 用户的完整生命周期:创建、修改、锁定、删除的实操细节
3.1 useradd参数全解与推荐实践
useradd是创建用户的主命令,我只列线上真正用得上的:
useradd -u 1001 -g 1000 -G wheel,develop -c "真实姓名" -d /home/zhangsan -s /bin/bash -e 2026-12-31 zhangsan逐个拆开看:
-u:指定UID,不指定则按/etc/login.defs的规则自动递增。-g:初始组。可以指定组名或GID,该组必须先存在。-G:附加组,多个组用逗号分割,中间不要加空格。-c:备注信息。-d:家目录路径。-s:登录Shell。-e:账号过期时间,到了日期自动失效,适合临时授权。-M:不创建家目录。-m:强制创建家目录,某些发行版默认不创建。-r:创建系统账号(UID进入系统范围)。
我自己的推荐模板是:普通开发运维用户,固定UID范围,加入wheel组用于sudo授权;应用服务账号用-r -M -s /sbin/nologin三件套,避免服务账号直接登录。
另外要提醒:useradd只是创建账号,没有设置密码前该账号处于锁定状态,不能登录。需要接着用passwd设置密码。
3.2 passwd命令与批量修改:chpasswd
设置密码的常规做法:
passwd zhangsan交互式输入两次密码,简单但不利于批量操作。如果要在脚本里设置密码,我用chpasswd:
echo "zhangsan:NewPass123" | chpasswd也可以批量读取文件:
chpasswd < userlist.txt文件格式就是每行用户名:新密码。需要注意密码传入时不要出现在shell历史里,下面这种写法会让密码留在~/.bash_history:
# 不推荐:密码会在历史记录中出现 passwd zhangsan --stdin # 某些发行版支持,但不安全更稳妥的写法是用read -s提示输入:
read -s -p "请输入新密码: " newpass echo "zhangsan:$newpass" | chpasswd还有一个容易被忽略的操作是passwd -l和passwd -u,分别锁定和解锁账号。锁定账号是在密码串前面加“!”,解锁则移除。但注意,passwd -l锁的是密码认证,如果用户配置了SSH密钥登录,依然可以进来。后面我会专门讲这个坑。
3.3 usermod:修改用户属性的关键选项
用户创建后基本属性需要调整时,用usermod。最常见的三个场景:
- 把用户加入附加组:
usermod -aG docker zhangsan-aG中的-a表示追加,不加-a时会把用户从原有附加组中全部移除,只保留这次指定的组。我犯过一次这个错误:想把用户加到docker组,结果把用户从wheel等附加组里踢了出去,sudo权限直接消失。所以凡是追加组成员,永远要写-aG。
- 修改用户家目录:
usermod -d /data/home/zhangsan -m zhangsan-d重新指定家目录,-m把原家目录的内容迁移过去。只改-d不加-m,用户登录后会面对一个空家目录,历史的.bashrc全部丢失。
- 锁定和解锁账号:
usermod -L zhangsan # 锁定 usermod -U zhangsan # 解锁3.4 用户锁定与解锁的正确姿势
我上面提到一个关键问题:usermod -L和passwd -l锁定的只是密码认证。如果用户配置了SSH公钥,依然能通过密钥登录。要真正禁用一个账号,应该同时做这几件事:
usermod -L zhangsan # 锁密码 usermod -s /sbin/nologin zhangsan # 改Shell,禁止交互登录如果是临时冻结,也可以直接设置账号过期:
chage -E 0 zhangsan这样密码和密钥认证都进不来,到期日直接为0表示立即过期。
还有一种“软锁定”做法是只改Shell为/sbin/nologin而不锁密码。好处是用户看到提示“This account is currently not available”,管理员不需要记住后续还要解锁密码。
3.5 userdel的注意事项与清理残留
删除用户是误操作率最高的命令,我现在强制自己遵守两条规则:
- 查清楚用户关联的所有文件和进程再删。
- 删完后复查,而不是删完就走。
推荐顺序:
# 第一步:查看用户关联进程 ps -u zhangsan # 第二步:查找属于该用户的所有文件 find / -user zhangsan 2>/dev/null # 第三步:删除用户,连带家目录和邮件池 userdel -r zhangsan-r会同时删除用户家目录和/var/mail下的邮箱文件,这是最常用的参数。但如果家目录在-r之外的路径,或者用户归属的文件散落在/data、/opt,这两个命令解决不了,需要手动find出来处理,通常是chown给接管人,而不是直接rm。
还有一点容易踩:用户被删除后,其UID会被释放,过阵子新用户自动分配到这个UID,于是新用户就“继承”了之前的所有文件。如果你清理不干净,会造成很隐蔽的权限串号。所以删除用户后,最好把空出来的UID加入/etc/login.defs的跳过列表,或者立刻用新用户做一次全盘文件属主复查。
3.6 批量创建用户的脚本思路
批量场景常见于实验室、培训机房、临时项目组。我一般这么写:
#!/bin/bash for user in zhang01 zhang02 zhang03; do useradd -m -s /bin/bash "$user" echo "$user:Init@123456" | chpasswd chage -d 0 "$user" # 强制第一次登录修改密码 done其中chage -d 0比较关键:把“最后一次改密时间”设为0,用户第一次登录就会被要求立即修改密码。这是批量创建临时账号时防弱密码的兜底手段。
4. 组管理的运行机制:初始组、附加组与有效组
4.1 /etc/group的四字段结构
组信息存储在/etc/group,一行四字段:
develop:x:1001:san,zhang| 字段 | 示例 | 含义 |
|---|---|---|
| 组名 | develop | 唯一组名 |
| 组密码占位 | x | 实际组密码在/etc/gshadow,极少数情况用 |
| GID | 1001 | 组的数字ID |
| 组成员 | san,zhang | 附加加入该组的用户,逗号分隔 |
注意,/etc/group第四列的成员列表只显示附加组关系。如果一个用户的初始组是develop,他并不会出现在这个列表里,而是通过/etc/passwd的GID字段来关联。很多人误以为修改/etc/group第四列就能完全控制所有成员,其实初始组关系不在这里体现。
4.2 groupadd、groupmod、groupdel与gpasswd
组的生命周期管理和用户类似:
groupadd devops # 创建组 groupmod -n develop devops # 组改名 groupdel develop # 删除组删除组之前必须保证没有用户以它为初始组,否则会报错。如果只是普通附加组成员,groupdel会把这些成员关系一并清掉。
gpasswd则用于管理组密码和组内成员:
gpasswd -a zhangsan develop # 把用户追加进组 gpasswd -d zhangsan develop # 把用户移出组 gpasswd -M user1,user2 develop # 直接指定完整成员列表 gpasswd -A user1 develop # 设置组管理员在没有usermod -aG的旧系统上,gpasswd -a就是唯一的添加成员方式。它有在线生效的特点,不需要用户重新登录就立即具备新的附加组身份,而usermod -aG对新登录shell立即生效,对已登录的进程需要重开会话才生效。这个细节在排查“明明加了组还是没权限”时会用到:用户当前会话的权限是在登录那一刻就确定下来的,附加组的变更要重新登录才加载。
4.3 newgrp与有效组:临时切换组身份
用户可能同时属于多个组,文件创建时使用的是什么组身份?答案是有效组。用户登录后默认的有效组就是初始组。如果想临时把有效组切换成某个附加组,用newgrp:
newgrp develop切换后,当前shell新建的文件就会以develop作为属组。这是旧时代的做法,现代应用里用得不多,但在某些要求文件归属于特定项目组的场景下仍然有效。需要理解的是,newgrp本质上会启动一个全新的shell环境,环境变量会重置,如果脚本依赖原来的PATH,切换后可能会找不到命令。
真正的组身份可能和有效组不同,Linux里还有“真实组”“保存组”这些概念,但日常运维只需要抓住一句话:新建文件的属组取决于进程的有效组,而不是/etc/group里的完整成员关系。
4.4 组与项目协作:多用户共享目录的标准做法
多人协作目录是我在服务器上配置得最多的权限需求。标准做法有这么几步:
groupadd project_alpha usermod -aG project_alpha user1 usermod -aG project_alpha user2 mkdir -p /srv/project_alpha chown root:project_alpha /srv/project_alpha chmod 2770 /srv/project_alpha这里2770的解读是:
2:SGID位,目录下新建文件的属组自动继承目录属组。7:属主权限,读写执行。7:属组权限,读写执行。- 最后的
0:其他用户无任何权限。
有了SGID,user1在目录里创建的文件自动属于project_alpha组,user2只要属于这个组就能修改。否则就会出现:user1创建文件后,user2因为文件属组是user1的初始组而无法编辑。
还需要配合umask让新文件自动带组写权限,不然即使属组对了,权限位也可能是rw-r--r--,组内成员只能看不能改。这点我在第5节细说。
4.5 为什么建议用户使用附加组而非初始组
很多发行版默认创建用户时会同时创建一个同名组,并且把同名组设为初始组。这种私有组方案本身没问题,但如果你希望用户加入某个业务组,不要把业务组设成初始组,而是用附加组。
原因很简单:初始组决定用户默认新建文件的属组。如果用户初始组是develop,那他在/tmp创建一个临时文件,自动就属于develop组,其他项目组的人可能也会有这个组的写权限。这等于不经意间把临时文件的管理边界扩大到了整个组。反过来,用私有组当初始组,用户默认文件只属于自己的私有组,加入的业务组只在特定目录里通过SGID体现权限,边界清晰得多。
5. 权限基线的落地:用户组与文件权限的联动
5.1 文件权限rwx的底层含义
用户和组最终要通过文件权限发挥作用。rwx三个位置的含义大家都会背,但有几个细节值得强调:
- 目录的
r:能不能列出目录名。 - 目录的
w:能不能在目录里创建、删除、重命名文件。 - 目录的
x:能不能进入目录,能不能访问目录内文件的元数据。
这里最反直觉的是:删除一个文件,看你有没有文件所在目录的写权限,而不是文件本身的写权限。所以我见过有人给某个只读文件开了目录的w权限,文件虽然只读,依然能被删除。僵局场景是把共享数据目录设成chattr +i来防删,这也是常见做法。
文件权限解码示例:
-rwxr-x---- 第一个字符
-表示普通文件,目录是d,链接是l,块设备是b,字符设备是c。 - 属主
rwx,属组r-x,其他---。 r=4,w=2,x=1,相加后就是常见的750等数字。
5.2 SUID、SGID与Sticky Bit的现实应用
特殊权限位是用户组权限最容易忽略的部分。
- SUID(4):执行该程序时,进程以程序属主的身份运行,而不是执行者的身份。最典型的例子是
/usr/bin/passwd,普通用户执行它时需要以root身份修改/etc/shadow,所以它带有SUID位。你可以看:
ls -l /usr/bin/passwd # -rwsr-xr-x. 1 root root 34400 ...如果担心安全,可以针对自建脚本排查是否有意外SUID。用下面的命令找出所有SUID程序:
find / -perm -4000 -type f 2>/dev/nullSGID(2):作用于目录时,目录内新建文件自动继承目录的属组,这在共享目录场景中至关重要;作用于文件时,进程以文件属组身份运行,常见于某些日志程序。
Sticky Bit(1):用在
/tmp这类共享目录,目录允许所有人写,但用户只能删除自己拥有的文件。/tmp默认权限是drwxrwxrwt,最后一个t就是Sticky Bit。如果你准备搭建一个多人共享上传区,这个权限位比直接chmod 777安全得多。
设置特殊权限的数字写法:
chmod 4770 /opt/tool chmod 2770 /srv/project chmod 1777 /tmp5.3 umask与新建文件的默认权限
很多组协作问题最后定位在umask上。umask决定了新建文件和目录的“减掉”哪些权限。默认情况下:
touch newfile # 666 - umask(通常是022) = 644,属主可写,组和其他人只读 mkdir newdir # 777 - 022 = 755,属组和其他人没有写权如果用户属于协作组,需要让同组人直接修改文件,就得调整umask为002:
umask 002这样新建文件的权限是664,目录是775,组内成员可以编辑。配合上SGID目录,整个协作目录里新生成的文件都是组可写的。
需要理解的是,应用服务自己启动时会设置自己的umask,比如很多Java服务默认的umask 027,你改了用户shell的umask,不一定影响后台服务创建的日志文件。排查“服务创建的日志别人看不了”时,要确认服务进程的umask,而不是登录shell的umask。
5.4 sudo与/etc/sudoers:最小权限授权
用户和组管理里很关键的一个出口就是sudo。我不会建议任何人在多用户环境里直接分享root密码,正确思路是:
- 维护团队的管理员加入
wheel组或sudo组,获得完整sudo权限。 - 普通业务用户只授予特定命令的免密权限。
/etc/sudoers的常用配置:
# 允许wheel组所有成员执行全部命令 %wheel ALL=(ALL) ALL # 允许devops组无密码执行systemctl restart app %devops ALL=(ALL) NOPASSWD: /bin/systemctl restart app # 允许指定用户执行特定命令 zhangsan ALL=(ALL) /usr/bin/systemctl restart nginx修改/etc/sudoers务必用visudo,它会做语法检查,避免写错一个标点导致sudo全部不可用的灾难现场。
有一个实际经验:把运维人员加入wheel的同时,不要顺手把NOPASSWD配置成所有命令都免密。免密看似省事,但对键盘记录、误操作完全没有缓冲,一个rm -rf /var连确认都没有。至少保留密码提示,作为最后一道心理防线。
5.5 用户与组的安全基线建议
结合我的维护经验,整理了一份用户和组管理的安全基线,适合大多数Linux服务器:
- root账号禁止SSH直接登录,管理员通过普通用户加sudo进入,再用
su -切换到root。 - 为每个应用创建独立系统账号,
-r -M -s /sbin/nologin,应用只拥有自己目录下的权限。 - 服务账号不要加入sudo组,任何交互式权限都不给。
- 长期未登录账号定期检查,超过90天未登录且无业务关联的,锁定或删除。
- 关键应用目录设置SGID,确保协作组内文件属组一致性。
- 定期扫描SUID文件,出现新增的SUID二进制要立刻排查来源。
- 收紧家目录权限:
chmod 700 /home/zhangsan或至少750,避免其他人读取个人配置中的密钥和敏感信息。 - 密码策略通过
/etc/login.defs和chage强制,密码定期更换但不要过于频繁导致用户把密码写在便利贴上。
6. 高频故障排查:用户管理中的典型场景与排查链路
6.1 “User not in sudoers file”如何处理
现象:用户执行sudo时报错,提示当前用户不在sudoers文件中。
排查链路:
# 第一步:查看用户所属组 id zhangsan # 第二步:确认是否属于wheel或sudo组 groups zhangsan # 第三步:切换root直接编辑sudoers visudo如果是生产环境临时需要授权,我会先把用户加到wheel组:
usermod -aG wheel zhangsan然后让用户重新登录再试。注意:刚加入组后,用户当前已登录的会话不会立即生效,必须退出重新登录,这是排查时最容易误判的地方。
6.2 密码正确却无法登录
这个坑我踩过一次:用户说密码是对的,但SSH登录一直失败。排查思路:
# 第一步:确认密码认证是否被锁 passwd -S zhangsan # LK表示锁定,PS表示有可用密码,NP表示无密码 # 第二步:检查账号是否过期 chage -l zhangsan # 第三步:检查Shadow里的密码字段是否被加了特殊前缀 grep zhangsan /etc/shadow # 如果密码字段以!开头,说明账号被锁定还有一种情况是SSH服务端配置了AllowUsers或AllowGroups白名单,把用户挡在了外面。排查时看/etc/ssh/sshd_config:
grep -E "AllowUsers|AllowGroups|DenyUsers" /etc/ssh/sshd_config这类问题最容易出现的原因就是:管理员在/etc/passwd或/etc/shadow上做了手工修改,破坏了字段结构,导致PAM模块解析失败。手工改用户文件永远不如用官方命令安全。
6.3 用户已删但文件属主显示数字UID
删除用户后,该用户留下的文件不会自动清理,ls -l会显示数字UID而不是用户名。这个数字本身无害,但会造成两种隐患:新用户复用UID后“继承”旧文件权限;备份脚本按用户名做转储时漏掉这些文件。
处理方式:
# 找出所有属主为1000的文件 find / -uid 1000 2>/dev/null # 统一改成接管人 find / -uid 1000 -exec chown zhangsan_new {} \; 2>/dev/nullfind -exec逐个执行chown,大目录下会比较慢,也可以用xargs批量:
find / -uid 1000 -print0 2>/dev/null | xargs -0 chown zhangsan_new如果你不想重新分配同名用户,只是保留文件给别的现有用户,就把UID替换成对方的UID。
6.4 UID/GID冲突的排查
Uid冲突通常出现在NIS/NFS、容器宿主机、不同发行版服务器合并等场景。现象是:同一个用户名在两台机器上UID不同,通过NFS共享文件后,权限对不上号。排查方法:
# 查看所有Linux服务器上的用户UID getent passwd | awk -F: '{print $1":"$3}' # 对比哪个账号的UID在主机间不一致处理策略是统一UID。选择一台规范服务器作为基准,把其他服务器上同名用户的UID通过usermod -u改过来。改完后还要立即修复文件属主:
find / -user old_uid -exec chown new_uid {} \; 2>/dev/null6.5 HOME目录权限错误导致的环境异常
现象:用户登录后出现Service is unknown、bash环境不加载、/root/.bashrc报错。
最常见原因是家目录属主或权限不对。比如把家目录chmod 777了,或者从旧机器迁移时属主变成了数字UID。修复:
chown -R zhangsan:zhangsan /home/zhangsan chmod 700 /home/zhangsan还有一个细节:家目录所在父目录不能有other的写权限,否则SSH会拒绝登录并提示bad ownership or modes for home directory。这类问题常出现在把家目录搬到了/data或/opt下、父目录权限被设置成了777的场景。
6.6 用好内置检查工具:pwck、grpck与id、getent
最后推荐几个我排查用户组问题时的常用工具:
| 命令 | 作用 | 使用时机 |
|---|---|---|
id username | 查看用户UID、GID、所有组 | 一切权限问题排查的起点 |
getent passwd username | 查看用户实际生效的记录 | 判断NSS解析来源(本地文件或LDAP) |
getent group groupname | 查看组的实际成员 | 用户不在组里但/etc/group里有,可能解析来源有问题 |
pwck | 检查/etc/passwd与/etc/shadow一致性 | 怀疑手工改坏了账户文件时 |
grpck | 检查/etc/group与/etc/gshadow一致性 | 组文件异常时 |
pwconv | 把密码从passwd同步到shadow | /etc/shadow丢失或异常时 |
有一次我排查用户无法登录,最后发现是/etc/shadow里的账号行被误删了,而/etc/passwd里还在。用pwck立刻提示“no matching password entry”,用pwconv按/etc/passwd重建/etc/shadow就恢复了。这些命令平时用得少,但关键时刻能救命。
在我后来的运维习惯里,每隔一段时间都会跑一次pwck和grpck,成本极低,却能提前发现账号文件里隐藏的格式损坏和字段错位,比问题发生后大海捞针地排查要省事得多。