用户与组管理
Linux 运维基础 · 第五章 目标:理解用户体系,掌握用户创建和 sudo 权限配置
1. 概述#
Linux 是多用户系统。同一个服务器上可以有 root、运维、开发、数据库等多个角色同时登录。本章覆盖用户体系的三张核心档案表(passwd/shadow/group)、用户增删改、sudo 权限配置——这些都是运维日常必做的操作。
2. 用户体系核心文件#
2.1 /etc/passwd — 用户账户信息#
bash
cat /etc/passwd | head -3
# root:x:0:0:root:/root:/bin/bash
# daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
# heiye:x:1000:1000:Black Night:/home/heiye:/bin/bash每行 7 个字段,用 : 分隔:
| 字段顺序 | 含义 | 示例 |
|---|---|---|
| 1 | 用户名 | root |
| 2 | 密码占位符 | x(密码已移到 /etc/shadow) |
| 3 | UID(用户 ID) | 0=root, 1-999=系统用户, 1000+=普通用户 |
| 4 | GID(主组 ID) | 0 |
| 5 | 用户描述(GECOS) | root |
| 6 | 家目录 | /root |
| 7 | 登录 Shell | /bin/bash(/usr/sbin/nologin 表示不能登录) |
2.2 /etc/shadow — 密码哈希存储#
bash
sudo cat /etc/shadow | grep heiye
# heiye:$6$randomsalt$hashedpasswordstring...:19000:0:99999:7:::每行 9 个字段,用 : 分隔:
| 字段 | 含义 |
|---|---|
| 1 | 用户名 |
| 2 | 密码哈希($1$=MD5[已淘汰]、$5$=SHA-256、$6$=SHA-512、$y$=yescrypt[Debian 11+/Ubuntu 新默认];!/!! 或 * = 无法用密码登录) |
| 3 | 上次修改密码的日期(从 1970-01-01 起的天数) |
| 4 | 密码最短使用天数(0 = 可随时改) |
| 5 | 密码最长使用天数(99999 = 近乎永不过期) |
| 6 | 密码过期前警告天数 |
| 7 | 密码过期后宽限天数 |
| 8 | 账户失效日期 |
| 9 | 保留字段 |
运维要点:如果shadow密码字段是 !,说明账户被锁定;如果是 *,说明是系统账户不允许登录。
2.3 /etc/group — 组信息#
bash
cat /etc/group | head -3
# root:x:0:
# daemon:x:1:
# docker:x:998:heiye,deploy每行 4 个字段:
| 字段顺序 | 含义 | 示例 |
|---|---|---|
| 1 | 组名 | docker |
| 2 | 组密码占位符 | x |
| 3 | GID | 998 |
| 4 | 组成员列表(逗号分隔) | heiye,deploy |
查看用户属于哪些组:
bash
groups heiye
# heiye : heiye docker sudo
id heiye
# uid=1000(heiye) gid=1000(heiye) groups=1000(heiye),998(docker),27(sudo)2.4 主组 vs 附加组#
- 主组(primary group):
/etc/passwd第 4 字段的那个 GID,只有一个。你新建文件时,文件的属组默认就是你的主组。 - 附加组(supplementary groups):
/etc/group里把你列为成员的其它组,可以有多个。决定你能访问哪些"按组授权"的资源(例如加入docker组才能免 sudo 跑 docker)。
bash
id # 一眼看全:uid、主组(gid=)、所有附加组(groups=)
groups # 只列组名
# 刚被加进一个附加组后,需要重新登录(开新会话)才生效——因为组身份在登录时就固定了
newgrp docker # 无需重新登录,临时把「当前 shell 的主组」切成 docker
# 之后新建的文件属组即为 docker;exit 退出这个子 shell 就还原3. 用户管理命令#
3.1 useradd — 创建用户#
bash
# 最简单的创建(使用系统默认值)
useradd deploy
# 完整参数创建
useradd -u 1500 \ # 指定 UID
-g developers \ # 指定主组
-G docker,sudo \ # 附加组(逗号分隔)
-d /opt/deploy \ # 指定家目录
-s /bin/bash \ # 指定 Shell
-c "Deploy User" \ # 描述
-m \ # 创建家目录
deploy # 用户名
# 创建不允许登录的用户(仅用于运行服务)
useradd -r -s /usr/sbin/nologin myapp
# -r 表示系统用户,UID < 1000常用参数速查#
| 参数 | 说明 |
|---|---|
-u | 指定 UID |
-g | 指定主组(必须已存在) |
-G | 指定附加组 |
-d | 指定家目录 |
-s | 指定登录 Shell |
-c | 添加描述信息 |
-m | 自动创建家目录 |
-r | 创建系统用户 |
-e | 指定过期日期(YYYY-MM-DD) |
3.2 usermod — 修改用户#
bash
# 修改描述
usermod -c "New Description" deploy
# 添加到附加组
usermod -aG docker deploy # -a 表示 append,不用会覆盖原有附加组!
# 锁定用户
usermod -L deploy # 在 shadow 密码前加 !
# 解锁用户
usermod -U deploy
# 修改 Shell
usermod -s /sbin/nologin deploy # 禁止登录
# 修改家目录
usermod -d /new/home -m deploy3.3 userdel — 删除用户#
bash
userdel deploy # 删除用户,保留家目录
userdel -r deploy # 删除用户 + 删除家目录 + 删除邮件池3.4 passwd — 密码管理#
bash
passwd deploy # 设密码(root 可直接设)
passwd -l deploy # 锁定密码
passwd -u deploy # 解锁密码
passwd -S deploy # 查看密码状态
passwd -e deploy # 强制用户下次登录修改密码
passwd -d deploy # 删除密码(危险)3.5 查看登录历史#
bash
last # 所有登录记录
last -n 20 # 最近 20 条
lastb # 登录失败记录(需要 root)
lastlog # 每个用户的最后登录时间3.6 chage — 密码有效期策略#
chage 专管 /etc/shadow 里那几个和"密码时效"相关的字段,比手改 shadow 安全。
bash
chage -l deploy # 查看某用户的密码/账户有效期设置
chage -M 90 deploy # 密码最长 90 天必须改(最大使用天数)
chage -m 7 deploy # 改密后至少 7 天才能再改(最小天数,防连续改绕过历史)
chage -W 14 deploy # 密码到期前 14 天开始警告
chage -I 30 deploy # 密码过期后再拖 30 天仍不改,则禁用账户(inactive)
chage -E 2026-12-31 deploy # 设置账户到期日
chage -d 0 deploy # 置为「已过期」,强制下次登录必须改密(同 passwd -e)3.7 /etc/login.defs — 新建用户的默认策略#
useradd 不带对应参数时,很多默认值来自 /etc/login.defs:
| 配置项 | 作用 |
|---|---|
UID_MIN / UID_MAX | 普通用户 UID 范围(通常 1000–60000) |
SYS_UID_MIN / SYS_UID_MAX | 系统用户 UID 范围(如 100–999) |
PASS_MAX_DAYS | 新用户默认的密码最长使用天数 |
PASS_MIN_DAYS | 默认最短使用天数 |
PASS_WARN_AGE | 默认过期警告天数 |
UMASK | 登录时应用的默认 umask |
ENCRYPT_METHOD | 密码哈希算法(SHA512 / YESCRYPT) |
改
login.defs只影响之后新建的用户;已有用户的时效策略要用chage单独调。
4. sudo vs su#
4.1 su — 切换用户#
bash
su deploy # 切到 deploy 用户(需要 deploy 的密码)
su - deploy # 切到 deploy,同时加载 deploy 的环境变量
su # 不指定用户,默认切 root
su - # 切 root 并加载 root 的环境su 的本质问题:切 root 等于拿到了全部权限,任何误操作都可能致命。而且多人共用 root 密码,谁干了什么都无法追溯。
4.2 sudo — 临时提权#
bash
sudo command # 以 root 身份执行一条命令
sudo -u deploy command # 以 deploy 身份执行
sudo -l # 查看当前用户有哪些 sudo 权限
sudo -v # 刷新 sudo 时间戳(延长免密时间)sudo 的优点:
- 权限最小化:只给需要的命令,不给 root 全权限
- 可追溯:每次 sudo 都记入
/var/log/auth.log - 免密操作:可配置某些命令无需密码
4.3 对比总结#
| 特性 | su | sudo |
|---|---|---|
| 权限范围 | 完全 root 权限 | 精确到命令级别 |
| 密码 | 需要目标用户的密码 | 需要自己的密码(可免密) |
| 审计 | 无法追溯谁执行了什么 | /var/log/auth.log 记录每条 |
| 多用户 | 共享 root 密码 | 各自用各自密码 |
| 生产推荐 | 不推荐 | 推荐 |
5. /etc/sudoers 配置#
5.1 编辑方式#
bash
# 永远不要直接 vim /etc/sudoers
# 用 visudo——它会做语法检查,防止你配错导致无法 sudo
visudo # 编辑主文件
visudo -f /etc/sudoers.d/myapp # 建独立文件(推荐方式)5.2 语法规则#
text
用户名 主机=(以谁的身份运行) 可执行的命令示例逐条解析#
bash
# 1. root 可以在任何主机以任何人身份执行任何命令
root ALL=(ALL:ALL) ALL
# 2. deploy 在任何主机以 root 身份执行 systemctl restart
deploy ALL=(root) /usr/bin/systemctl restart *
# 3. deploy 免密码执行 systemctl restart(常用配置)
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart *
# 4. %developers 组的所有成员可以免密执行任意命令
%developers ALL=(ALL) NOPASSWD: ALL
# 5. 限制具体服务
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx, /usr/bin/systemctl restart myapp
# 6. 允许 restart 任意服务,但显式禁止 restart firewalld
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart *, !/usr/bin/systemctl restart firewalld通配符授权有坑,能列白名单就别用
*:restart *这类"通配 +!取反"很脆弱——攻击者常能用额外参数、路径变体(systemctl restart nginx.service、绝对/相对路径)或选项绕过!黑名单。生产里优先像示例 5 那样逐条列全命令白名单,而不是"通配后再排除"。
字段含义#
| 字段 | 含义 | 示例 |
|---|---|---|
| 第 1 字段 | 用户/组(% 开头 = 组) | deploy 或 %developers |
| 第 2 字段 | 允许从哪些主机登录 | ALL 或 localhost |
| 第 3 字段 | 以谁的身份运行 | (root) 或 (ALL) |
| 第 4 字段 | 可执行的命令 | 用逗号分隔,! 开头表示禁止 |
NOPASSWD: | 免输密码 | NOPASSWD: /bin/systemctl |
5.3 实战:创建 deploy 用户,只给重启权限#
bash
# Step 1:创建用户
useradd -m -s /bin/bash deploy
# Step 2:设密码
passwd deploy
# Step 3:创建 sudoers 文件(推荐独立文件)
visudo -f /etc/sudoers.d/deploy
# 添加内容:
# deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx, /usr/bin/systemctl restart myapp
# Step 4:验证
deploy@server:~$ sudo -l
# User deploy may run the following commands on server:
# (root) NOPASSWD: /usr/bin/systemctl restart nginx, /usr/bin/systemctl restart myapp
deploy@server:~$ sudo systemctl restart nginx # 成功
deploy@server:~$ sudo systemctl restart mysql # 被拒绝
deploy@server:~$ sudo systemctl status nginx # 被拒绝——只允许 restart5.4 sudo 日志审计#
bash
# Ubuntu/Debian
tail -f /var/log/auth.log | grep sudo
# RHEL 系(Rocky / AlmaLinux / CentOS Stream)
tail -f /var/log/secure | grep sudo
# systemd 系统(不分发行版)也能直接查 journal
journalctl _COMM=sudo # 只看 sudo 产生的日志
journalctl -e | grep sudo
# 输出示例
# Jul 1 10:30:15 server sudo: deploy : TTY=pts/0 ; PWD=/home/deploy ; USER=root ; COMMAND=/usr/bin/systemctl restart nginx6. 组管理#
bash
# 创建组
groupadd developers
groupadd -g 800 developers # 指定 GID
# 修改组
groupmod -n devs developers # 重命名
# 删除组
groupdel developers
# 将用户加入组
usermod -aG docker heiye # 加用户到 docker 组
gpasswd -a heiye docker # 另一种方式
# 将用户移出组
gpasswd -d heiye docker7. 实战:安全加固检查项#
bash
# 1. 检查空密码用户
awk -F: '($2 == "" ) { print $1 " has no password!" }' /etc/shadow
# 2. 检查 UID=0 的用户(只有 root 应该是 0)
awk -F: '($3 == 0) { print $1 }' /etc/passwd
# 3. 检查所有 sudo 权限
grep -v '^#' /etc/sudoers | grep -v '^$'
grep -r '^[^#]' /etc/sudoers.d/
# 4. 检查哪些用户可以登录
awk -F: '$7 !~ /(nologin|false)$/ { print $1 }' /etc/passwd
# 5. 检查 .ssh/authorized_keys 权限(关键是不能被组/其他人可写,否则 sshd 会拒绝)
find /home -name authorized_keys -perm /022 -exec ls -la {} \; # -perm /022 = group 或 other 有 w8. 小结#
| 知识点 | 一句话记忆 |
|---|---|
| /etc/passwd | 用户信息,7 字段,最后一个是 Shell |
| /etc/shadow | 密码哈希($6$=SHA-512、$y$=yescrypt),! 开头 = 锁定,* = 系统账户 |
| useradd | -m 创家目录,-G 附加组,-s 指定 Shell;默认值来自 /etc/login.defs |
| 主组/附加组 | 主组定新建文件的属组;附加组决定能访问哪些按组授权的资源;id 一次看全 |
| chage | 管密码时效:-M 最长天数、-E 账户到期、-d 0 强制下次登录改密 |
| su vs sudo | su 拿全权限无审计,sudo 权限精确可追溯,生产用 sudo |
| visudo | 编辑 /etc/sudoers 的唯一正确方式,有语法检查;命令白名单优于通配 * |
| NOPASSWD | deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart myapp |