背景与问题
在 Linux 系统的日常运维工作中,用户权限管理是最基础也是最重要的工作之一。无论是一台新增的服务器初始化,还是生产环境的账号权限调整,运维工程师都需要频繁与用户账号、用户组和权限提升打交道。很多初级运维人员在面对 /etc/passwd、/etc/shadow、/etc/group 这些配置文件时往往一头雾水,在配置 sudo 权限时经常把自己锁在系统外面,或者权限配置过于宽松留下安全隐患。
本文将从 Linux 用户权限的底层原理出发,系统讲解用户和用户组的管理机制、权限配置文件的核心字段含义、sudo 的工作原理和配置方法,以及常见权限故障的排查思路。通过本文,读者能够掌握 Linux 权限管理的完整知识体系,具备独立处理各类用户权限问题的能力。
1 Linux 用户与用户组的基础原理
1.1 Linux 如何存储用户信息
Linux 系统中的用户信息存储在三个核心配置文件中:/etc/passwd 存储用户基本信息、/etc/shadow 存储用户密码的加密信息、/etc/group 存储用户组信息。这三个文件共同构成了 Linux 用户认证和授权的基础,理解它们的结构是掌握用户权限管理的第一步。
/etc/passwd 文件的格式为七字段制,以冒号分隔。执行 grep root /etc/passwd 可以看到 root 用户的完整记录:
root:x:0:0:root:/root:/bin/bash
第一个字段 root 是用户名;第二个字段 x 表示密码存储在 /etc/shadow 中(早期 Unix 系统密码直接放在这里,但现在永远不放明文);第三个字段 0 是用户 UID;第四个字段 0 是用户主组的 GID;第五个字段 root 是用户备注信息;第六个字段 /root 是用户主目录;第七个字段 /bin/bash 是用户的登录 Shell。
普通用户的 UID 通常从 1000 开始,系统用户的 UID 通常在 1-999 之间。执行以下命令可以查看系统中 UID 的分配情况:
# 查看所有用户及其 UID,按 UID 排序
awk -F: '{print $1, $3, $4}' /etc/passwd | sort -k2 -n
# 查看系统用户(UID < 1000)
awk -F: '($3 < 1000) {print $1, $3}' /etc/passwd | sort -k2 -n
# 查看普通用户(UID >= 1000)
awk -F: '($3 >= 1000) {print $1, $3}' /etc/passwd | sort -k2 -n
理解 UID 的分区对于系统安全至关重要。UID 0 表示 root 用户,拥有系统最高权限;UID 1-99 是系统预留给系统守护进程和服务的,很多邮件服务器、web 服务器进程以这些 UID 运行;UID 100-499 是系统用户,通常由软件包管理器在安装某些服务时创建;UID 1000+ 是普通用户,由管理员手动创建。某些老旧系统可能使用 UID 500 作为普通用户的起始值,但在现代 Linux 发行版中,Debian 和 RHEL 系的默认配置都使用 1000。
/etc/shadow 文件存储用户密码的加密信息,只有 root 用户和 shadow 组成员可以读取。其格式包含九个字段:
root:$6$randomsalt$hashedpassword:18912:0:99999:7:::
第一个字段是用户名;第二个字段是加密后的密码($6$ 表示 SHA-512 加密,$1$ 是 MD5,$5$ 是 SHA-256);第三个字段是上次修改密码的日期(从 1970-01-01 起算的天数);第四个字段是密码最小存活期(0 表示无限制);第五个字段是密码最大存活期(99999 表示永不过期);第六个字段是密码过期警告提前天数;第七个字段是密码过期后账号宽限期;第八个字段是账号过期日期;第九个字段保留未用。
密码字段前面有 ! 或 * 表示账号已锁定,不能用于登录。执行 passwd -l username 锁定账号,passwd -u username 解锁账号。
/etc/group 文件存储用户组信息,格式为四字段制:
root:x:0:
第一个字段是组名;第二个字段是组密码(通常为 x,表示使用 /etc/gshadow);第三个字段是 GID;第四个字段是成员列表,逗号分隔。
1.2 用户组的作用与分类
用户组是 Linux 权限管理的重要概念。每个用户在创建时都会自动分配一个主组(Primary Group),用户也可以加入多个附加组(Supplementary Groups)。组的主要作用是将多个用户归为一类,统一管理文件访问权限。
在 Linux 中,文件的权限分为三组:所有者(owner)、所属组(group)、其他人(others)。当一个用户创建一个文件时,该文件默认属于该用户的主组。如果需要让多个用户共享一组文件,正确的做法是将这些用户加入同一个用户组,然后设置文件所属组权限。
执行 groups username 可以查看用户所属的所有组:
# 查看当前用户的组信息
groups
# 查看指定用户的组信息
groups www-data
groups nginx
输出示例:
www-data : www-data www-cache nginx
这表示 www-data 用户属于 www-data 主组,同时附加在 www-cache 和 nginx 组中。
理解主组和附加组的区别很重要。用户的 chgrp 或 newgrp 命令只影响主组,而 usermod -G 或 usermod -aG 用于管理附加组。使用 id 命令可以同时看到用户的 UID、主组 GID 和所有附加组:
id www-data
uid=33(www-data) gid=33(www-data) groups=33(www-data),40(www-cache),996(nginx)
1.3 进程与文件权限的关系
理解 Linux 权限模型需要清楚进程与文件权限之间的关系。当用户执行一个程序时,内核会为该进程设置以下权限属性:进程的实际用户 ID(real UID)和实际组 ID(real GID)继承自登录用户;进程的有效用户 ID(effective UID)和有效组 ID(effective GID)通常等于实际用户 ID 和实际组 ID,但可以通过 setuid 程序或 sudo 等机制改变;文件系统用户 ID 和文件系统组 ID 与有效用户 ID 和有效组 ID 相同,用于文件访问权限检查。
文件访问权限检查遵循以下规则:首先检查进程的有效用户 ID 是否等于文件的所有者 UID,如果相等则应用所有者权限;如果不等,再检查进程的有效组 ID 是否等于文件的所属组 GID,如果相等则应用所属组权限;如果都不等,则应用其他人的权限。一旦匹配到对应的权限类别,立即使用该权限,不会继续往下检查。
这个权限检查模型有一个经典案例可以说明:/etc/shadow 文件的权限通常是 600(所有者可读写,其他人无权访问),只有 root 可以读写,普通用户无法直接读取。这是因为普通用户启动的进程的有效用户 ID 不是 root,所以无法通过文件权限检查。
2 用户和用户组的管理命令详解
2.1 useradd 命令的参数与选项
useradd 是创建新用户的主要命令。直接执行 useradd username 可以快速创建一个基础用户,但生产环境中通常需要指定更多参数。理解 useradd 的各项选项对于创建符合规范的账号至关重要。
-d 选项指定用户主目录路径。默认情况下,系统会在 /home 下创建与用户名同名的目录作为主目录:
# 创建用户并指定主目录
useradd -d /data/webapps/www-data www-data
# 查看创建的用户信息
grep www-data /etc/passwd
-s 选项指定用户的登录 Shell。生产环境中,某些服务账号可能需要设置为 /usr/sbin/nologin 或 /bin/false,防止该账号用于交互式登录:
# 创建不可登录的系统用户
useradd -r -s /usr/sbin/nologin redis
# 创建可登录的普通用户
useradd -m -s /bin/bash deploy
-g 选项指定用户的主组 GID 或组名,-G 选项指定用户的附加组:
# 创建用户并指定主组
useradd -g www-data -G nginx,www-cache www-data
# 同时指定多个附加组
useradd -g developers -G docker,git,sslCerts devops
-c 选项添加用户备注信息,通常用于填写用户全名或职务:
useradd -c "Zhang San - Ops Engineer" -m -s /bin/bash zhangsan
-u 选项手动指定用户 UID。正常情况下应该让系统自动分配,但某些场景下需要手动指定,比如 LDAP 用户映射:
# 创建 UID 为 2000 的用户
useradd -u 2000 -m deploy
-e 选项设置账号过期日期,-f 选项设置密码过期后账号被永久禁用的天数:
# 创建临时账号,30天后过期
useradd -e $(date -d "+30 days" +%Y-%m-%d) -m tempuser
-M 选项不创建主目录,适用于服务账号:
useradd -M -s /usr/sbin/nologin prometheus
-p 选项可以直接设置加密后的密码,但生产环境中更安全的做法是创建用户后再用 passwd 命令设置密码:
# 创建用户
useradd -m -s /bin/bash deploy
# 设置密码
passwd deploy
useradd 命令的默认行为由 /etc/login.defs 和 /etc/default/useradd 文件控制。查看这些配置文件可以了解系统的默认设置:
# 查看 useradd 默认配置
cat /etc/default/useradd
# 查看 login.defs 中的用户配置
grep -E "^CREATE_HOME|^USERGROUPS_ENAB|^UID_MIN|^UID_MAX|^GID_MIN|^GID_MAX" /etc/login.defs
2.2 usermod 命令修改用户属性
对于已有用户,修改其属性需要使用 usermod 命令。该命令的选项与 useradd 基本类似,但增加了锁定、解锁、修改登录 Shell 等功能。
修改用户的附加组是最常见的操作之一。使用 -aG(append to groups)可以在不覆盖现有附加组的情况下添加新组:
# 错误的做法:会覆盖用户所有附加组
usermod -G docker devops
# 正确的做法:追加到现有附加组
usermod -aG docker devops
# 添加多个附加组
usermod -aG docker,git,ssl-cert admin
修改用户主目录需要同时修改 /etc/passwd 中的记录和实际的主目录内容:
# 修改用户主目录
usermod -d /data/new-home -m deploy
# 参数 -m 会自动迁移主目录内容到新位置
锁定和解锁用户账号使用 -L 和 -U 选项:
# 锁定账号(在其密码前添加 !)
usermod -L deploy
# 解锁账号
usermod -U deploy
# 批量锁定过期账号
for user in $(awk -F: '($8!="") {print $1}' /etc/shadow); do
expire_date=$(date -d "$(awk -F: -v u=$user '($1==u) {print $8}' /etc/shadow) days 1970-01-01" +%s 2>/dev/null)
if [ -n "$expire_date" ] && [ $(date +%s) -gt $expire_date ]; then
usermod -L $user
echo"Locked expired user: $user"
fi
done
修改用户的登录 Shell:
# 禁止用户登录
usermod -s /usr/sbin/nologin www-data
# 修改为可登录
usermod -s /bin/bash deploy
2.3 userdel 删除用户
删除用户时如果不加任何选项,主目录和邮件池会保留在系统中,这在清理过期账号时可能造成空间浪费:
# 安全删除:先锁定,确认无误后再删除
usermod -L olduser
# 等待一段时间后确认可以删除
userdel -r olduser
-r 选项会删除用户的主目录和邮件池,是生产环境中推荐的做法:
# 完全删除用户及其主目录
userdel -r deploy
# 如果主目录已被手动删除,可以不加 -r
userdel deploy
在删除用户之前,最好先检查该用户是否有正在运行的进程,以及是否有属于该用户的文件:
# 检查用户进程
ps -u deploy
ps -ef | grep "^deploy"
# 检查用户拥有的文件(跨越多个分区)
find / -user deploy -ls 2>/dev/null
# 检查用户的 crontab 和 at 任务
crontab -u deploy -l
at -l -u deploy
2.4 groupadd、groupmod、groupdel 组管理
用户组的管理命令与用户管理类似。创建组时指定 GID:
# 创建组,自动分配 GID
groupadd developers
# 指定 GID 创建组
groupadd -g 1500 qa
# 创建系统组
groupadd -r system-services
修改组名或 GID 使用 groupmod:
# 修改组名
groupmod -n newgroupname oldgroupname
# 修改 GID(会影响该组所有文件的所有权)
groupmod -g 1600 developers
删除组前需要确保没有用户以该组为主组:
# 检查是否有用户的主组是这个组
grep "qaservers" /etc/passwd
# 删除组
groupdel qaservers
2.5 passwd 和 chpasswd 管理密码
passwd 命令是管理用户密码的主要工具,支持多种密码策略设置:
# 设置用户密码
passwd username
# 查看密码状态
passwd -S username
# 锁定/解锁账号
passwd -l username
passwd -u username
# 设置密码过期
passwd -x 90 username # 90天后过期
passwd -x 0 username # 立即过期
passwd -x -1 username # 永不过期
# 密码警告天数
passwd -w 7 username
# 密码最小存活期(防止频繁改密)
passwd -n 1 username
批量修改密码使用 chpasswd,从标准输入读取 username:password 格式:
# 交互式批量修改
chpasswd
# 或使用 here-string
chpasswd <<EOF
user1:Password123
user2:Password456
EOF
生产环境中应该使用 chpasswd 配合随机密码生成:
# 生成随机密码并批量设置
for user in user1 user2 user3; do
password=$(openssl rand -base64 12)
echo"${user}:${password}" | chpasswd
echo"${user}:${password}" >> /root/tmp_passwords.txt
done
chmod 600 /root/tmp_passwords.txt
3 sudo 的工作原理与配置方法
3.1 sudo 与 su 的本质区别
su(switch user)命令用于切换用户身份,直接创建一个新的 shell 进程并继承当前 shell 的环境变量。使用 su - 会同时加载目标用户的完整环境。使用 su 的最大风险在于它需要知道目标用户的密码——如果运维人员需要临时以 root 身份执行命令,必须知道 root 的密码,这本身就是安全隐患。
sudo 的设计理念完全不同。执行 sudo command 时,系统会检查 /etc/sudoers 配置文件,验证当前用户是否有权限执行该命令。验证方式是通过用户的自身密码(而不是目标用户的密码)确认身份。如果验证通过,sudo 会以目标用户的身份执行命令,执行完毕后返回普通用户身份。
这个设计解决了三个核心问题:不需要共享 root 密码;可以细粒度控制哪些用户可以执行哪些命令;所有 sudo 操作都有完整的审计日志。
验证方式上,sudo 默认使用 PBKDF2 或 Argon2 算法缓存用户密码(通常是 15 分钟),在此期间重复执行 sudo 不需要再次输入密码。这个超时时间可以通过 timestamp_timeout 配置调整。
3.2 /etc/sudoers 配置语法详解
/etc/sudoers 是 sudo 权限配置的核心文件,语法规则必须严格遵守。语法错误可能导致所有用户都无法使用 sudo,严重的可能把自己锁在系统外面。
基本的 sudoers 规则格式为:
who hosts=(runas) commands
hosts:在哪台机器上(通常用 ALL 表示所有机器)
单行配置示例:
# 允许 devops 用户在所有机器上以 root 身份执行所有命令
devops ALL=(root) ALL
# 允许 webadmin 组的所有成员在所有机器上以 root 身份执行 apachectl 和 nginx 命令
%webadmin ALL=(root) /usr/sbin/apachectl, /usr/sbin/nginx
用户组在 sudoers 中使用 % 前缀标识。
3.2.1 主机别名配置
主机别名(Host Alias)用于将多台主机归为一组,便于管理:
# 定义主机别名
Host_Alias WEBSERVERS = web1, web2, web3
Host_Alias DBSERVERS = db1, db2
# 使用主机别名
devops WEBSERVERS=(root) ALL
dba DBSERVERS=(root) ALL
3.2.2 用户别名配置
用户别名(User Alias)将多个用户或用户组归为一组:
# 定义用户别名
User_Alias DEVELOPERS = zhangsan, lisi, wangwu
User_Alias ADMINS = %wheel, %sudo
# 使用用户别名
ADMINS ALL=(root) ALL
3.2.3 命令别名配置
命令别名(Cmnd Alias)将多个命令归为一组:
# 定义命令别名
Cmnd_Alias WEB_CMDS = /usr/sbin/apachectl, /usr/sbin/nginx, /bin/systemctl status nginx, /bin/systemctl status apache
Cmnd_Alias DB_CMDS = /usr/bin/mysql, /usr/bin/mysqldump, /usr/bin/psql, /bin/systemctl status mysqld
Cmnd_Alias SHUTDOWN_CMDS = /usr/sbin/shutdown, /usr/sbin/reboot, /usr/sbin/poweroff
# 使用命令别名
webadmin ALL=(root) WEB_CMDS
dba ALL=(root) DB_CMDS
%wheel ALL=(root) SHUTDOWN_CMDS
3.2.4 运行身份配置
默认情况下,sudo 以 root 身份运行命令,但可以配置为其他用户:
# 允许 www-data 用户以 mysql 用户身份运行 mysqldump
www-data ALL=(mysql) /usr/bin/mysqldump
# 允许 deploy 用户以任意用户身份运行 ruby 和 rake
deploy ALL=(ALL) /usr/bin/ruby, /usr/bin/rake
3.3 生产环境 sudoers 配置最佳实践
3.3.1 最小权限原则
遵循最小权限原则,只授予完成工作所需的最小命令集合:
# 不好:权限过大
devops ALL=(root) ALL
# 好:只允许重启 nginx
devops ALL=(root) /bin/systemctl restart nginx
# 更好:只允许重启 nginx 且不带其他参数
devops ALL=(root) /bin/systemctl restart nginx
3.3.2 限制危险命令
对于可能造成系统级破坏的命令,应该明确限制或禁止:
# 禁止直接修改 /etc/passwd 和 /etc/shadow
%sysadmin ALL=(root) ALL, !/usr/bin/passwd root, !/usr/sbin/userdel
# 更好的做法是分两个规则,允许普通操作但禁止危险操作
%sysadmin ALL=(root) /usr/sbin/useradd, /usr/sbin/usermod, /usr/sbin/userdel
3.3.3 带参数的命令限制
对于带有参数的命令,需要仔细考虑参数的范围:
# 允许以 root 身份重启任何服务
devops ALL=(root) /bin/systemctl restart *
# 允许以 root 身份重启 nginx 和 mysqld
devops ALL=(root) /bin/systemctl restart nginx, /bin/systemctl restart mysqld
# 限制只能重启特定服务
devops ALL=(root) /bin/systemctl restart nginx, /bin/systemctl restart mysqld, /bin/systemctl restart php-fpm
3.3.4 NOPASSWD 选项
NOPASSWD 标签允许用户在不输入密码的情况下执行 sudo 命令,适用于自动化脚本场景,但必须严格限制使用范围:
# 自动化脚本使用(严格限制命令和用户)
automation ALL=(root) NOPASSWD: /usr/local/bin/backup.sh, /usr/local/bin/health_check.sh
# 一般用户不允许使用 NOPASSWD
devops ALL=(root) ALL
3.4 visudo 与配置安全
编辑 /etc/sudoers 必须使用 visudo 命令,该命令会在保存前进行语法检查,如果语法错误会提示并拒绝保存。这是防止把自己锁在系统外面的关键保护机制。
# 编辑 sudoers 配置
visudo
# 指定编辑器
EDITOR=vim visudo
# 检查配置语法(不编辑)
visudo -c
visudo 的默认编辑器是 vi,可以通过 EDITOR 环境变量修改:
# 使用 vim 编辑
EDITOR=vim visudo
# 或者在 /etc/environment 中永久设置
echo"EDITOR=vim" >> /etc/environment
3.5 sudo 日志与审计
sudo 的所有操作都会被记录,默认记录到 /var/log/secure(RHEL/CentOS)或 /var/log/auth.log(Debian/Ubuntu):
# 查看当前用户的 sudo 操作记录
sudo grep "$USER" /var/log/auth.log | tail -20
# 查看所有 sudo 操作
sudo grep "sudo" /var/log/auth.log | tail -50
# 实时监控 sudo 操作
tail -f /var/log/auth.log | grep sudo
启用更详细的 sudo 日志需要在 /etc/sudoers 中添加 Defaults logfile="/var/log/sudo.log":
# 以 root 身份执行
visudo
# 添加以下行
Defaults logfile=/var/log/sudo.log
Defaults log_host, log_year, logfile=/var/log/sudo.log
4 用户权限管理的实战场景
4.1 场景一:创建新服务的运行账号
为新部署的服务创建专用账号是常见的运维任务。以部署 Nginx 为例:
# 创建专用的 www-data 用户(很多发行版已默认创建)
useradd -r -s /usr/sbin/nologin -M -d /nonexistent www-data
# 创建运行目录并设置权限
mkdir -p /var/www/html
chown -R www-data:www-data /var/www/html
# 验证配置
ls -la /var/www/html
id www-data
4.2 场景二:团队成员权限分配
假设有三个运维工程师(zhangsan、lisi、wangwu)和一个开发团队,需要分配不同的权限:
# 创建用户组
groupadd devteam
groupadd opsteam
# 创建用户并加入相应组
useradd -m -s /bin/bash -G devteam zhangsan
useradd -m -s /bin/bash -G devteam lisi
useradd -m -s /bin/bash -G opsteam,devteam, sudo wangwu
# 配置 sudoers(使用 visudo 编辑)
# 开发团队:可以重启 web 服务,查看日志
%devteam ALL=(root) /bin/systemctl restart nginx, /bin/systemctl restart php-fpm, /bin/tail -50 /var/log/nginx/*.log
# 运维团队:可以管理所有服务,查看所有日志
%opsteam ALL=(root) ALL
# 设定密码策略
passwd -x 90 -w 7 zhangsan
passwd -x 90 -w 7 lisi
passwd -x 90 -w 7 wangwu
4.3 场景三:临时权限回收
当员工离职或权限需要回收时:
# 1. 立即锁定账号
usermod -L former_employee
# 2. 检查该用户的进程
ps -u former_employee
ps -ef | grep former_employee
# 3. 终止所有进程
pkill -u former_employee
# 4. 备份并删除主目录
tar -czf /root/backup/former_employee_home.tar.gz /home/former_employee
rm -rf /home/former_employee
# 5. 删除 crontab 和 at 任务
crontab -r -u former_employee
at -r -u former_employee
# 6. 删除用户(最后执行)
userdel -r former_employee
4.4 场景四:批量管理服务账号
在有数十台服务器的环境中,批量管理账号需要使用脚本和配置管理工具:
#!/bin/bash
# 批量创建标准化服务账号
SERVICES="nginx php-fpm mysql postgresql redis elasticsearch"
for svc in$SERVICES; do
if ! id $svc &>/dev/null; then
useradd -r -s /usr/sbin/nologin -M -d /nonexistent $svc
echo"Created user: $svc"
else
echo"User $svc already exists"
fi
done
# 设置密码策略(所有服务账号密码永不过期,但必须锁定登录)
for svc in$SERVICES; do
passwd -l $svc
done
# 验证所有服务账号已锁定
for svc in$SERVICES; do
status=$(passwd -S $svc | awk '{print $2}')
echo"$svc: $status"
done
5 常见权限故障排查与修复
5.1 权限问题的排查思路
权限问题的排查需要遵循系统性方法。第一步是确认问题现象:是某个用户无法执行特定命令,还是无法访问特定文件或目录。第二步是追踪权限链路:从用户到进程到文件,逐层检查权限检查点。第三步是定位最小权限违反点。第四步是修复并验证。
以“用户无法写入 /var/log/app.log”为例:
# 1. 确认问题现象
ls -la /var/log/app.log
# 2. 检查文件权限
# -rw-rw---- 1 appuser appgroup 4096 Apr 17 10:00 /var/log/app.log
# 3. 检查用户是否属于 appgroup
groups appuser
# appuser : appuser secondary_groups
# 4. 如果用户不在 appgroup,添加
usermod -aG appgroup appuser
# 5. 验证(需要重新登录 shell 使组变更生效)
su - appuser -c "groups"
# 6. 或者使用 newgrp 立即生效
newgrp appgroup
5.2 sudo 权限问题的排查
当用户报告无法执行 sudo 命令时:
# 1. 检查 sudoers 配置语法
visudo -c
# 2. 查看用户的实际 sudo 权限
sudo -l -U username
# 3. 检查用户是否在允许的组中
groups username
# 4. 查看 sudo 日志(需要 root 权限)
grep username /var/log/auth.log | grep sudo
# 5. 常见错误信息分析:
# "username is not in the sudoers file" -> 用户未被授权
# "user username: command not allowed" -> 用户无权执行该命令
# "Sorry, user username may not run sudo on this host" -> 主机不匹配
5.3 把自己锁在系统外面的修复方法
配置 sudoers 时最危险的操作是语法错误导致无法保存正确配置。如果已经执行了错误的保存,可以尝试以下方法修复:
方法一:通过单用户模式重置
# 重启系统,在 GRUB 菜单选择内核,按 e 编辑
# 在 linux 行末尾添加 single 或 init=/bin/bash
linux /boot/vmlinuz-... ro single
# 以只读方式挂载根分区,重新挂载为可写
mount -o remount,rw /
# 修复 sudoers
visudo
# 或者直接删除错误的 sudoers(不推荐)
# rm /etc/sudoers
# 重新复制默认版本
# cp /etc/sudoers.pkg /etc/sudoers
方法二:通过物理 console 登录
如果在云环境中,可以先从控制台以 root 身份登录(部分云平台默认提供 root 登录),然后修复 sudoers。
方法三:通过 SSH 关键文件恢复
如果配置了 SSH 公钥登录且当前会话未断开,可以通过 SFTP 上传正确的 sudoers 文件:
# 备选方案:使用 SCP(如果会话还在)
scp correct_sudoers.txt user@remote:/tmp/
ssh user@remote "cp /tmp/correct_sudoers.txt /etc/sudoers"
5.4 文件权限误操作修复
误将关键系统文件权限设置错误会导致系统无法正常工作:
# 常见误操作修复
# 误修改 /usr/bin/sudo 权限(非常危险)
chmod 777 /usr/bin/sudo # 这会导致任何人都可以修改 sudo
# 修复
chmod 4755 /usr/bin/sudo # setuid 位确保以所有者身份运行
# 误修改 /etc/passwd 权限
chmod 777 /etc/passwd # 这会导致安全问题
# 修复
chmod 644 /etc/passwd
# 误修改 /etc/shadow 权限
chmod 777 /etc/shadow # 这会导致密码泄露风险
# 修复
chmod 400 /etc/shadow
# 误修改 /etc/ssh 目录权限(会导致 SSH 无法使用)
chmod 777 /etc/ssh
# 修复
chmod 700 /etc/ssh
chmod 600 /etc/ssh/sshd_config
chmod 644 /etc/ssh/ssh_host_*
5.5 特殊权限位(setuid/setgid/sticky bit)问题
setuid 位允许程序以文件所有者的身份运行,是提权的重要机制。生产环境中应严格控制 setuid 程序:
# 查找所有 setuid 程序
find / -perm -4000 -type f 2>/dev/null
# 查找所有 setgid 程序
find / -perm -2000 -type f 2>/dev/null
# 常见 setuid 程序及其用途
# /usr/bin/passwd - 允许用户修改自己的密码
# /usr/bin/sudo - 允许用户以 root 身份执行命令
# /usr/bin/newgrp - 允许用户切换主组
# /bin/su - 允许用户切换身份
# 如果发现未知的 setuid 程序,需要高度警惕
# 检查文件完整性和来源
rpm -qf /usr/bin/some_suid_program
dpkg -S /usr/bin/some_suid_program
6 用户权限管理的安全加固
6.1 密码策略配置
强密码策略是账号安全的基础。通过 PAM(Pluggable Authentication Modules)可以配置密码复杂度要求:
# Debian/Ubuntu: 编辑 /etc/pam.d/common-password
# RHEL/CentOS: 编辑 /etc/pam.d/system-auth
# 添加密码复杂度要求(pam_pwquality)
password requisite pam_pwquality.so retry=3 minlen=12 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1
# 参数说明:
# minlen=12 - 最小长度12字符
# dcredit=-1 - 至少包含1个数字
# ucredit=-1 - 至少包含1个大写字母
# lcredit=-1 - 至少包含1个小写字母
# ocredit=-1 - 至少包含1个特殊字符
密码历史记录防止重复使用最近使用过的密码:
# 在 PAM 配置中添加
password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok remember=5
6.2 账号锁定策略
配置连续登录失败后的账号锁定策略:
# 编辑 /etc/pam.d/common-auth 或 /etc/pam.d/system-auth
# 添加
auth required pam_faillock.so preauth audit silent deny=5 unlock_time=1800
# deny=5: 连续5次失败后锁定
# unlock_time=1800: 锁定30分钟后自动解锁(秒为单位)
6.3 强制密码过期
定期更换密码降低密码泄露后的风险窗口:
# 查看密码策略
grep "^PASS_MAX_DAYS\|^PASS_MIN_DAYS\|^PASS_WARN_AGE" /etc/login.defs
# 修改默认策略
sed -i 's/^PASS_MAX_DAYS.*/PASS_MAX_DAYS 90/' /etc/login.defs
sed -i 's/^PASS_WARN_DAYS.*/PASS_WARN_DAYS 7/' /etc/login.defs
# 对已有用户应用策略
chage -M 90 -W 7 username
# 批量检查即将过期的账号
awk -F: '($2!="!!") {split($5,a,";"); if(a[1]!="") print $1, a[1]}' /etc/shadow
6.4 限制 root 直接登录
生产环境应该禁止 root 直接登录,强制使用 sudo:
# 编辑 /etc/ssh/sshd_config
PermitRootLogin no
# 同时确保 SSH 使用密钥认证
PasswordAuthentication no
PubkeyAuthentication yes
# 重启 SSH 服务
systemctl restart sshd
6.5 审计账号变更
建立账号变更的审计机制:
# 监控 /etc/passwd、/etc/shadow、/etc/group 的变更
# 方法一:使用 auditd
auditctl -w /etc/passwd -p wa -k passwd_changes
auditctl -w /etc/shadow -p wa -k shadow_changes
auditctl -w /etc/sudoers -p wa -k sudoers_changes
# 查看审计日志
ausearch -k passwd_changes
ausearch -k sudoers_changes
# 方法二:使用 inotifywait
inotifywait -m -e modify,create,delete /etc/passwd /etc/shadow /etc/group /etc/sudoers &
7 最佳实践总结
7.1 日常运维 Checklist
在进行用户权限相关操作时,建议按照以下清单逐项检查:
- 创建新用户前,确认用户类型(系统用户/普通用户)、主组、附加组、Shell 类型
7.2 快速参考命令表
| |
|---|
| useradd -m -s /bin/bash username |
| passwd username |
| usermod -aG groupname username |
| usermod -L username |
| userdel -r username |
| id username |
| visudo |
| sudo -l -U username |
| passwd -S username |
| chage -d 0 username |
7.3 常见错误避免
第一,不要使用 chmod 777 解决权限问题。777 权限意味着任何人都可以读写执行,这是严重的安全漏洞。应该分析具体是哪个用户或组需要什么权限,正确设置。
第二,不要共享账号。每个人都应该拥有独立的用户账号,便于审计和问题追踪。共享 root 账号尤其危险,无法定位操作来源。
第三,不要在 sudoers 中使用 ALL ALL=ALL 除非确实需要。细粒度的命令控制可以限制误操作和恶意操作的损害范围。
第四,不要跳过 sudoers 语法检查。visudo -c 是防止语法错误的最后防线,必须在保存前执行。
结论
Linux 用户权限管理是运维工作的基石。本文系统讲解了用户和用户组的存储机制、useradd/usermod/userdel 等核心命令的用法、sudo 的工作原理和配置语法,以及常见权限故障的排查修复方法。
核心要点回顾:用户信息存储在 /etc/passwd、/etc/shadow、/etc/group 三个配置文件中,理解其字段含义是掌握权限管理的基础;UID 分为系统用户(1-999)和普通用户(1000+),不同 UID 范围有不同的用途;sudo 通过 /etc/sudoers 实现细粒度的权限控制,必须使用 visudo 编辑以避免语法错误;生产环境应遵循最小权限原则,避免共享账号,定期审计权限配置。
权限管理的最终目标是确保正确的人可以访问正确的资源,同时限制误操作和恶意操作的影响范围。掌握本文所述内容后,运维人员应该能够独立处理日常工作中的各类用户权限问题,并为系统安全打下坚实基础。
参考资料:
man useradd、man usermod、man userdelman groupadd、man groupmod、man groupdel/etc/default/useradd 用户创建默认模板