用户管理

Linux 用户、组与权限管理

本文按以下顺序整理:用户操作 → 组操作 → 权限设置。每组操作都列出常用命令、参数、作用和安全注意事项。

命令前的 sudo 表示需要 root 权限。删除用户、批量修改属主或权限前,先确认路径和业务影响。

目录

一、先理解用户、组和权限的关系

用户 --UID--> 文件属主
用户 --主组 GID--> 组(每个用户只有一个)
用户 --附加组--> 组(每个用户可以有多个)
组 --GID--> 文件属组
  • 每个用户只有一个主组,记录在 /etc/passwd 第 4 列。
  • 用户可以属于多个附加组,记录在 /etc/group 的成员列表中。
  • 主组成员一般不出现在 /etc/group 成员列表中,查看主组用 id -gn 用户。
  • 组本身不是权限。权限设置在文件、目录或 sudo 规则上,组用于批量归类用户。
  • 文件访问按属主、属组、其他用户的匹配结果判断,不是把多类权限简单相加。

相关配置文件:

文件 作用
/etc/passwd 用户名、UID、主组 GID、家目录、Shell
/etc/shadow 密码哈希、密码有效期、账号过期时间
/etc/group 组名、GID、附加组成员
/etc/gshadow 组密码、组管理员、组成员
/etc/login.defs UID/GID 范围、密码策略等默认值
/etc/skel/ 新建用户家目录的模板
/etc/sudoers、/etc/sudoers.d/ sudo 授权规则

1.1 /etc/passwd 字段

格式:

用户名:密码占位符:UID:GID:GECOS:家目录:登录Shell

示例:

alice:x:2001:2001:Alice:/home/alice:/bin/bash
序号 字段 示例 含义
1 用户名 alice 登录名,通常使用小写
2 密码占位符 x 密码哈希在 /etc/shadow,这里只占位
3 UID 2001 用户 ID;root 的 UID 是 0
4 GID 2001 主组 GID,组必须存在于组数据库
5 GECOS Alice 备注信息,通常为全名或用途
6 家目录 /home/alice 登录后的初始目录
7 登录 Shell /bin/bash 登录时执行的程序;nologin 表示禁止登录

字段注意:

  • 密码列通常为 x,不要在这里存放明文密码。
  • UID 0 是 root。不要随意把普通用户改为 UID 0。
  • 第 4 列是主组 GID。附加组不在该文件里,而在 /etc/group。
  • GECOS 字段可以包含逗号分隔的附加信息,但不同工具解释不完全一致。
  • Shell 为空时,部分程序会回退到 /bin/sh。
  • Shell 为 /usr/sbin/nologin 或 /sbin/nologin 时,交互式登录会被拒绝。

1.2 /etc/shadow 字段

格式:

用户名:加密密码:上次改密日期:最小间隔:最大有效期:警告天数:宽限天数:账号过期日期:保留字段

示例:

alice:$6$...:20000:7:90:14:30:21000:
序号 字段 示例 含义
1 用户名 alice 与 /etc/passwd 对应
2 加密密码 $6$... 密码哈希;!、!!、* 表示不可用或锁定
3 上次改密日期 20000 从 1970-01-01 起的天数;0 表示下次登录必须改密
4 最小间隔 7 两次改密之间至少间隔的天数;0 表示不限制
5 最大有效期 90 密码有效天数;到期后要求改密
6 警告天数 14 密码到期前提前提醒的天数
7 宽限天数 30 密码过期后仍可登录改密的天数
8 账号过期日期 21000 从 1970-01-01 起的天数;空表示永不过期
9 保留字段 空 预留给未来使用

密码字段状态:

值 含义
$6$... 通常为 SHA-512 密码哈希
! 或 !! 密码被锁定或未设置
* 无可用密码,通常表示不能密码登录
空 可能表示无需密码,风险高;是否允许登录还取决于 PAM 配置

字段注意:

  • 日期按“UTC 1970-01-01 起的天数”计算,不是 YYYY-MM-DD 文本。
  • 账号过期与密码过期不同:账号过期后不能登录;密码过期后通常要求改密。
  • 最大有效期小于最小间隔时,用户可能无法修改密码。
  • 不要直接编辑 /etc/shadow。优先使用 passwd、chage、usermod。
  • /etc/shadow 通常只允许 root 读取。

为什么普通用户执行 getent shadow 自己 没有输出

这是正常现象。getent 只是通过 NSS 查询数据库,不会绕过 /etc/shadow 的文件权限:

ls -l /etc/shadow

典型权限:

---------- 1 root root /etc/shadow

普通用户没有读权限,因此查询结果为空,命令还可能返回非零状态:

getent shadow test1
echo "$?"

即使查看的是自己的记录,也一样不会返回密码哈希。密码哈希不应暴露给普通用户,否则离线破解风险会增加。

使用 root 或 sudo 才能查看:

sudo getent shadow test1

也可以查看非敏感的有效期信息:

sudo passwd -S test1
sudo chage -l test1

排查时注意:

  • getent passwd test1 能返回,只说明用户可以查询 /etc/passwd。
  • getent shadow test1 没有输出,不代表用户不存在,也不代表账号被删除。
  • 如果 NSS 配置了 LDAP 或 SSSD,shadow 查询还取决于对应的 NSS 服务是否支持。
  • 不要为了“查得到”而修改 /etc/shadow 权限,例如改成 644 或 777。
  • /etc/shadow 的属主和权限异常本身是安全问题,应使用发行版默认值或 pwck、chmod 正确修复。

1.3 /etc/group 字段

格式:

组名:组密码占位符:GID:附加组成员

示例:

dev:x:2000:alice,bob
序号 字段 示例 含义
1 组名 dev 组名称
2 组密码占位符 x 组密码通常在 /etc/gshadow
3 GID 2000 组 ID,必须唯一
4 附加组成员 alice,bob 逗号分隔的用户名,不能有空格

字段注意:

  • 第 4 列是附加组成员,不是主组成员。
  • 用户的主组由 /etc/passwd 第 4 列决定,不一定出现在这里。
  • 成员列表为空表示没有显式的附加组成员。
  • 组名和 GID 应保持唯一;-o 允许重复 GID,但一般不建议。
  • 修改组成员后,已有会话不会自动刷新。

1.4 /etc/gshadow 字段

格式:

组名:加密组密码:组管理员:组成员

示例:

dev:$6$...:alice:bob,carol
序号 字段 示例 含义
1 组名 dev 与 /etc/group 对应
2 加密组密码 $6$... 组密码;! 开头表示锁定
3 组管理员 alice 可修改组密码和成员的用户,逗号分隔
4 组成员 bob,carol 组内成员,逗号分隔

字段注意:

  • /etc/gshadow 中的密码优先于 /etc/group 中的组密码。
  • 组成员可以不用组密码访问组权限。
  • 组管理员也可以修改组密码和成员,并拥有组员权限。
  • 组成员列表通常应与 /etc/group 保持一致。
  • /etc/gshadow 通常只允许 root 读取。
  • 不要直接编辑这些文件,优先使用 groupadd、groupmod、gpasswd、grpconv 等工具。

1.5 四个文件之间的关系

/etc/passwd -- 用户名/UID/主组GID --> /etc/group
/etc/shadow -- 用户密码和账号策略
/etc/group  -- 组名/GID/附加组成员
/etc/gshadow -- 组密码/组管理员/组成员

不要只根据一个文件判断用户权限,建议使用:

getent passwd alice
getent group dev
id alice
sudo getent shadow alice
sudo getent gshadow dev

getent 会通过 NSS 查询本地文件、LDAP 等来源,比直接 cat 更适合排查系统中的实际用户和组信息。但 shadow 和 gshadow 包含敏感信息,普通用户查询不到时是正常的。

二、用户操作

2.1 useradd:创建用户

基本语法:

sudo useradd [参数] 用户名

常用参数:

参数 作用 说明
-m 创建家目录 从 /etc/skel 复制模板文件
-M 不创建家目录 与 -m 相反
-d 目录 指定家目录 不配合 -m 时只写入配置,不创建目录
-b 目录 指定家目录的上级目录 默认通常是 /home
-s Shell 指定登录 Shell 如 /bin/bash、/usr/sbin/nologin
-u UID 指定用户 ID 必须唯一,普通用户通常从 1000 开始
-g 组 指定主组 组必须已存在;可用组名或 GID
-G 组1,组2 指定附加组 多个组用逗号分隔,不能有空格
-c "说明" 设置备注 通常填写姓名或用途
-e 日期 设置账号过期日期 格式 YYYY-MM-DD
-f 天数 密码过期后多少天禁用账号 0 立即禁用,-1 不启用
-r 创建系统账号 UID 通常在系统号段,默认不建家目录
-p 哈希值 直接写入加密密码 不推荐,容易泄露
-N 不创建同名私有组 主组使用默认组
-U 创建同名私有组 可覆盖默认配置
-D 查看或修改默认配置 查看默认值:useradd -D

创建可登录用户:

sudo useradd -m -s /bin/bash -c "Alice" alice
sudo passwd alice

创建指定主组、附加组和 UID 的用户:

sudo groupadd -g 2000 dev
sudo groupadd ops
sudo useradd -m -u 2001 -g dev -G ops -s /bin/bash alice

创建不能登录的服务账号:

sudo useradd -r -s /usr/sbin/nologin appuser

说明:

  • useradd 默认不会设置密码,需要再执行 passwd。
  • 不指定 -g 时,很多发行版会创建同名私有组作为主组。
  • -G 只设置附加组,不会把用户加入主组的成员列表。

2.2 passwd:设置和修改密码

基本语法:

sudo passwd [参数] 用户名   # root 修改指定用户
passwd                      # 普通用户修改自己

常用参数:

参数 作用 说明
-S 查看密码状态 输出 PS 可用、LK 锁定、NP 无密码
-l 锁定密码 在密码哈希前加 !,不禁止 SSH 密钥登录
-u 解锁密码 去掉密码哈希前的 !
-d 删除密码 账号变成无密码状态,风险高
-e 强制下次登录改密码 等价于密码立即过期
-n 天数 最短改密间隔 期间不能再次改密
-x 天数 密码最大有效期 到期后必须修改密码
-w 天数 提前警告天数 密码到期前提醒
-i 天数 密码过期后宽限天数 超过后账号不可用
-f 强制执行 配合 -u 等参数使用

示例:

sudo passwd alice              # 设置或重置密码
sudo passwd -S alice           # 查看状态
sudo passwd -l alice           # 锁定密码
sudo passwd -u alice           # 解锁密码
sudo passwd -e alice           # 下次登录强制改密
sudo passwd -n 7 -x 90 -w 14 alice

注意:passwd -l 只锁定密码登录,SSH 公钥等方式可能仍可登录。要禁用整个账号,可使用 chage -E 0 alice 或 usermod -e 1 alice。

批量设置密码:

echo 'alice:StrongPassword' | sudo chpasswd

这种方法可能进入 Shell 历史,生产环境优先交互式 passwd,或使用权限受控的临时文件配合 chpasswd < 文件。

2.3 chage:密码和账号有效期

基本语法:

sudo chage [参数] 用户名

常用参数:

参数 作用 说明
-l 查看有效期信息 显示上次改密、有效期等
-d 日期或天数 设置上次改密时间 -d 0 强制下次登录改密
-m 天数 最短改密间隔 0 表示随时可改
-M 天数 密码最大有效期 -1 表示不检查
-W 天数 到期前警告天数 提前提醒用户
-I 天数 密码过期后的宽限天数 超期后锁定账号
-E 日期或天数 账号过期日期 -1 表示取消过期日期

示例:

sudo chage -l alice
sudo chage -m 7 -M 90 -W 14 alice
sudo chage -I 30 alice
sudo chage -E 2026-12-31 alice
sudo chage -d 0 alice

区别:

  • -M 是密码有效期,过期后要求改密。
  • -I 是密码过期后的宽限天数,超过后账号被锁定。
  • -E 是整个账号的过期日期。
  • -d 0 只是要求下次登录改密。

2.4 usermod:修改用户

基本语法:

sudo usermod [参数] 用户名

常用参数:

参数 作用 说明
-l 新名 修改登录名 不会自动修改家目录和组名
-u UID 修改 UID 用户不应有运行中的进程
-g 组 修改主组 组必须存在
-G 组1,组2 设置附加组列表 会覆盖原有附加组
-aG 组1,组2 追加附加组 必须加 -a,否则会覆盖
-d 目录 修改家目录 配合 -m 可迁移旧目录内容
-s Shell 修改登录 Shell 如改为 /bin/bash 或 /usr/sbin/nologin
-c "说明" 修改备注 姓名或用途说明
-e 日期 修改账号过期日期 格式 YYYY-MM-DD;空值取消过期
-f 天数 修改密码过期后的宽限天数 0 立即禁用,-1 不启用
-L 锁定密码 在密码哈希前加 !
-U 解锁密码 去掉密码哈希前的 !
-p 哈希值 设置加密密码 不推荐,容易出现在进程列表中

示例:

sudo usermod -aG docker alice
sudo usermod -s /bin/bash alice
sudo usermod -g dev alice
sudo usermod -d /home/alice2 -m alice
sudo usermod -L alice
sudo usermod -U alice

注意:

  • 追加附加组必须使用 -aG;单独使用 -G 会替换原有附加组列表。
  • 修改 UID 后,家目录内的文件通常会自动调整,但家目录外的文件需要手动修正。
  • 修改用户名后,还要检查家目录、同名组、sudoers、SSH、cron、systemd 和数据库授权。

修改 UID 后查找旧文件:

sudo find /path -uid 2001 -ls
sudo find /path -uid 2001 -exec chown 2002 {} \;

2.5 userdel:删除用户

基本语法:

sudo userdel [参数] 用户名

常用参数:

参数 作用 说明
-r 删除家目录和邮件池 不会清理所有系统范围内的关联文件
-f 强制删除 用户仍登录或文件归属异常时也可能删除,风险高
-Z 删除 SELinux 用户映射 仅适用于启用 SELinux 的环境

示例:

# 先检查、备份
pgrep -u alice -a
sudo tar czf /backup/alice-home.tar.gz /home/alice

# 删除用户和家目录
sudo userdel -r alice

userdel -r 不保证清理以下内容:

  • /var/spool/cron/ 中的定时任务。
  • /etc/sudoers.d/ 中的授权。
  • SSH 密钥和 authorized_keys。
  • 数据库账号和应用配置。
  • 家目录以外的用户文件。

删除后检查:

sudo find / -uid 2001 -ls 2>/dev/null

2.6 id、groups、getent:查看用户信息

命令 作用
id alice 显示 UID、主组、附加组
id -u alice 只显示 UID
id -g alice 只显示主组 GID
id -gn alice 只显示主组名称
id -G alice 显示所有组 GID
groups alice 显示所有组名称
getent passwd alice 从用户数据库查询用户
getent group dev 从组数据库查询组
sudo getent shadow alice 查询密码信息,必须使用 root 或 sudo

用户数据库可能来自本地文件、LDAP 或其他 NSS 服务,因此优先使用 getent 查询,而不是只查看 /etc/passwd。

注意:普通用户查询自己的 shadow 记录也可能返回空,因为 /etc/shadow 默认不可读。getent 不会绕过文件权限:

ls -l /etc/shadow
sudo getent shadow alice

查不到通常不是用户不存在,而是权限限制。

2.7 su:切换用户

基本语法:

su [参数] [-] [用户名]

不带用户名时默认切换到 root:

su -

常用参数:

参数 作用 说明
- 或 -l 启动登录 Shell 清理环境变量,切换到目标用户家目录,推荐使用
-c "命令" 以目标用户执行一条命令 执行完返回,不进入交互式 Shell
-s Shell 指定 Shell root 才可绕过 /etc/shells 限制
-m 或 -p 保留当前环境变量 容易混用环境,一般不推荐
-g 组 指定主组 仅 root 可用
-G 组 指定附加组 仅 root 可用
-P 创建独立伪终端 某些版本支持,增强终端隔离
-f 传递 -f 给 Shell 主要用于 csh/tcsh

示例:

su - alice
su - alice -c 'id'
su - alice -s /bin/bash

注意:su 本身没有 -u 和 -H 参数。它们属于 sudo:

命令 参数 作用
sudo -u 用户 以指定用户身份运行命令
sudo -H 将 HOME 设置为目标用户家目录
su 无 -u 目标用户直接写在命令后面,如 su - alice
su 无 -H 使用 su - 启动登录 Shell 时,通常会切换到目标用户家目录

常见等价关系:

# su 切换登录 Shell
su - alice

# sudo 以 alice 身份启动登录 Shell
sudo -iu alice

# su 以 alice 身份执行单条命令
su - alice -c 'id'

# sudo 以 alice 身份执行单条命令,并使用 alice 的家目录
sudo -u alice -H id

说明:

  • sudo -iu alice 中的 -i 表示模拟登录环境,-u alice 指定目标用户。
  • sudo -u alice -H command 不会启动登录 Shell,适合脚本和单条命令。
  • sudo -H 只影响 HOME;如果需要完整登录环境,应使用 sudo -i。
  • su - 的 - 是登录 Shell 简写,不是 sudo 的 -H。

切换用户后 SSH 连接其他主机

常见写法可以执行:

sudo su - alice -c 'ssh bob@192.0.2.10'

但更推荐直接使用 sudo -u,不需要启动登录 Shell:

sudo -u alice -H ssh bob@192.0.2.10

区别:

  • su - alice 会以 alice 的登录环境启动 Shell;如果 alice 的 Shell 是 nologin,会失败。
  • sudo -u alice -H ssh ... 直接以 alice 的 UID 执行 ssh,即使 alice 是 nologin 服务账号也可以运行;-H 让 HOME 指向 alice 的家目录。
  • ssh bob@192.0.2.10 中的 bob 是远端主机的登录用户,不是本机切换后的 alice。
  • 如果写成 ssh 192.0.2.10,SSH 默认使用本机当前用户名 alice 作为远端用户名。
  • 本机切换用户只影响使用哪个本地账号的 ~/.ssh 配置、私钥和 SSH agent,不会自动获得远端权限。

如果需要 alice 使用自己的密钥:

sudo -u alice -H ssh -i /home/alice/.ssh/id_ed25519 bob@192.0.2.10

目录和密钥权限通常应为:

chmod 700 /home/alice/.ssh
chmod 600 /home/alice/.ssh/id_ed25519
chmod 600 /home/alice/.ssh/authorized_keys
chown -R alice:alice /home/alice/.ssh

注意:

  • su 的 -c 命令建议用单引号,避免本地 Shell 提前展开变量。
  • 首次连接会提示确认主机指纹,自动化脚本应提前配置 known_hosts 或使用受控的 StrictHostKeyChecking 策略。
  • 非交互式脚本应使用密钥认证和 BatchMode=yes,避免卡在密码输入。
  • 不要把密码写在命令行中,命令行参数可能被其他用户通过进程列表看到。
  • 如果 alice 没有可用的 SSH 私钥,切换到 alice 后也无法使用 root 的私钥。此时应单独为 alice 配置密钥,或明确使用有权限的本地账号。

su 的注意事项

  • 尽量使用 su - 用户,不要省略 -。- 会加载目标用户的登录环境;省略后可能继承当前目录和部分环境变量,导致命令行为不一致。
  • su 默认切换到 root,生产环境应明确写出目标用户,避免误操作。
  • su 需要目标用户的密码,只有 root 切换时通常不需要密码。不要为了免密切换而滥用 PAM 或 sudoers 配置。
  • 普通用户能否 su 到 root,取决于 /etc/pam.d/su 中的 pam_wheel.so 配置,不取决于用户是否在 wheel 组本身。
  • su - 会按目标用户当前的用户和组数据库初始化身份,但已经打开的旧会话不会自动刷新。修改组成员后,新开的 su - 会话通常能读到新组信息,旧 Shell 仍保持原状态。
  • su -c 适合执行单条命令,但不要拼接不可信输入,避免 Shell 注入。
  • su 和 sudo 的认证对象不同:su 通常验证目标用户密码,sudo 通常验证当前用户密码,并按 sudoers 规则授权。
  • 在脚本中由 root 切换身份时,优先使用 runuser 或 setpriv,避免依赖 PAM 和密码交互。
  • 修改过用户组、UID 或 GID 后,必须重新登录或重新 su -,旧会话不会自动刷新权限。
  • su - 后环境变量、家目录和 PATH 会变化,排查“命令找不到”或“配置文件不生效”时要先确认当前身份和 Shell。
  • 操作完成后及时 exit,不要长期保留 root 或高权限会话。

检查当前身份和环境:

id
whoami
echo "$HOME"
echo "$PATH"

2.8 不能登录的用户如何启动服务

“不能登录”通常是指把用户的登录 Shell 设置为:

/usr/sbin/nologin

这只限制交互式登录,不等于该用户不能拥有进程或不能运行服务。

先区分两种场景

场景 说明
交互式登录 用户通过 SSH、终端或 su - 登录,nologin 会阻止
以该用户身份启动进程 由 root、systemd、容器运行时等主动切换 UID 后执行,不经过登录 Shell

因此,服务账号可以使用 nologin,仍可被 systemd 等服务管理器以该 UID 启动。

方式一:systemd 服务(推荐)

创建服务账号:

sudo groupadd -r myapp
sudo useradd -r -g myapp -s /usr/sbin/nologin -d /opt/myapp -M myapp

创建应用目录并设置属主:

sudo mkdir -p /opt/myapp
sudo chown -R myapp:myapp /opt/myapp
sudo chmod 750 /opt/myapp

创建 unit 文件:

# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network.target

[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/myapp --config /opt/myapp/conf/myapp.conf
Restart=on-failure
RestartSec=3

# 可选的安全加固
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true

[Install]
WantedBy=multi-user.target

加载并启动:

sudo systemctl daemon-reload
sudo systemctl enable --now myapp
sudo systemctl status myapp

检查进程实际运行身份:

ps -o pid,user,group,cmd -C myapp

关键点:

  • systemd 以 User=myapp 指定的 UID 启动进程,不要求 myapp 能登录。
  • User= 中的服务账号应使用系统账号,Shell 设为 nologin。
  • Group= 指定的组必须存在,并且应与服务目录的属组一致。
  • 服务需要的目录、端口、日志和配置文件必须授予 myapp 或对应组权限。
  • 不要让服务以 root 运行,除非确实需要绑定低端口或执行特权操作。
  • 如果需要绑定 80/443,优先使用反向代理或 CAP_NET_BIND_SERVICE,而不是直接使用 root。

方式二:root 手动以服务账号执行命令

sudo -u myapp /opt/myapp/bin/myapp --config /opt/myapp/conf/myapp.conf

或者:

sudo runuser -u myapp -- /opt/myapp/bin/myapp

注意:

  • sudo -u myapp 需要 root 或相应 sudoers 授权。
  • runuser 通常只允许 root 使用,适合脚本。
  • 直接用 su - myapp 会被 nologin 阻止,不适合作为启动服务的方式。
  • 用 su myapp -s /bin/bash 强行绕过 nologin 会破坏服务账号的安全边界,不推荐。

方式三:容器或编排系统

Docker、Kubernetes 等运行时可以指定 UID,不依赖登录 Shell:

USER 1001:1001

或:

securityContext:
  runAsUser: 1001
  runAsGroup: 1001

容器镜像中即使没有 nologin 用户,也可以直接用数字 UID 运行。生产中应固定 UID/GID,并确保挂载目录权限匹配。

常见错误

错误做法 问题
su - myapp 启动服务 nologin 会拒绝登录,服务无法启动
把服务账号 Shell 改成 /bin/bash 增加被登录利用的风险
给服务账号配置可登录密码 没有必要,且扩大攻击面
用 root 运行所有服务 服务被攻破后直接获得 root 权限
只改 User=,不改目录权限 服务启动失败,报权限不足
用共享账号运行多个服务 无法隔离故障和审计责任

推荐的服务账号流程

sudo groupadd -r myapp
sudo useradd -r -g myapp -s /usr/sbin/nologin -d /opt/myapp -M myapp
sudo install -d -o myapp -g myapp -m 0750 /opt/myapp
sudo install -d -o myapp -g myapp -m 0750 /opt/myapp/conf
sudo install -d -o myapp -g myapp -m 0750 /var/log/myapp
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
id myapp
ps -o pid,user,group,cmd -C myapp

服务账号原则:

  • 使用系统 UID/GID,Shell 设置为 nologin。
  • 不设置登录密码,或保持密码锁定。
  • 每个服务使用独立账号,避免共享。
  • 只授予必要目录和文件权限。
  • 通过 systemd、容器运行时或 root 主动切换身份启动,不通过登录。

2.9 Docker 为什么需要 sudo

root 启动 Docker 时,Docker daemon 通常监听一个 Unix Socket:

/var/run/docker.sock

客户端执行 docker ps、docker run 时,并不是直接操作容器,而是通过这个 Socket 向 root 运行的 daemon 发送请求。因此,普通用户能否直接使用 Docker,取决于 Socket 的访问权限,而不是 docker 命令本身。

查看 Socket:

ls -l /var/run/docker.sock
stat -c '%U %G %a %A' /var/run/docker.sock

典型结果:

srw-rw---- 1 root docker 660 /var/run/docker.sock

含义:

字段 含义
s Socket 文件
root 属主是 root
docker 属组是 docker
660 属主和属组可读写,其他用户无权限

普通用户不在 docker 组时,访问 Socket 会被拒绝,所以只能使用 sudo docker ...。

方式一:加入 docker 组

sudo usermod -aG docker alice

然后让 alice 重新登录,使附加组生效:

id alice

验证:

docker ps

注意:

  • 必须使用 -aG,不要用 -G 覆盖原有附加组。
  • 组信息变更后,已有会话不会立即生效,需要重新登录。
  • 加入 docker 组后不需要 sudo,但权限风险很高。
为什么 id 显示已加入 docker 组,docker 仍然报错

容易混淆的两个命令:

id test11     # 查询账号数据库,显示该用户“已配置”的组
id            # 查询当前进程真正拥有的 UID/GID 和附加组

id 用户名 成功显示 docker,只证明 /etc/group 中已经记录了成员关系,不代表当前 Shell 进程已经获得该组权限。

验证当前会话是否真正生效:

id
docker ps

如果 id 用户名 有 docker,但 id 没有,说明当前会话还是旧权限。处理方式:

newgrp docker
id
docker ps

或者退出当前 SSH/终端会话,重新登录。仅执行 usermod 不会修改已经启动的 Shell 进程的附加组。

加入 docker 组后仍然不能访问的排查顺序
  1. 确认 Docker daemon 是否运行:
sudo systemctl status docker
  1. 确认 sudo docker ps 是否正常:
sudo docker ps

如果 sudo docker ps 也失败,说明问题不在用户组,而在 daemon、Socket 路径或 Docker 配置。

  1. 查看 Socket 的属主、属组和权限:
ls -l /var/run/docker.sock
stat -c '%U %G %a %A' /var/run/docker.sock
getent group docker

有效条件是:

  • Socket 属组确实是 docker。
  • Socket 权限允许组读写,通常是 660。
  • 当前进程确实拥有 docker 组。

如果 Socket 属组不是 docker,加入 docker 组没有作用。应检查 Docker 的 --group 或 daemon 配置,不要直接把 Socket 改成 777。

  1. 确认 Docker 客户端连接的 Socket 路径是否正确:
echo "$DOCKER_HOST"
docker context ls

rootless Docker 或自定义 DOCKER_HOST 可能使用其他 Socket 路径。

.docker/config.json 的 permission denied

这类警告通常是 Docker 客户端读取自己的配置失败:

WARNING: Error loading config file:/home/user/.docker/config.json - permission denied

它与“能否连接 Docker daemon”是两件事。多数情况下该警告不会阻止连接,但应确认配置文件的权限:

ls -ld ~/.docker
ls -l ~/.docker/config.json
stat -c '%U %G %a %A' ~/.docker ~/.docker/config.json
namei -l ~/.docker/config.json
getfacl ~/.docker/config.json 2>/dev/null

常见原因:

  • 曾经用 sudo docker 或 sudo -E docker 运行,配置被 root 创建。
  • 家目录或 .docker 目录权限不足。
  • .docker 是指向不可访问路径的符号链接。
  • ACL、挂载权限或网络文件系统权限异常。

如果确认文件应由当前用户拥有,可以修正:

sudo chown -R "$USER":"$(id -gn)" ~/.docker
chmod 700 ~/.docker
chmod 600 ~/.docker/config.json

如果不需要已有配置,也可以先备份后移走:

mv ~/.docker/config.json ~/.docker/config.json.bak

不要把整个家目录或 .docker 目录改成 777。

方式二:继续使用 sudo

sudo docker ps
sudo docker run --rm hello-world

可以为特定命令配置 sudoers:

%dev ALL=(root) /usr/bin/docker ps

但通常不建议细粒度授权 docker 命令,因为 Docker 权限本身很难安全收窄。

为什么 docker 组约等于 root 权限

Docker daemon 以 root 运行,Socket 实际上是一个高权限控制接口。能访问 Socket 的用户通常可以:

  • 以 root 身份运行容器。
  • 把宿主机根目录挂载进容器。
  • 读取或修改宿主机文件。
  • 通过特权容器或 --pid=host 等方式影响宿主机。

例如:

docker run --rm -v /:/host -it alpine chroot /host

因此,加入 docker 组基本等同于获得 root 权限。安全要求高的环境应考虑:

  • 使用 rootless Docker。
  • 使用 Podman 等无守护进程方案。
  • 通过受控的 CI/CD 或编排平台执行容器操作。
  • 不给普通开发组直接授予 docker Socket 访问权限。
  • 使用 docker context、SSH 远程 Docker 或专用构建节点隔离权限。

常见现象与排查

现象 原因 处理
permission denied while trying to connect to the Docker daemon socket 当前用户不能访问 Socket 使用 sudo 或加入 docker 组
加入 docker 组后仍报错 当前会话未刷新组信息 重新登录
docker 命令找不到 PATH 或未安装客户端 检查 command -v docker 和软件包
Cannot connect to the Docker daemon daemon 未启动或 Socket 路径不同 检查 systemctl status docker 和 Socket 路径
sudo docker 可用但普通 docker 不可用 正常,说明当前用户没有 Socket 权限 按需加入组,不要直接改 Socket 为 777

不要用下面的方式绕过权限:

sudo chmod 777 /var/run/docker.sock

这会让任意本地用户获得 Docker 控制权,等同于把 root 权限开放给所有用户。

2.10 密码登录与 SSH 免密登录

SSH 登录必须先通过认证,常见方式有两种:

方式 认证凭据 远端保存什么 是否传输密码
密码登录 远端账号密码 密码哈希在 /etc/shadow 是,但受 SSH 加密通道保护
公钥免密登录 客户端私钥 客户端公钥在 ~/.ssh/authorized_keys 不传输密码,也不传输私钥

“免密”通常不是完全没有认证,而是用私钥认证代替密码认证。私钥仍然受本机文件权限保护。

密码登录流程

  1. 客户端连接 SSH 服务端。
  2. 服务端要求密码认证。
  3. 客户端输入远端账号密码。
  4. 服务端通过 PAM 等机制校验密码。

前提条件:

  • 远端账号存在且未被锁定或过期。
  • 账号有可用密码。
  • 服务端允许密码认证:PasswordAuthentication yes。
  • 用户没有被 AllowUsers、DenyUsers、PAM、防火墙等策略拒绝。

检查服务端配置:

sudo sshd -T | grep -E '^(passwordauthentication|pubkeyauthentication|permitrootlogin|authorizedkeysfile)'

注意:sshd -T 需要 root,且显示的是当前生效配置,不一定是 /etc/ssh/sshd_config 中的原始文本。

SSH 公钥免密登录流程

  1. 客户端生成一对密钥:私钥和公钥。
  2. 客户端把公钥写入远端用户的 ~/.ssh/authorized_keys。
  3. 客户端连接时,服务端检查该公钥是否被授权。
  4. 服务端向客户端发送挑战,客户端用私钥签名。
  5. 服务端用公钥验证签名,通过后允许登录。

生成密钥:

ssh-keygen -t ed25519 -C 'alice@laptop'

复制公钥到远端:

ssh-copy-id alice@192.0.2.10

也可以手动追加公钥:

mkdir -p ~/.ssh
chmod 700 ~/.ssh
cat id_ed25519.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

权限要求:

# 远端用户家目录不能对其他用户可写
chmod go-w ~
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

# 客户端私钥必须仅自己可读
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub

常见问题:

  • ~/.ssh、authorized_keys 或家目录权限过宽,sshd 的 StrictModes yes 会拒绝使用公钥。
  • 公钥复制到了错误用户的家目录。
  • 服务端 PubkeyAuthentication no。
  • 私钥文件损坏、权限过宽或使用了错误的密钥。
  • SELinux 上下文不正确,可检查 restorecon -Rv ~/.ssh。

两种方式的对比

对比项 密码登录 SSH 公钥免密登录
是否输入密码 需要 通常不需要
凭据 账号密码 客户端私钥
密码是否通过网络传输 是,但受 SSH 加密通道保护 否
抗暴力破解 较弱,依赖密码强度和限速 较强,私钥难以暴力穷举
私钥泄露风险 无 有,私钥泄露即可登录
是否依赖 authorized_keys 否 是
是否依赖账号密码 是 通常否
自动化友好程度 较差 较好
推荐场景 临时登录、首次配置 日常运维、自动化、CI/CD

锁密码不等于禁止 SSH 登录

这是最容易误解的地方:

sudo passwd -l alice

这通常只是锁定密码认证,alice 仍然可能通过 SSH 公钥登录。类似地:

sudo usermod -L alice

也主要影响密码认证。

如果要彻底禁止某个账号登录,应结合多种措施:

# 设置账号过期,禁止所有登录方式
sudo chage -E 0 alice

同时按需:

  • 设置 PasswordAuthentication no。
  • 使用 DenyUsers alice 或 AllowUsers 白名单。
  • 移除远端 authorized_keys。
  • 在 PAM 中配置账号锁定策略。
  • 禁用账号或删除账号。

反过来,如果只把 Shell 设置为 nologin,也要注意:某些服务端配置或 ForceCommand 场景下仍可能执行非交互命令。安全边界应以 PAM、账号状态和 SSH 配置共同判断。

服务端常见配置

# /etc/ssh/sshd_config
PubkeyAuthentication yes
PasswordAuthentication no
PermitRootLogin prohibit-password
AuthorizedKeysFile .ssh/authorized_keys
StrictModes yes

含义:

配置 作用
PubkeyAuthentication yes 允许公钥认证
PasswordAuthentication no 禁止密码认证
PermitRootLogin prohibit-password root 禁止密码登录,仅允许密钥等方式
AuthorizedKeysFile 指定公钥文件位置
StrictModes yes 检查家目录和密钥文件权限

修改后先校验再重载:

sudo sshd -t
sudo systemctl reload sshd

不同发行版的服务名可能是 ssh 而不是 sshd:

sudo systemctl reload ssh

注意:重载前保留一个已登录的会话,避免配置错误导致无法远程登录。

排查命令

客户端使用详细日志:

ssh -vvv alice@192.0.2.10

只使用公钥认证:

ssh -o PreferredAuthentications=publickey alice@192.0.2.10

测试密码认证:

ssh -o PreferredAuthentications=password alice@192.0.2.10

服务端日志:

sudo journalctl -u sshd -n 100 --no-pager
sudo tail -n 100 /var/log/auth.log

排查时先判断失败发生在:

  • 网络连接阶段。
  • SSH 协议协商阶段。
  • 用户认证阶段。
  • 登录 Shell 或 PAM 会话阶段。

三、组操作

3.1 groupadd:创建组

基本语法:

sudo groupadd [参数] 组名

常用参数:

参数 作用 说明
-g GID 指定 GID 必须唯一
-r 创建系统组 GID 通常在系统号段
-f 组已存在时按成功处理 常用于幂等脚本
-o 允许非唯一 GID 一般不推荐
-p 哈希值 设置组密码 不推荐,容易泄露

示例:

sudo groupadd dev
sudo groupadd -g 2000 ops
sudo groupadd -r appgroup

组分类:

  • 主组:用户登录时默认生效,只有一个。
  • 附加组:用户额外加入的组,可以有多个。
  • 私有组:新用户创建的同名组,通常只包含该用户。
  • 系统组:为服务或系统资源创建,GID 通常较小。

3.2 usermod 和 gpasswd:维护组成员

把用户加入附加组:

sudo usermod -aG dev alice
sudo gpasswd -a alice dev

从组中移除用户:

sudo gpasswd -d alice dev

gpasswd 常用参数:

参数 作用 说明
-a 用户 把用户加入组 追加成员
-d 用户 从组中移除用户 不影响主组
-M 用户1,用户2 设置组成员列表 会覆盖原成员列表
-A 用户1,用户2 设置组管理员 组管理员可维护成员
-r 删除组密码 仅成员可使用 newgrp
-R 限制组访问 组密码设为 !

注意:

sudo usermod -G dev,ops alice

会替换用户已有附加组,不会追加。追加必须使用 -aG。

组成员修改后,已有登录会话不会自动刷新附加组,用户通常需要重新登录。

3.3 groupmod:修改组

基本语法:

sudo groupmod [参数] 组名

常用参数:

参数 作用 说明
-n 新组名 修改组名 只改名称
-g 新GID 修改 GID 旧文件不会自动更新属组
-o 允许非唯一 GID 配合 -g 使用
-p 哈希值 修改组密码 不推荐

示例:

sudo groupmod -n newdev dev
sudo groupmod -g 3000 dev

修改 GID 后修正旧文件:

sudo find /path -gid 2000 -ls
sudo find /path -gid 2000 -exec chgrp 3000 {} \;

3.4 groupdel:删除组

sudo groupdel dev

常用参数:

参数 作用 说明
-f 强制删除 部分发行版支持;可删除用户主组,风险高,不建议依赖

如果组是某个用户的主组,通常不能直接删除:

groupdel: cannot remove the primary group of user 'alice'

处理方式:

sudo usermod -g newgroup alice
sudo groupdel dev

删除组不会自动修改旧文件属组,需要检查残留:

sudo find / -gid 2000 -ls 2>/dev/null

3.5 newgrp:切换当前组

newgrp dev

作用:在当前终端临时切换到指定组,启动一个新的 Shell 会话。

参数 作用
- 同时重新初始化登录环境

注意:newgrp 只影响当前 Shell 及其启动的进程,不会修改用户的组成员配置。长期生效仍应使用 usermod -aG 或 gpasswd -a。

查看当前会话的组:

id

四、权限设置

权限模型

属主 user     u
属组 group    g
其他 other    o
权限 文件 目录
r 读取文件内容 列出目录中的文件名
w 修改文件内容 创建、删除、重命名目录项
x 执行程序 进入目录、访问目录内文件

目录的 w 权限通常需要配合 x 才能正常使用。

chown 和 chgrp:修改属主和属组

sudo chown alice file.txt
sudo chown alice:dev file.txt
sudo chgrp dev file.txt
命令或参数 作用
chown 用户 文件 修改文件属主
chown 用户:组 文件 同时修改属主和属组
chown :组 文件 只修改属组
chgrp 组 文件 只修改属组
-R 递归处理目录内容
--reference=文件 参照已有文件设置属主和属组

chmod:修改权限

符号方式:

chmod u+rwx,g+rx,o-rwx /srv/project
chmod g+r file.txt
chmod o-rwx file.txt
对象 含义
u 属主
g 属组
o 其他用户
a 所有用户,等价于 ugo
操作 含义
+ 增加权限
- 移除权限
= 设置为指定权限

数字方式:

r = 4
w = 2
x = 1

7 = rwx
6 = rw-
5 = r-x
4 = r--
0 = ---

示例:

chmod 750 /srv/project
chmod 640 file.txt
chmod -R g+r /srv/project

常用参数:

参数 作用
-R 递归修改目录及其内容
--reference=文件 参照已有文件设置权限
-v 显示处理过程

特殊权限

数值 名称 常见用途
4 setuid 程序以文件属主身份运行,风险高
2 setgid 文件以属组身份运行;目录中新文件继承目录属组
1 sticky 目录中的文件通常只有文件属主、目录属主或 root 能删除
chmod 1777 /tmp
chmod 4755 /path/to/program
chmod 2770 /srv/project

setuid 应谨慎使用,不建议给脚本或普通程序随意设置。

默认权限 umask

umask
umask 027

umask 027 时:

  • 普通文件最大权限 666,实际通常为 640。
  • 目录最大权限 777,实际通常为 750。

权限排查

命令 作用
ls -ld /path 查看目录本身的权限和属主
ls -l /path/file 查看文件权限和属主
id 用户 查看用户 UID、主组和附加组
namei -l /path/file 逐级查看路径上每一层目录权限
getfacl /path 查看 ACL 权限

五、共享目录与 ACL

共享目录

团队共享目录推荐使用“属组 + setgid + 合适 umask”:

sudo groupadd project
sudo usermod -aG project alice
sudo mkdir -p /srv/project
sudo chown root:project /srv/project
sudo chmod 2770 /srv/project
  • 2770 中的 2 是 setgid 位。
  • 目录下新建文件和子目录会自动继承属组 project。
  • 组内用户可读写和进入,其他用户无权限。
  • 用户需要重新登录,确保新附加组生效。

ACL 精细授权

ACL 适合给额外用户或组授权,而不改变文件的基本属主和属组:

sudo setfacl -m u:bob:rw /srv/project/file.txt
sudo setfacl -m g:ops:rx /srv/project
sudo setfacl -d -m g:project:rwx /srv/project
getfacl /srv/project
参数 作用
-m 修改 ACL 规则
-x 用户或组 删除指定 ACL 规则
-b 删除所有扩展 ACL
-d 设置目录默认 ACL,新建内容自动继承

查看和清理:

getfacl /srv/project
sudo setfacl -x u:bob /srv/project/file.txt
sudo setfacl -b /srv/project/file.txt

ACL 的 mask 会限制组和命名用户的权限范围,排查权限时不应只看 ls -l。

六、sudo 权限

不建议直接把用户写入 /etc/sudoers,优先使用组和 visudo。

sudoers 规则的基本结构

一条 sudoers 规则通常写成:

用户或组  主机 = (运行身份) 命令

完整语法可以理解为:

User_List Host_List = (Runas_List) Tag_Spec: Cmnd_List

例如:

%dev ALL=(root) /usr/bin/systemctl restart myapp

这条规则的字段含义:

字段 示例 含义
用户或组 %dev % 开头表示组 dev;不加 % 表示用户
主机 ALL 规则适用于所有主机
= = 分隔“谁/在哪”与“能做什么”
运行身份 (root) 允许通过 sudo -u root 以 root 身份执行
命令 /usr/bin/systemctl restart myapp 只允许执行这条具体命令

因此该规则表示:

dev 组中的用户,可以在任意主机上,
以 root 身份执行:
sudo /usr/bin/systemctl restart myapp

注意:

  • %dev 是组;dev 才是用户。
  • ALL 在主机位置表示所有主机,在命令位置表示所有命令,在运行身份位置表示所有用户,含义随字段位置变化。
  • (root) 只限定可以“以谁的身份”运行,不是“只能运行 root 的命令”。
  • 写了具体命令和参数后,用户通常只能按该参数形式执行;不要误以为可以执行 systemctl 的任意子命令。
  • systemctl 应使用实际绝对路径,建议通过 command -v systemctl 确认。
  • systemctl restart myapp 中的服务名和参数要按实际服务名调整。
  • 如果服务名和参数可被用户控制,仍可能形成越权风险。

常用 sudoers 字段

写法 含义
alice ALL=(ALL) ALL alice 可在所有主机上以任意用户身份执行任意命令
%dev ALL=(ALL) ALL dev 组所有成员拥有上述权限
%dev ALL=(root) ALL dev 组只能以 root 身份执行任意命令
%dev ALL=(root) /usr/bin/systemctl restart myapp 只允许执行指定命令
%dev ALL=(root) NOPASSWD: /usr/bin/systemctl status myapp 指定命令免密码,但仍需是 dev 组成员
alice ALL=(root) /usr/bin/systemctl restart myapp 只授权单个用户

NOPASSWD: ALL 表示什么

%dev ALL=(ALL) NOPASSWD: ALL

含义:

字段 含义
%dev dev 组的所有成员
ALL 在任意主机上
(ALL) 可以以任意用户身份运行,包括 root
NOPASSWD: 执行 sudo 时不需要输入该用户自己的密码
ALL 可以执行任意命令

等价于:

dev 组中的任何成员,都能免密获得完整的 root 权限,
可以执行任意命令、读取任意文件、修改系统配置。

这不是“免密执行某一条命令”,而是“免密执行所有命令”。因此:

  • 只应在完全可信、受控的运维组中使用。
  • 不应授予普通开发组、临时账号或共享账号。
  • 用户一旦进入该组,基本等同于拥有 root 权限。
  • 应优先改为收窄命令、收窄运行身份,例如:
%dev ALL=(root) NOPASSWD: /usr/bin/systemctl status myapp

PASSWD: 与 NOPASSWD: 相反,表示执行该命令前需要认证。标签会影响同一命令列表中后续命令,使用 PASSWD: 可以恢复密码验证:

%dev ALL=(root) NOPASSWD: /usr/bin/systemctl status myapp, PASSWD: /usr/bin/systemctl restart myapp

命令别名与排除规则

实际 sudoers 配置中常见下面这种写法:

%tbdba  ALL=(ALL) ALL,SUPERMIT,!SHELLS,SUDOEXEC,!VIETC
%tbnoc  ALL=(ALL) ALL,SUPERMIT,!SHELLS,SUDOEXEC,!VIETC,!USERADD
%tbscm  ALL=(ALL) ALL,SUPERMIT,!SHELLS,SUDOEXEC,!VIETC,!USERADD
%tbdev  ALL=(ALL) ALL,SUPERMIT,!SHELLS,SUDOEXEC,!VIETC,!USERADD
%tbtest ALL=(ALL) ALL,SUPERMIT,!SHELLS,SUDOEXEC,!VIETC,!USERADD

逐段理解:

片段 含义
%tbdba 等 组 tbdba 等组的所有成员
ALL 在任意主机上
(ALL) 可以以任意用户身份运行,包括 root
ALL 允许运行所有命令
SUPERMIT 引用名为 SUPERMIT 的 sudoers 别名
!SHELLS 排除名为 SHELLS 的命令别名
SUDOEXEC 引用名为 SUDOEXEC 的别名
!VIETC 排除名为 VIETC 的命令别名
!USERADD 排除名为 USERADD 的命令别名

这些大写名称不是 sudo 内置命令,而是当前 sudoers 文件中通过 Cmnd_Alias 定义的可复用命令集合,例如:

Cmnd_Alias SHELLS   = /bin/sh, /bin/bash, /bin/csh
Cmnd_Alias USERADD  = /usr/sbin/useradd, /usr/sbin/usermod, /usr/sbin/userdel
Cmnd_Alias VIETC    = /usr/bin/vi /etc/passwd
Cmnd_Alias SUDOEXEC = /usr/bin/sudo

以上只是结构示例,不代表本机实际定义。要确认真实含义,需要查看:

sudo grep -R 'Cmnd_Alias.*\(SUPERMIT\|SHELLS\|SUDOEXEC\|VIETC\|USERADD\)' /etc/sudoers /etc/sudoers.d

或者查看某用户最终解析后的权限:

sudo -l -U alice

需要特别理解 ALL 与 !别名 的组合:

  • ALL 先表示允许所有命令。
  • !SHELLS、!VIETC、!USERADD 表示从命令集合中排除这些命令。
  • 但这类排除通常不能形成可靠的安全边界。sudo 手册明确指出:从 ALL 中使用 ! 减去少量命令,一般不会按预期生效。
  • 用户可以复制被排除的命令到另一个文件名后执行,也可以通过编辑器、分页器等程序的 Shell 逃逸绕过。
  • 如果用户同时拥有 ALL,实际上很难阻止其创建自己的程序来获得 root Shell。
  • 因此这些 !SHELLS、!VIETC、!USERADD 更适合视为“提示性限制”或审计标记,不能当作真正的隔离措施。
  • 需要严格限制时,不要先给 ALL;应只白名单列出允许的具体命令,并配合 NOEXEC、sudoedit 等机制。

五个组的差异:

  • tbdba 没有 !USERADD,因此其规则没有显式排除 USERADD 别名中的命令,但仍受 ALL 和其他排除规则影响。
  • tbnoc、tbscm、tbdev、tbtest 都包含 !USERADD,显式排除了 USERADD 别名对应的用户管理命令。
  • 五条规则都包含 SUPERMIT、!SHELLS、SUDOEXEC、!VIETC,具体权限仍由这些别名定义决定。
  • 由于五条规则都已经包含 ALL,这些差异不能理解为严格的安全隔离;拥有这些组权限的用户仍可能通过其他命令或自建程序绕过限制。

这类规则常见于“受限运维组”的设计:希望授予大部分 root 能力,同时用别名表达不希望使用的 Shell、用户管理、关键配置编辑等操作。但必须注意:ALL 之后的 ! 排除通常只是管理约定,不是可靠的技术隔离。实际评估时既要查看完整别名定义,也要通过 sudo -l -U 用户 和实际测试确认权限边界。

推荐写法

使用组授权,并放到独立配置文件中:

sudo groupadd ops
sudo usermod -aG ops alice
sudo visudo -f /etc/sudoers.d/ops

文件中写入:

%ops ALL=(root) /usr/bin/systemctl restart myapp

检查配置和用户权限:

sudo visudo -c
sudo -l -U alice

Debian/Ubuntu 常见 sudo 组:

sudo usermod -aG sudo alice

RHEL/CentOS 常见 sudo 组:

sudo usermod -aG wheel alice

注意:sudo 组成员和 wheel 组成员的具体权限由发行版默认 sudoers 配置决定,加入组后仍应使用 sudo -l -U 用户 核实实际权限。

七、完整流程与排错

创建用户完整流程

sudo groupadd dev
sudo useradd -m -u 2001 -g dev -s /bin/bash alice
sudo passwd alice
sudo chage -d 0 alice
sudo usermod -aG sudo alice   # Debian/Ubuntu,按需
id alice

修改用户完整流程

sudo usermod -aG docker alice
sudo usermod -s /bin/bash alice
sudo chage -M 90 alice
id alice

删除用户完整流程

pgrep -u alice -a
sudo tar czf /backup/alice-home.tar.gz /home/alice
sudo userdel -r alice
sudo find / -uid 2001 -ls 2>/dev/null

常见问题

现象 排查方向
用户创建后不能登录 是否设置密码、Shell 是否为 nologin、家目录和账号是否正常
加入组后权限没生效 是否重新登录,当前会话是否仍使用旧组信息
附加组丢失 是否误用了 usermod -G,应使用 -aG
修改 UID/GID 后文件异常 旧文件仍保留旧 UID/GID,需要手动修正
groupdel 失败 该组可能是某个用户的主组,先修改主组
删除用户后有残留 检查 cron、sudoers、SSH、数据库、systemd 和家目录外文件
共享目录文件属组不对 检查目录 setgid、用户附加组和 umask
sudo 不生效 使用 visudo 检查语法,确认用户已重新登录
posted @ 2026-10-29 13:58  lxd670  阅读(7)  评论(0)    收藏  举报