Linux用户管理全攻略:从登录到用户组与sudo提权

发布时间:2026/9/16 19:17:59
Linux用户管理全攻略:从登录到用户组与sudo提权 1. 登录与注销Linux 会话的第一道门1.1 登录的本质从输入用户名到进入 Shell 的完整链路很多人会把“登录 Linux”理解成“输入账号密码然后进入系统”这个理解不算错但作为运维或者开发者我们最好能把登录背后的那条链路看清楚。在传统的 Linux 启动流程中系统初始化完成后会由 init 系统启动一个叫 getty 的程序它负责在终端上显示登录提示符就是那个login:等待用户输入用户名。拿到用户名之后getty 会调用 login 程序login 再提示输入密码。密码验证通过后login 会读取/etc/passwd里对应用户的记录拿到用户的 UID、GID、家目录和默认 Shell然后设置好环境变量切换用户身份最终启动 Shell。到这里你才真正“登录”进去了。这套流程在本地终端、SSH 远程登录、图形界面登录中都有体现只是图形界面把密码验证的环节包在了 greeter 程序里。理解这条链路的好处是当登录出问题时你能判断是哪一环挂了。比如能输用户名但密码一直不对可能不是密码错了而是 PAM 模块的问题或者是账号被锁定了比如登录成功后马上被踢回登录界面那大概率是默认 Shell 配置出问题了。还有一个容易忽略的点登录过程校验的不只是密码还会检查账号是否过期、密码是否过期、家目录是否存在、默认 Shell 是否可执行。家目录被删了或者 Shell 写错路径都能导致登录失败。错误信息有时候只显示 “Login incorrect” 这种非常含糊的提示没有日志根本查不出来。1.2 注销与退出exit、logout 和 CtrlD 有什么区别登录进去之后总会退出来。很多新手搞不清楚exit、logout和按CtrlD到底有什么不一样实际上它们都是退出当前会话但适用场景略有差别。exit退出当前 Shell 进程。在普通用户登录的 Shell 里执行会结束当前会话并返回登录界面。logout只能用于登录 Shell就是通过 login 流程进入的那个 Shell。如果你是在一个子 Shell 或者 su 切换过去的 Shell 里执行 logout 会直接报错“Not login shell”这时只能用 exit。CtrlD等效于输入 exit向当前 Shell 发送 EOF 信号。在 bash 里会根据配置决定是否直接退出默认行为是退出。实际工作里我最常用的还是exit。尤其是 SSH 远程登录退出的时候最好连续 exit 到完全退出否则你以为断开了实际上可能还在某个跳板机的用户下挂着。每次 exit 之前可以用whoami确认一下当前身份避免退错层级。1.3 不同终端登录方式的注意点本地终端TTY登录需要经过完整的 getty login 流程SSH 远程登录则是在 sshd 服务内部完成验证不经过 getty图形界面登录走的是显示管理器。三种方式的验证逻辑大体一致但配置文件不同。比如/etc/securetty这个文件老系统里会限制 root 是否允许从某个终端直接登录。如果你把 root 登录只允许在 tty1~tty6那么通过 SSH 用 root 登录就会直接被拒。很多发行版默认不启用 securetty 限制但如果你在最小化安装的服务器上遇到“root 明明密码正确却无法 SSH 登录”第一个排查项就是PermitRootLogin和Securetty。这一部分没有什么高深的内容但它是理解后续所有用户管理操作的前提。清楚了“什么算登录、什么算退出”再去看 useradd、userdel、su 这些命令时就不会只是死记参数了。登录链路里涉及到的用户身份、家目录、Shell、密码策略正是后面用户管理要操作的对象。2. 用户管理实操添加、查询、删除的完整闭环2.1 添加用户useradd 的基本用法和关键参数Linux 添加用户的核心命令是useradd但不同发行版的默认行为差异很大这是新手最容易踩坑的地方。最简单的用法是useradd zhangsan。在 CentOS/RHEL 系下这会在/home下创建家目录并把/etc/skel下的骨架文件拷贝进去还会为用户设置一个默认 Shell通常是 bash。但在 Ubuntu/Debian 系下直接useradd zhangsan可能不会自动创建家目录Shell 也会是/bin/sh用起来很别扭。之所以有这个差异是因为 Ubuntu 官方把useradd封装了一层adduser普通用户习惯用adduser来添加用户。adduser是交互式的会引导你设置密码、填写用户信息体验友好很多。但useradd才是标准命令跨平台行为一致脚本里必须用它。我建议在正式环境里添加用户时按下面的完整参数来useradd -m -d /home/zhangsan -s /bin/bash -c Zhang San -u 1050 zhangsan各参数含义-m强制创建家目录。-d指定家目录路径。-s指定登录 Shell不指定的话不同系统默认不同最好显式写出来。-c用户备注信息相当于“全名”会在 /etc/passwd 的 GECOS 字段里显示。-u指定 UID。生产环境里为了权限统一建议手动分配 UID避免用户被误删后重建时 UID 变了导致原来归他所有的文件失去归属。还有一个经常一起用的参数是-e用于设置账号过期日期格式是YYYY-MM-DD。比如给实习生开账号直接指定三个月后过期到期自动失效省得人工去清。如果你不光要建用户还要同时建组可以用useradd -m -g devgroup -G docker,jenkins -s /bin/bash zhangsan-g指定用户的主组私有组-G指定附加组多个附加组用逗号隔开。2.2 查询用户信息id、who、w、last、finger 的实战用法查询用户信息是运维日常里用得最多的一类命令很多人只会whoami这远远不够。whoami只输出当前有效用户名简单但信息量太少。我工作中最常用的是id[rootlocalhost ~]# id zhangsan uid1050(zhangsan) gid1051(zhangsan) groups1051(zhangsan),10(wheel),994(docker)这一行输出包含三个关键信息UID、主组 GID、附加组列表。排查权限问题时第一件事就是id 用户名看看用户是否被正确加进了目标组。特别是在配置 sudo 权限或 Docker 权限时用户不在对应组里后面所有操作都会报 Permission denied。查询当前谁在线用whowho root pts/0 2024-01-15 09:22 (192.168.1.100) zhangsan pts/1 2024-01-15 10:05 (192.168.1.101)w比who多了负载信息和当前正在执行的命令w 10:30:12 up 3 days, 2:45, 2 users, load average: 0.05, 0.02, 0.01 USER TTY FROM LOGIN IDLE JCPU PCPU WHAT root pts/0 192.168.1.100 09:22 1:02 0.25s 0.25s -bash zhangsan pts/1 192.168.1.101 10:05 3:00 0.10s 0.03s vim install.loglast用于查看登录历史它读取的是/var/log/wtmp文件last -10 zhangsan pts/1 192.168.1.101 Mon Jan 15 10:05 still logged in root pts/0 192.168.1.100 Mon Jan 15 09:22 still logged in reboot system boot 5.14.0-362.el9 Tue Jan 9 14:20 still running排查“谁在凌晨三点登过我的服务器”或者“服务器什么时候重启过”时last就是第一工具。还有一个finger命令可以查看用户更详细的资料但很多最小化安装的系统默认没有。需要时可以用finger 用户名查看用户全名、家目录、Shell、最后一次登录时间等。不过说实话finger信息的核心内容在id和last里都能看到按需安装即可。2.3 删除用户userdel 与文件清理的隐患删除用户用userdel单纯执行userdel zhangsan只会删除/etc/passwd、/etc/shadow、/etc/group里的记录家目录和邮件目录会残留在系统里。要连家目录一起删除用-ruserdel -r zhangsan但这个命令有个坑它只会删除家目录不会删除该用户在其他目录下创建的文件。比如用户在/data/project下写了一大堆源码你把用户删了这些文件的属主会显示成一串数字 UID时间一长根本不知道归谁管。生产环境里删除用户前一定要确认两件事第一这个用户有没有正在运行的进程pgrep -u zhangsan第二这个用户的所有文件是否需要提前归档或者转移给其他人find / -user zhangsan可以扫描。还有一个细节userdel之后如果你重新创建一个同名但 UID 不同的用户原来未删除的文件就归新用户所有了。这在多人环境里是个安全隐患所以删除用户前扫描文件并处理掉不能偷懒。2.4 修改已有用户usermod 的几个高频场景用户创建之后经常需要调整模块化的命令是usermod。它的参数和 useradd 高度重合作用却不同日常最常用的是这几个场景。第一把用户加入附加组usermod -aG docker zhangsan注意这里有个非常容易踩的坑-G单独使用不带-a会把用户从原有附加组里全部移除只保留你指定的组。所以任何情况下在现有系统上添加组成员都要写成-aG这个-a千万别手滑漏掉。我见过不止一次因为漏写-a导致用户突然没有 sudo 权限的故障。第二锁定和解锁账号。员工离职但可能还要审计遗留数据时可以用usermod -L zhangsan锁住密码让用户无法登录但保留账号和文件。usermod -U是解锁。第三修改账号过期时间usermod -e 2024-06-30 zhangsan。第四修改用户默认 Shellusermod -s /sbin/nologin zhangsan。把用户的 Shell 改成/sbin/nologin是运维里禁用远程登录的标准做法。用户保留账号还能接收邮件但无法通过 SSH 登录。比起直接删用户这种方式更温和适合“暂时还没想好到底怎么处理”的场景。3. 切换用户su 与 sudo 的正确打开方式3.1 su 的用法为什么那个“-”符号这么重要讲切换用户之前先说一个真实经历。前几年带新人对方要切到 root 去改配置输入su之后发现 PATH 变量跟普通用户一模一样连service命令都找不到整个人懵了。原因很简单他敲的是su而不是su -。su和su -的区别在于su只切换用户身份保留当前 Shell 的环境变量PATH、HOME 等都不变。su -完整切换到目标用户的环境重新读取目标用户的配置文件.bash_profile、.bashrc 等相当于重新登录了一次。实际使用中绝大多数场景都应该用su -。否则你切到 root 后PATH 里没有/sbin和/usr/sbin很多管理命令会提示找不到HOME 也还是原来用户的目录容易把文件写到别人的家目录里。连切换普通用户也一样比如从 root 切到部署用户su - deployuser加上-才能拿到 deployuser 的 Python 虚拟环境、Java 环境变量等。3.2 sudo 的配置逻辑与临时提权生产环境里不建议大家都记住 root 密码然后su -切过去因为 root 密码在多人之间传播是个巨大的安全风险。正确做法是用sudo。sudo的核心配置文件是/etc/sudoers修改它一定要用visudo命令visudo为什么不能用 vim 直接改因为 visudo 在保存的时候会检查语法如果语法错误会拒绝保存并提示你修复。直接 vim 改一旦写错sudo 就全盘坏掉修复起来很麻烦。最简单的授权方式是让用户加入wheel组CentOS/RHEL 系或者sudo组Ubuntu/Debian 系usermod -aG wheel zhangsan然后/etc/sudoers里确认有类似这一行%wheel ALL(ALL) ALL这行的含义是wheel 组里的成员可以在所有主机上以所有用户身份执行所有命令。如果你只想给用户授权一两条命令可以这样写zhangsan ALL(root) /usr/bin/systemctl restart nginx这就意味着 zhangsan 只能通过 sudo 执行重启 nginx 的命令其他任何命令都无权执行。这在“给开发开生产环境权限”的诉求里很实用。sudo还支持免密zhangsan ALL(ALL) NOPASSWD: ALL但要谨慎使用。免密 sudo 等于持有该用户密码的人可以直接提权到 root安全评审一般不会通过。3.3 切换用户时的常见坑第一个坑是文章前面说的su丢了-导致环境变量不对。第二个坑是 sudo 执行带重定向的命令报 Permission denied。比如sudo echo options /etc/nginx/conf.d/test.conf你会看到 Permission denied原因很经典sudo只作用于echo重定向是当前 Shell 自己做的当前用户对/etc/nginx/conf.d/没有写权限所以被拒。正确写法是echo options | sudo tee /etc/nginx/conf.d/test.conf第三个坑是切换用户后习惯不清。在 root 下切到普通用户后还得确认当前目录是不是普通用户可以访问的。如果还待在 root 的家目录普通用户根本进不去停留在那里执行任何写操作都会报错。切过去之后第一时间cd ~回到目标用户家目录这是好习惯。第四个坑是忘记退出。多人共用一台服务器时root 在某个终端里su -到其他用户干完活直接关终端其实另一个用户的会话还挂在后台。可以用exit逐层退出或者用loginctl查看当前登录会话。4. 组的概念所有者、所在组和其他组4.1 为什么需要组权限三元组与身份归属聊组之前先想一个问题为什么 Linux 不能直接基于用户分配权限非要再引入组原因很简单文件数量多、用户数量多一对一管理根本管不过来。组的作用就是给用户分类然后基于分类授权。Linux 的权限模型里每个文件有三组权限位分别对应三类身份所有者user文件属于谁。所在组group文件属于哪个组组内的其他成员对这个文件拥有组权限位的权限。其他组others既不是所有者也不属于文件所在组的用户。每个身份各自有读r4、写w2、执行x1三个权限位放在一起就是rwxr-xr-x这种经典的十位权限串。第一位的-代表普通文件d代表目录l代表软链接后面每三位一组分别对应所有者、所在组、其他组。举一个现实中的例子项目组有 A、B、C 三个成员他们都需要读写/data/project目录同时不能让外面的测试组成员进来。最合适的做法是建一个project组把 A、B、C 都加进去然后把/data/project的组所有权改成 project目录权限设成770所有者全权组全权其他无权限。如果不用组你得让系统管理员手工为三个用户分别设置 ACL 或反复调整文件所有权成本成倍上升。4.2 查看组信息groups、id、getent 的组合用法查询一个用户属于哪些组最直接的是groups zhangsan zhangsan : zhangsan wheel dockergroups输出里的第一个组是主组后面的是附加组。更严谨一点可以用idid zhangsan uid1050(zhangsan) gid1051(zhangsan) groups1051(zhangsan),10(wheel),994(docker)这里能看到主组 GID 是 1051附加组是 wheel 和 docker。如果要查看系统里有哪些组直接看/etc/group文件cat /etc/group | head -10 root:x:0: bin:x:1: daemon:x:2: sys:x:3: adm:x:4: tty:x:5: disk:x:6: lp:x:7: mem:x:8: kmem:x:9:每一行的格式是组名:密码占位符:GID:组成员列表。组密码基本用不上看到x占位就行。有些系统里用户数量多翻/etc/group不方便可以用getent group docker docker:x:994:zhangsan,wangwugetent的好处是它会同时查询本地文件和 NSS 配置的其他数据库LDAP 等在统一认证环境里比直接读文件更可靠。4.3 组的创建与管理groupadd、groupmod、groupdel创建组用groupaddgroupadd -g 2000 devgroup-g手动指定 GID避免系统自动分配时和已有组冲突。如果只是随手建组不带参数也行。管理组信息用groupmod比如修改 GIDgroupmod -g 2001 devgroup修改组名groupmod -n devteam devgroup删除组用groupdelgroupdel devteam但注意如果某个用户的私有组就是这个组那么组不能被删除系统会提示 “cannot remove the primary group of user xxx”。这时要么先处理用户要么把用户的gid改成其他组。一个比较重要的细节删除组不会自动修改属于该组的文件。文件依然显示原来的 GID 数字只是ls -l里不再能解析出组名显示为一个裸数字。这种孤儿文件在后期维护时会很头疼所以删组之前同样建议先扫描文件归属。4.4 把用户加进组gpasswd 与 usermod -aG 的取舍把用户加入组有两种常用方式。第一种是前面提过的usermod -aGusermod -aG devteam zhangsan第二种是gpasswd -agpasswd -a zhangsan devteam从操作效果看两者都把 zhangsan 加进了 devteam 组没有本质区别。从日常使用习惯来说我更喜欢gpasswd因为它天然不会覆盖用户已有的附加组——它只做“追加”这一个动作不存在像 usermod 漏写-a那样的风险。但 usermod 可以同时处理多个组脚本里有时更灵活usermod -aG devteam,docker,jenkins zhangsan把用户移出组用gpasswd -dgpasswd -d zhangsan devteam有一点必须提醒用户登录状态下的组权限不会立即生效。用户已经登录你在另一个终端把它加进 docker 组他当前 shell 里敲 docker 命令依然会报权限拒绝必须退出重新登录或者执行newgrp docker再输一次密码。这条规则我在带团队时反复强调了不止十次仍然会有人踩。5. 基础操作串起来一个 5 分钟的多用户环境搭建实战理论知识说完了下面完整演示一遍我日常搭建一个多用户环境的操作过程希望能起到“抄作业”的作用。5.1 场景目标假设需求是新项目组三位成员 joe、sam、lucy 需要共同读写/data/project目录三位都可以通过 sudo 执行系统服务管理命令其他用户一律无权访问项目目录。5.2 操作步骤与命令第一步创建用户自动创建用户私有组useradd -m -s /bin/bash -c Joe joe useradd -m -s /bin/bash -c Sam sam useradd -m -s /bin/bash -c Lucy lucy第二步设置初始密码passwd joe passwd sam passwd lucy第三步创建项目组并把用户加进去groupadd project gpasswd -a joe project gpasswd -a sam project gpasswd -a lucy project第四步创建项目目录并设置归属和权限mkdir -p /data/project chown root:project /data/project chmod 770 /data/project770的含义是所有者root有所有权限所在组project有所有权限其他人无任何权限。三位同事在 project 组内可以正常读写目录系统里其他用户连进入目录的权限都没有。第五步配置 sudo 授权。用 visudo 编辑添加一行%project ALL(root) /usr/bin/systemctl这行代码让 project 组的三位成员可以通过 sudo 执行所有 systemctl 命令。第六步验证结果id joe # uid1050(joe) gid1051(joe) groups1051(joe),1054(project) sudo -l -U joe # User joe may run the following commands on this host: # (root) /usr/bin/systemctl5.3 实际执行中需要注意的事项上面的步骤里面有三点值得展开说一下。第一chown root:project中如果只写chown :project /data/project就是只改组所有权不修改属主。这两种写法都可以但显式写root:project更清楚避免看命令的人不知道所有者是谁。第二为什么目录权限用770而不是775因为项目目录通常不希望被其他人浏览源代码770卡死了“其他组”的访问入口是更安全的选择。第三如果用户之前已经登录加组之后需要退出重新登录才能生效。因此上面的操作最好安排在用户还没登录的时段进行或者做完后要求对方重新连接一次。6. 常见问题速查与排查思路6.1 Identity 查询与验证类问题一个很简单但很常见的问题我明明把用户加进 docker 组了为什么他还是不能执行 docker 命令排查思路无非三步执行id 用户名看输出里到底有没有 docker 组。如果输出里有 docker 组确认用户是否在加组前就登录了让他重新登录。如果重新登录后还不行检查 docker 的 socket 权限是否被改过ls -l /var/run/docker.sock确认权限是否还正常。还有一种更隐晦的情况用户通过 SSH 登录后又用su切换过身份id显示的信息可能是旧会话里的缓存。这时用newgrp docker强制切换组身份或者干脆重启一次 SSH 会话问题通常能解决。6.2 用户删除与文件归属类问题删错了用户或者删错之后文件没人认领这种事很多运维都经历过。常见场景是离职员工的账号被删了但他的项目文件还留在共享目录里属主显示为数字 UID。处理这类问题没有什么特效药唯一的办法是前期预防。我的习惯是删除用户前先跑一遍find / -xdev -user zhangsan -type f | wc -l find / -xdev -user zhangsan -type d | wc -l先统计文件数量再列出具体路径确认没有需要保留的内容后才执行userdel -r。如果已经删了用户文件成了孤儿可以手动把文件转给当前用户find /data -uid 1050 -exec chown root:root {} \;这条命令会扫描/data下所有属主 UID 为 1050 的文件逐一改成 root 所有。6.3 sudo 提权相关报错合集报错信息常见原因解决方法user is not in the sudoers file用户不在任何 sudo 授权组里用 root 执行usermod -aG wheel 用户名后重新登录sudo: no tty present非交互环境执行 sudo 且没有分配终端脚本里改用sudo -n避免卡住或者在 sudoers 配置里按需放行sudo: effective uid is not 0sudo 二进制本身权限被改坏用 root 修复/usr/bin/sudo权限为4755/etc/sudoers is world writablesudoers 文件权限错误以 root 执行chmod 440 /etc/sudoers然后用 visudo 检查语法sudo: effective uid is not 0这个报错很多人一辈子遇不到但只要遇到基本就是有人改坏了 sudo 的 setuid 位。处理的前提是你还有 root 通道如果没有只能进单用户模式修复。6.4 文件权限中组权限不生效的另类场景这类问题最容易出现在 ACMLACL和传统权限混用的环境里。有时你用chmod设置好了组权限但用户仍然读写失败。我在实际环境中排查到的最常见原因是文件所在目录没有给用户所在的组授予可进入的执行权限x。举个例子你把文件/data/project/readme.txt的组权限设成了rw但/data/project目录的权限是700其他组的用户根本进不了目录自然拿不到文件的读权限。所以当“文件权限看着没问题但访问失败”时先检查路径上每一级目录的权限。Linux 权限的坑很多都是叠加出来的。单独看某个文件权限是对的但往上每一层目录都在拦截最后组合出来就是“无权限”。排查这种问题有一个土办法用namei -l /data/project/readme.txt一次看全路径上每一层的权限。这个命令在排查“路径可达性”问题上非常好用强烈建议记下来。上述内容来自我真实操作中的积累。如果这篇笔记能帮助你少踩几个坑那它的价值就实现了。后续如果时间允许我还会再写一篇关于文件权限深入讲解的内容比如 setuid、setgid、sticky bit 这些特殊权限位的使用场景欢迎继续关注。