前言
Linux是一个多用户、多任务的操作系统,用户与权限管理是Linux系统安全的核心基石。所有系统操作、文件访问和进程运行都基于用户身份和权限控制。深入理解用户分类、UID/GID机制、sudo权限和文件权限体系,是保障系统安全、规范用户行为的必备技能。
本文内容适用于 Ubuntu、CentOS 9 Stream、银河麒麟 和 openEuler 等所有主流Linux发行版。
::
一、用户与组的基础概念
1.1 UID与GID:用户和组的唯一标识
Linux系统不通过用户名识别用户,而是通过数字ID来识别:
- UID (User ID):用户唯一标识号,每个用户拥有一个全局唯一的UID。
- GID (Group ID):用户组唯一标识号,每个组拥有一个全局唯一的GID。
NOTE核心配置文件
- 用户名和UID的映射关系存储在
[/etc/passwd]密级文件中。 - 用户密码哈希值存储在处于极高权限读写控制的
[/etc/shadow]文件中。 - 组名和GID的映射关系存储在
/etc/group文件中。 ::
1.2 /etc/passwd:揭秘用户账户的核心档案
在 Linux 中,所有用户的基本信息(除了密码的真实哈希值)都以明文形式公开存放在 /etc/passwd 文件中。理解这个文件的结构,是排查用户问题的基本功。
我们可以使用 cat 或 head 查看其中的内容:
[root@server ~]# head -n 3 /etc/passwdroot:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologintestuser:x:1000:1000:Test Account:/home/testuser:/bin/bash每一行代表一个用户,通过冒号 : 分隔成了 7 个关键字段。以 testuser:x:1000:1000:Test Account:/home/testuser:/bin/bash 为例,字段含义拆解如下:
| 字段序号 | 示例内容 | 含义解析 |
|---|---|---|
| 1 | testuser | 用户名。登录时使用的账号名称。 |
| 2 | x | 密码占位符。早期的确在这里存密码,后来为了安全,密码被移到了权限极严的 /etc/shadow 中,这里统一用 x 占位。 |
| 3 | 1000 | UID (用户ID)。系统内部真正用来识别用户的数字标识。 |
| 4 | 1000 | GID (主组ID)。用户所属的主组的数字标识,对应 /etc/group 中的记录。 |
| 5 | Test Account | 用户信息说明。通常是用户的全名、联系方式等备注信息(可选字段,可为空)。 |
| 6 | /home/testuser | 家目录路径。用户登录成功后,默认进入的工作目录。 |
| 7 | /bin/bash | 默认 Shell。用户登录后分配的命令解释器。如果是 /sbin/nologin 或 /bin/false,则代表该用户被禁止登录系统(通常用于系统服务账号)。 |
1.3 Linux用户分类
根据UID范围和权限不同,Linux用户分为三类:
| 用户类型 | UID范围 | 说明 |
|---|---|---|
| 超级用户 (root) | 0 | 拥有系统最高权限,可以执行任何操作,不受权限限制。 |
| 系统用户 | 1-999 | 系统服务运行所需的用户,默认禁止登录Shell,如 nginx、mysql。 |
| 普通用户 | 1000+ | 管理员创建的普通登录用户,权限受限,仅能操作自己家目录和授权资源。 |
[!WARNING] 发行版差异注意
Ubuntu 22.04 LTS及更新的发行版,普通用户UID从1000开始(早期部分版本为500+)。跨发行版迁移数据时需警惕UID错位导致权限丢失的问题。
1.4 用户组的概念
用户组是具有相同权限的用户集合,用于简化权限管理:
- 主组 (primary group):每个用户必须且只能有一个主组,创建用户时默认创建同名主组。
- 附加组 (supplementary group):用户可以加入0个或多个附加组,继承附加组的所有权限。
二、用户管理核心命令(增删改查完全指南)
在日常运维中,员工入职、转岗、离职都对应着账号的生命周期管理。以下所有增删改查操作,均需要 root 权限或通过 sudo 执行。
2.1 创建与删除用户:useradd & userdel
创建用户 (useradd)
创建新用户账户是系统初始化的第一步。不同的场景需要搭配不同的参数。
常用参数速查表:
| 参数 | 作用说明 | 常见场景 |
|---|---|---|
-m | 自动创建用户的家目录(/home/用户名) | 为真人创建账号时必加 |
-s | 指定用户的默认 Shell 程序 | 正常登录指定 /bin/bash,禁止登录指定 /sbin/nologin |
-g | 指定用户的主组(只能有一个) | -g developers |
-G | 指定用户的附加组(可多个,逗号分隔) | -G wheel,docker |
-r | 创建系统虚拟账户(UID小于1000) | 创建用来运行 Nginx/MySQL 的非登录账号 |
WARNING安全警示
为真人创建登录账户时,务必携带 -m 参数以生成家目录(/home/用户名)。否则用户后续通过 SSH 登录时,将面临无法存放 SSH 公钥(.ssh 目录缺失)、环境配置文件(如 .bashrc)丢失等严重问题。
::
# 1. 常规操作:创建普通用户,自动创建家目录,并指定 bash 为解释器(最常用)useradd -m -s /bin/bash testuser
# 2. 复合操作:创建用户时,直接指定它的主组(-g)和多个附加组(-G)# 场景:新入职开发,属于 developers 组,同时需要 nginx 和 wheel 的权限useradd -m -s /bin/bash -g developers -G wheel,nginx devuser
# 3. 创建系统虚拟用户(极其重要)# 场景:为了运行 Nginx 或 MySQL 建立的账号。# 必须加上 -r(系统账号)、-s /sbin/nologin(禁止登录)、不需要 -m(不需要家目录)useradd -r -s /sbin/nologin mysql删除用户 (userdel)
员工离职时,妥善删除账号是必经流程,删除分为“软删除”和“硬删除”。
常用参数速查表:
| 参数 | 作用说明 | 常见场景 |
|---|---|---|
| (无) | 仅删除用户账号信息,保留家目录 | 员工离职,账号回收但需要保留其工作文件交接 |
-r | 彻底删除用户,连同家目录和邮件池一并删除 | 清理测试账号、清理已完成交接的离职人员垃圾 |
# 1. 软删除:仅删除系统账号,但保留 /home/testuser 家目录里的数据# 场景:员工离职,账号回收,但他的工作文件需要留给主管审查交接userdel testuser
# 2. 硬删除:彻底删除账号,并强制删掉对应的家目录和本地邮件池# 场景:交接完毕,彻底清理系统垃圾userdel -r testuser2.2 密码安全生命周期:passwd
passwd 不仅仅是用来“改密码”的,它更是系统管理员控制账户安全周期的利器。
常用参数速查表:
| 参数 | 作用说明 | 常见场景 |
|---|---|---|
-e | 强制密码过期 (expire) | 统一建号后,要求新员工首次登录必须重置密码 |
-l | 锁定账户 (lock) | 发现账号异地登录或被爆破,紧急冻结禁止密码登录 |
-u | 解锁账户 (unlock) | 解除锁定状态 |
-S | 查看状态 (Status) | 查看某账号当前是否被锁定、密码过期时间等信息 |
-d | 删除密码 (delete) | 极度危险,允许账号无密码登录,绝对禁止使用! |
# 1. 修改密码:root 可以改任何人的,普通用户直接敲 passwd 只能改自己的passwd testuser
# 2. 强制下次登录重置密码(极度推荐!)# 场景:管理员统一为新员工建号并设置初始密码(如 123456),# 执行此命令后,新员工第一次登录必须马上修改密码,免去安全隐患passwd -e testuser
# 3. 锁定异常账户(防爆破)# 场景:发现 testuser 正在被频繁爆破密码,紧急锁定,让他无法用密码登录passwd -l testuser
# 4. 解锁账户passwd -u testuser
# 5. 查看账户的密码状态(LK=锁定,PS=正常,NP=无密码)passwd -S testuserCAUTION危险操作
绝对禁止使用 passwd -d 用户名 清空密码。此举将极大降低系统防御等级,造成任意人员零门槛提权隐患!
::
2.3 修改用户属性:usermod
当员工转岗,或者需要临时提权、封禁时,usermod 是修改已存在用户属性的神器。
常用参数速查表:
| 参数 | 作用说明 | 常见场景 |
|---|---|---|
-aG | 追加用户到附加组 (Append Group) | 提权必备:把用户加到 wheel 或 docker 组 |
-s | 修改默认 Shell | 封禁账号登录权限时改为 /sbin/nologin |
-l | 修改登录名 (Login) | 员工改名或转正平滑修改账号名,不影响底层 UID 和数据 |
-g | 修改主组 | 改变用户的初始主组(不推荐频繁操作主组) |
# 1. 将用户追加到新的附加组# 场景:让普通用户获得 sudo 提权资格(CentOS系加到 wheel,Ubuntu系加到 sudo)usermod -aG wheel testuser
# 2. 封禁登录:修改用户的默认 Shell# 场景:外包人员项目结束,保留数据但不允许再登录系统usermod -s /sbin/nologin testuser
# 3. 账号更名:平滑变更为新名字,原有的 UID、GID、家目录统统不变# 场景:外包转正,从 v-zhangsan 改名为 zhangsanusermod -l newuser olduser
# 4. 修改用户的主组(很少用,通常只改附加组)usermod -g newgroup testuserTIP血泪教训
在赋予用户新的附加组时,必须且永远使用 -aG(Append + Group)。如果漏写 a(仅使用 -G),将会直接清空并覆盖该用户原有的所有附加组!无数新手因为漏掉一个 a 导致用户丢失了原本的文件访问权限。
::
2.4 用户组的创建与修改:groupadd 等
权限控制的基石是 RBAC(基于角色的访问控制),在 Linux 中体现为**“组管理”**。我们应该先建组、给组赋权,再把用户拉进组里。
组管理核心命令与参数速查表:
| 命令/参数 | 作用说明 | 常见场景 |
|---|---|---|
groupadd | 创建新的用户组 | groupadd developers |
groupadd -r | 创建系统虚拟用户组 | 创建分配给 Nginx 等后台服务的组,GID 会小于 1000 |
groupmod -n | 修改用户组的名称 (New Name) | 公司部门改名,将 dev 组改名为 rd 组 |
groupdel | 删除用户组 | 清理废弃的权限组。注意:如果该组是某人的主组,则无法删除 |
gpasswd -a | 把用户加入组 (Add) | 相当于 usermod -aG,把 testuser 加进 wheel 组 |
gpasswd -d | 把用户移出组 (Delete) | 剥夺权限必备:将离职或转岗员工踢出核心运维组 |
# 1. 创建一个新用户组(如研发组、运维组)groupadd developers
# 2. 创建系统级的虚拟用户组(配合系统虚拟账户使用)groupadd -r mysql
# 3. 修改组名(将 developers 平滑变更为 devops,原有的 GID 不变)groupmod -n devops developers
# 4. 将用户移出某个附加组(使用 gpasswd 命令)# 场景:实习生结束轮岗,剥夺他的高级运维权限(移出 wheel 组)gpasswd -d testuser wheel
# 5. 删除用户组# 注意:如果要删除的组是某个用户的主组,则必须先删用户或修改其主组,否则无法删除groupdel devops2.5 查看与切换身份 (su 与查询命令)
日常排错时,我们需要经常查看用户身份,或者切换身份去验证权限。这里面的参数携带尤为关键。
切换身份参数速查表 (su):
| 参数组合 | 执行逻辑 | 核心特点与区别 |
|---|---|---|
su - 用户名 | 完全切换(Login Shell) | 强烈推荐。会完全读取目标用户的环境变量(如 .bashrc、.profile),并且当前目录直接切换到目标用户的家目录,就像重新登录了一样。 |
su 用户名 | 非完全切换(Non-login Shell) | 极度不推荐。只切换了身份,但保留上一个用户的环境变量和当前所在路径。经常导致命令找不到、权限错乱等各种诡异问题。 |
su - 用户名 -c "命令" | 免切身份执行单次命令 | 运维写脚本或配置 crontab 定时任务时的绝佳伴侣,不需要真的切进去。 |
# 1. 查看指定用户的身份信息(UID、主组、所有附加组)# 场景:排查某人为什么打不开某个文件,先看他在不在对应的组里id testuser
# 2. 抓内鬼:查看当前有哪些人在线,正在执行什么命令wwho
# 3. 切换身份(切记区分带减号和不带减号的区别)# 【强烈推荐】完全切换(需要密码,且重新加载该用户的完整环境变量,像重新登录一样)su - testuser
# 【不推荐】仅切换身份(环境变量仍残留上一个用户的配置,极易引发命令找不到、路径错乱)8 collapsed lines
su testuser
# 4. 免切用户执行一次性指令(运维最爱)# 场景:在 root 的定时任务 (crontab) 中,以 testuser 的身份去跑脚本su - testuser -c "sh /home/testuser/backup.sh"
# 5. 企业绝活:批量枚举系统所有可登录的真人账户(UID >= 1000 且 Shell 正常)awk -F: '$3 >= 1000 && $7 != "/sbin/nologin" && $7 != "/bin/false" {print $1}' /etc/passwd三、sudo 提权与精细化权限配置
在现代 Linux 服务器运维中,**“绝对禁止直接使用 root 登录”**是第一安全铁律。所有的高危操作都应该由普通用户通过 sudo 命令临时提权来完成。这样不仅能收敛权限,还能在系统日志(/var/log/secure 或 /var/log/auth.log)中留下清晰的操作审计记录。
3.1 为什么必须用 visudo?
配置 sudo 权限就是修改 /etc/sudoers 文件。
IMPORTANT生死攸关的规范
绝对禁止使用 vim /etc/sudoers 直接修改!必须使用 visudo 命令。
visudo 会在保存退出时自动进行语法校验。如果你用 vim 写错了一个符号,会导致全公司所有人都无法使用 sudo,连 root 都切不进去,系统直接“变砖”!
::
3.2 配置文件核心语法拆解
用 visudo 打开配置后,你会看到类似这样的配置格式:
root ALL=(ALL:ALL) ALL这五个部分的含义决定了权限的分配逻辑:
- 谁来执行:
root(可以是用户名,也可以是%组名) - 在哪里执行:第一个
ALL(表示可以在任何主机/网络上执行) - 以谁的身份:括号里的第一个
ALL(表示可以切换成系统里的任何用户,通常是 root) - 以什么组的身份:括号里的第二个
ALL(可省略,表示任何用户组) - 能执行什么命令:最后一个
ALL(表示允许执行所有命令,必须写命令的绝对路径)
3.3 企业级场景配置实战
在实际企业中,我们不会给每个人都分配 ALL 权限,而是会根据岗位职责进行“精细化切割”。
场景 1:给高级运维分配所有权限(免密)
默认情况下,每次敲 sudo 都要输一次自己的登录密码,非常繁琐。对于核心运维,可以配置免密执行。
# 允许 wheel 组的所有成员执行任何命令,并且不需要输入密码%wheel ALL=(ALL) NOPASSWD: ALL场景 2:给开发人员开放特定服务的重启权限
开发人员经常需要重启自己的项目服务,但绝对不能给他们删库的权限。
# 允许 devuser 用户免密执行重启 docker 服务和操作 docker 容器的命令# 注意:命令必须写绝对路径!devuser ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart docker, /usr/bin/docker *场景 3:黑名单机制(防范内鬼提权)
给某个外包团队分配了几乎所有权限,但唯独要防范他们修改 root 密码或切换到 root。
# 允许 opsadmin 执行所有命令,但禁止切换到root、禁止改root密码、禁止改sudoers文件opsadmin ALL=(ALL) ALL, !/usr/bin/su, !/usr/bin/passwd root, !/usr/sbin/visudo3.4 进阶技巧:使用命令别名 (Cmnd_Alias) 简化配置
当系统里有几十个开发人员、十几个服务需要管理时,一行行写绝对路径会让人崩溃。/etc/sudoers 支持使用别名来将命令和人员打包。
# 1. 定义用户别名(把张三、李四打包成 WEB_ADMINS)User_Alias WEB_ADMINS = zhangsan, lisi
# 2. 定义命令别名(把所有和 Nginx 相关的命令打包成 NGINX_CMDS)Cmnd_Alias NGINX_CMDS = /usr/bin/systemctl start nginx, /usr/bin/systemctl stop nginx, /usr/bin/systemctl reload nginx
# 3. 将别名绑定:允许 WEB_ADMINS 组的人免密执行 NGINX_CMDS 里的命令WEB_ADMINS ALL=(ALL) NOPASSWD: NGINX_CMDSTIP配置分离的最佳实践
在现代 Linux 中,我们通常不直接修改 /etc/sudoers 主文件。而是会在 /etc/sudoers.d/ 目录下,为每个项目或团队新建一个独立的配置文件(例如 visudo -f /etc/sudoers.d/dev_team)。这样不仅方便管理,也避免了多人同时修改主文件引发冲突。
::
四、Linux文件权限体系及修改
4.1 符号与数字八进制转换阵列
Linux文件将权限拆分为所有者 (u)、所属组 (g) 和其他用户 (o) 三维控制体。
| 权限类型 | 标识符号 | 八进制数字 | 对普通文件的作用 | 对目录的作用核心效果 |
|---|---|---|---|---|
| 读 (Read) | r | 4 | 可以 cat, less 阅览内容 | 可以 ls 列出目录结构名单 |
| 写 (Write) | w | 2 | 可以 vim 修补和覆盖内容 | 允许在目录内部 touch, rm 文件 |
| 执行 (Execute) | x | 1 | 将脚本作为二进制进程投递运行 | 通行证:可以 cd 进入该目录底层 |
4.2 赋权操作:chmod 与 chown
在 Linux 中,权限的修改分为两部分:改权限(谁能干嘛)用 chmod,改归属(这是谁的)用 chown。
1. chmod:修改权限(Change Mode)
chmod 支持两种写法:数字法(如 755)和字母法(如 u+x)。在自动化运维脚本中,数字法最为高效和普及。
字母法参数速查表:
| 对象控制符 | 含义 | 授权操作符 | 含义 | 权限符 | 含义 |
|---|---|---|---|---|---|
u | 所有者 (user) | + | 增加权限 | r | 读 |
g | 所属组 (group) | - | 撤销权限 | w | 写 |
o | 其他人 (other) | = | 精确覆盖权限 | x | 执行 |
a | 所有人 (all) |
# 【经典组合】所有者具有完全读写,组及其他仅可读chmod 644 config.yml
# 【追加执行权限】(常用于自己刚写完的脚本)chmod +x script.sh # 等价于 chmod a+x (给所有人加执行权限)chmod u+x script.sh # 只给所有者自己加执行权限
# 【基线规范】递归分离化授权:网站目录赋755,文件降权至644(防止黑客上传的图片被当成木马执行)find /var/www/html -type d -exec chmod 755 {} \;find /var/www/html -type f -exec chmod 644 {} \;2. chown:修改所有者和所属组(Change Owner)
当使用 root 账号解压、拉取了属于普通用户的代码,或者创建了日志目录时,务必使用 chown 修正归属。否则普通用户的服务(如 Nginx、MySQL)将因没有权限读取文件而启动失败,这是排查权限报错(Permission denied)时最常干的事。
chown 参数与语法速查表:
| 语法格式 | 作用说明 | 常见场景 |
|---|---|---|
chown user 文件 | 仅修改文件所有者为 user | 改变单个文件的控制权 |
chown user:group 文件 | 同时修改所有者为 user,所属组为 group | 最常用格式,冒号 : 或点 . 是分隔符 |
chown :group 文件 | 仅修改所属组(相当于 chgrp group 文件) | 开放某个文件给特定协作组读写 |
chown -R ... | 递归修改整个目录及其内部所有子文件/目录 | 给网站根目录或数据盘批量易主 |
# 1. 仅修改文件所有者为 testuserchown testuser deployment.sh
# 2. 仅修改文件所属组为 developers(前面留空只写冒号和组名)chown :developers deployment.sh
# 3. 同时修改所有者为 testuser,且所属组变更为 developerschown testuser:developers deployment.sh
# 4. 【核心参数 -R】深度易主:递归转移整个层级目录属权(运维最高频操作)# 场景:你用 root 拉取了最新的前端代码放到 /var/www/html,# 必须把整个文件夹移交给 nginx 账号,否则网页会报 403 Forbiddenchown -R nginx:nginx /var/www/html/4.3 高级进阶:特殊权限(SUID/SGID/SBIT)
除了普通的 rwx,Linux 还有三个高级权限位,它们能打破常规的安全壁垒:
- SUID (4):只能作用于可执行的二进制程序。普通用户在执行这个程序时,会临时获得程序所有者的权限。最经典的例子是
/usr/bin/passwd,普通用户能靠它修改/etc/shadow就是因为 SUID。 - SGID (2):作用于目录时,任何人在该目录下创建的新文件,所属组都会自动继承该目录的所属组。(常用于团队共享协作目录)。
- SBIT 粘滞位 (1):只能作用于目录。在该目录下,用户只能删除自己创建的文件,不能删除别人的文件。最经典的例子是公共临时目录
/tmp(权限是1777)。
# 赋予 SUID 权限(数字法在原有的三位前加 4)chmod 4755 /usr/local/bin/myapp# 赋予 SGID 权限chmod 2775 /shared_data/# 赋予 SBIT 粘滞位chmod 1777 /company_tmp/4.4 权限防护盾:默认掩码 Umask 控制
为什么我们 touch 一个新文件,它的默认权限是 644,而 mkdir 一个新目录,默认权限是 755?这就是被 umask 拦截处理后的结果。
- 新建文件的默认最高基底权限为
666(系统禁止文件一创建就有执行权限)。 - 新建目录的默认最高基底权限为
777。 - 最终生成的权限值 = 基底基数 - umask。
系统默认的 umask 是 022,所以:
- 文件:
666 - 022 = 644 - 目录:
777 - 022 = 755
# 在全局环境拦截高危文件建立(针对协同配合进行微调)if [ "$UID" -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then umask 022 umask 002 # 改为002,协同组创建的文件权限将自动变为664,目录变为775,方便同组人互相修改fi五、最佳实践基线
安全环境非一朝一夕之功。参考著名的自动化加固库 ::github{repo=“devsecops/ansible-os-hardening”},我们梳理了以下强制准则:
- 禁止直接使用root通过SSH登录:配置
PermitRootLogin no,所有提权动作必须依赖具备审计记录的sudo流水线。 - 遵循特权剥离原则 (Principle of Least Privilege):严苛梳理 sudoers 条目,只分配恰好足够运维业务存活的执行命令名单。
- 用户组化管理:拒绝“一号一授权”,采用“组绑定角色,账号分配到组”的标准化RBAC模型。
- 死角审计跟踪:定期轮询分析授权日志
:spoiler[/var/log/secure]或:spoiler[/var/log/auth.log],提取异常提取命令序列。 - 慎用特殊位权限:SUID 是黑客提权的最爱。定期通过
find / -perm -4000 -type f猎杀潜伏的非法SUID文件,拔除系统的“定时炸弹”。