Skip to content

用户与组

Linux 的登录认证、文件权限、服务进程身份都围绕用户和组展开。排查权限问题时,需要同时确认账号是否存在、属于哪些组、使用什么 Shell、以及进程以什么身份运行。

一、UID 和 GID

Linux 内核识别的是数字 ID,不是用户名。用户名只是给人看的标签,权限判断时看的是 UID 和 GID。

名称含义
UID用户 ID。0 是 root,拥有完整权限
GID主组 ID。每个用户属于一个主组
附加组用户额外加入的其他组,一个用户可同时属于多个组

查看当前用户身份:

bash
whoami       # 当前用户名
id           # uid、gid、所有附加组
groups       # 所属组列表

排查权限问题看 id 比看 whoami 更有价值。一个用户能否访问某个文件,取决于他的 uid 和所有 gid,光看用户名判断不了完整权限。

文件系统中记录的 owner 和 group 本质上是 UID 和 GID 的数字。两台机器之间复制文件时,如果目标机器上相同 UID 对应的用户不同,就会出现文件属于"不认识的人"的情况。比如源机器上 UID 1001 是 nginx,目标机器上 UID 1001 是 deploy,文件拷过去后 ls -l 会显示 owner 是 deploy

二、用户和组的关键文件

Linux 的用户和组信息分布在几个文件中。直接 cat 这些文件也行,但用 getent 更可靠——它会走系统名称服务(NSS),LDAP、NIS 等集中认证环境也能正确查询。

文件内容
/etc/passwd用户名、UID、GID、家目录、Shell
/etc/shadow密码哈希、密码过期策略
/etc/group组名、GID、组成员
/etc/gshadow组密码(很少用)
bash
getent passwd nginx
getent group wheel

/etc/passwd 一行拆解:

root:x:0:0:root:/root:/bin/bash
字段说明
用户名root登录时使用的名称
密码占位x密码哈希实际存在 /etc/shadow
UID0用户 ID
GID0主组 ID
GECOSroot注释字段,通常放全名或说明
家目录/root登录后的起始目录
Shell/bin/bash登录后启动的 Shell

三、创建用户

bash
useradd app          # 创建用户
passwd app           # 设置密码

useradd 的默认行为受 /etc/login.defs/etc/default/useradd 两个配置影响——是否创建家目录、默认 Shell、UID 范围等,不同发行版默认值不完全一样。生产上创建服务账号时,关键参数显式指定更保险。

指定家目录和 Shell:

bash
useradd -m -d /home/deploy -s /bin/bash deploy

创建不需要登录的服务用户(系统用户):

bash
useradd -r -s /sbin/nologin nginx

-r 创建系统用户,分配的 UID 通常在系统用户范围内(不同发行版范围不同)。/sbin/nologin/usr/sbin/nologin 作为 Shell 时,该用户不能登录系统,但服务进程仍然可以用它运行。

四、修改和删除用户

bash
usermod -aG wheel deploy         # 追加到 wheel 附加组
usermod -s /bin/bash deploy      # 修改登录 Shell
usermod -L deploy                # 锁定用户(禁止登录)
usermod -U deploy                # 解锁用户

usermod -G 的正常行为是替换所有附加组。要追加而不是替换,必须加 -a。这条很容易出错——把用户加到 docker 组或 sudo 组时漏了 -a,用户就会从原来的所有附加组中被移除。

删除用户:

bash
userdel app
userdel -r app        # 同时删除家目录和邮件目录

正式环境下删除用户前,通常先锁定再看一段时间,确认没有遗留的定时任务或服务依赖这个账号。

bash
usermod -L olduser
chage -E 0 olduser    # 将账号过期时间设为 1970-01-01,立即失效

五、su 和 sudo

su 切换用户身份:

bash
su - app

su -(带横杠)会加载目标用户的完整登录环境,包括环境变量、PATH、工作目录等。su app 不带横杠只切换用户身份,不切换环境,执行时会继承原来用户的 PATH 和当前目录。

sudo 以其他用户身份执行单条命令:

bash
sudo systemctl restart nginx

sudo 的配置文件通过 visudo 编辑:

bash
visudo

visudo 在保存前会检查语法,防止写错后 sudo 全部不可用。直接手动编辑 /etc/sudoers 有风险。

RHEL 系的管理员组通常叫 wheel,Ubuntu 叫 sudo。把一个用户加入管理员组:

bash
usermod -aG wheel deploy     # RHEL 系
usermod -aG sudo deploy      # Ubuntu / Debian

sudoers 中针对特定命令的授权写法:

sudoers
deploy ALL=(root) /usr/bin/systemctl restart nginx

字段从左到右:(1)授权哪个用户或组(组前面加 %);(2)从哪些主机登录时生效;(3)以谁的身份执行;(4)允许执行的具体命令,须写绝对路径。

sudo 权限的粒度越细越好。所有人配成 ALL=(ALL) NOPASSWD:ALL 在运维上风险偏高——事后看 sudo 日志,无法区分是谁执行了高危命令。

六、查看登录状态

bash
w                # 当前有哪些用户登录,在做什么
who              # 简化的在线用户列表
last             # 历史登录记录(读取 /var/log/wtmp)
lastb            # 失败登录记录(读取 /var/log/btmp)

SSH 暴露在公网时 lastb 的输出通常很长。暴力尝试多的时候,改端口只能减少日志噪音,真正的安全依赖仍然是密钥认证、限制来源 IP 或走堡垒机统一入口。