ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Linux用户管理完全指南:从UID映射到账号生命周期与安全审计

2026/9/14 15:54:49 拓冰建站 浏览量
Linux用户管理完全指南:从UID映射到账号生命周期与安全审计 干了好几年Linux运维我有一个很强烈的体会用户管理是绝大多数Linux管理员都会但很少有人真正重视的一环。很多人一提到用户管理脑子里就蹦出三五个命令——useradd建个用户passwd改下密码删的时候来个userdel -r收尾。这套流程在小机器上确实能跑但一旦到了多用户的生产服务器上坑就一个接一个地冒出来。前阵子帮同事排查一台服务器发现项目目录里一堆文件归属变成了数字“1005”查了半天才发现是上个管理员删用户的时候没处理干净新用户又把那个UID给顶上了。这种擦屁股的活干一次就够难受的。所以这篇想把Linux用户管理从头到尾掰开揉碎讲一遍。不单是命令怎么敲更重要的是弄清楚系统底层是怎么对待用户的、账号的完整生命周期应该怎么管理、删账号怎么才能不留后患顺带会分享一些日常维护中容易被忽略的安全习惯。无论你是刚接触Linux的新手还是在生产环境摸爬滚打过的运维这篇应该都能给你一些可以直接上手用的东西。1. 用户名的本质一个数字引发的管理难题1.1 内核只认UID用户名只是给人类看的翻译层很多人第一次看到ls -l输出的时候都盯着那个文件属主owner看半天这到底是个什么神仙用户怎么一会儿显示root一会儿显示数字答案其实很朴素——Linux内核完全不认识root、zhangsan这种名字它处理进程、文件权限的时候用的全都是整数ID也就是UID用户ID和GID组ID。用户名是给人类看的翻译层内核拿到root这个名字要先去查表换算成0然后才能真正判断“这个进程有没有权限打开那个文件”。拿最简单的场景举例你的项目目录里有个文件属主显示成了一个光秃秃的数字比如1005翻遍/etc/passwd也找不到这个用户。这种情况十有八九是文件原来的主人被删掉了但文件还在。系统不会因为属主没了就自动把文件删掉它只知道“这个文件归UID 1005管”至于这个UID现在有没有对应的用户名它根本不关心。如果你想让内核视角现原形一条命令就能做到ls -ln /some/file-n参数的作用就是“显示数字身份而不是用户名”。看到真实的UID以后很多权限问题就清晰了你不一定能直接get到www-data是谁但看到33这个数字你就知道这是Web服务在用的账号很多发行版里www-data固定占着UID 33这个坑。1.2/etc/passwd一张所有人都能读的“员工花名册”用户名到UID的映射关系全部写在/etc/passwd这个文件里。格式是每一行一个用户字段用冒号分隔一共7段字段示例含义用户名root登录名用于给人看密码占位符x真正的密码哈希不在这里这里只是占位UID0用户ID内核实际识别用的GID0初始组ID用户创建文件时的默认组注释信息root一般写用户全名或用途可以随便填家目录/root用户登录后的起始目录登录Shell/bin/bash用户登录后执行的Shell程序这个文件有个非常重要的特点它是所有用户都可读的权限通常是644。因为很多程序都需要通过用户名查UID、查家目录但这些信息不涉及密码哈希所以不怕被窥探。可一旦你在这个文件里看到密码字段不是x而是一长串密文那就说明系统配置有严重问题——这个文件不该承载密码哈希。顺便说一句很多新手会忍不住用一个叫什么编辑器直接改这个文件。我的建议是正经做法用vipw命令它会帮你加锁防止两个管理员同时编辑把文件搞坏。改完它还会提示你同步更新/etc/shadow。1.3/etc/shadow把密码单独锁进保险柜既然/etc/passwd任何人都能读那密码哈希再放里面就是自掘坟墓。过去老Unix系统确实把加密后的密码放在passwd文件里后来发现暴力破解太容易才拆出了/etc/shadow这个新文件把密码哈希和账户有效期信息单独放进去权限收紧为root可读通常是000或640。一行shadow记录长这样root:$6$9h3nF2kd$eU4bQ...:18765:0:99999:7:0:1::字段倒也不算复杂位置含义第1段用户名第2段加密后的密码哈希开头$6$表示SHA-512算法$y$是yescrypt第3段最近一次改密码的日期从1970年1月1日起算的天数第4段两次修改密码之间的最小间隔天数第5段密码有效期最大天数第6段密码过期前多少天提醒用户第7段密码过期后宽限天数第8段账号失效日期第9段保留字段如果密码字段是!或*表示这个账号被锁定了无法用密码登录。这也是许多管理员判断“这个用户到底还能不能登”的主要依据。日常排查的时候看到!就不要去纠结他密码是不是忘了——他就是被锁的账户。chage -l 用户名可以查看某用户完整的密码有效期信息比肉眼看shadow文件直观得多。1.4 组也是一个数字GID与主组、附加组的区别用户管理的另一个大块是组group对应的映射文件是/etc/group。组的作用是把一群用户归拢到一起然后通过组权限统一控制文件访问。比如项目目录设置成drwxrwx---属组是webdev组那组里的成员就都能读写省得一个个给用户授权。每个用户都有一个主组primary group创建文件时文件默认的组就是它。一个用户还可以同时加入若干个附加组supplementary groups获得这些组的访问权限。id 用户名命令会把这两类组都列出来$ id zhangsan uid1050(zhangsan) gid1050(zhangsan) groups1050(zhangsan),4(adm),27(sudo),999(docker)gid后面跟的是主组groups后面那些是附加组。这里有个容易绕晕的概念主组不一定只有一个但对用户来说它就只有一个“初始组”。而附加组可以有多个用于给用户叠加额外权限。比如把开发者加进docker组他就有了调用Docker的权限不用往sudoers里塞人就解决了工具授权问题。2. 新建用户的完整操作与权限规划2.1useradd背后的默认值机制新手建用户习惯于useradd zhangsan一把梭但这样建出来的用户往往不带家目录登录Shell也可能不是bash密码当然是空的属于“半成品”账号。这背后的原因是useradd的所有默认值都由/etc/default/useradd和/etc/login.defs两个文件控制。比如/etc/login.defs里有一组常用配置直接决定新用户的形态配置项含义常见默认值UID_MIN/UID_MAX普通用户UID范围1000~60000CREATE_HOME是否默认创建家目录yes或no取决于发行版USERGROUPS_ENAB是否自动创建同名用户组yesUMASK新文件的默认权限掩码022即文件644、目录755所以有些发行版比如Debian系默认建用户是带家目录和同名组的而有些精简系统可能什么都不建。我的建议是不要依赖发行版默认行为创建用户的时候把关键参数显式写出来这样不管换到什么环境行为都一致。2.2 生产级创建用户五步走我现在创建用户基本按照一套固定流程来每一步都有明确目的。假设要给新同事小张建一个开发账号需要加入docker组和webdev组且禁用SSH密码登录只允许密钥第一步创建用户。显式指定家目录、Shell、UID并加入需要的附加组。sudo useradd -m -d /home/zhangsan -s /bin/bash -U -u 1050 -G docker,webdev zhangsan参数拆解-m如果家目录不存在就自动创建并把/etc/skel里的骨架文件复制进去。-d指定家目录路径。默认会在/home下用用户名做目录但显式写出来更稳妥。-s指定登录Shell。不改的话有些系统默认是/bin/sh操作体验和bash差很多。-U创建同名用户组并把该组设为主组。-u 1050手动指定UID。自己固定UID范围方便后续用数字识别也避免和系统已有用户冲突。-G附加组列表多个组用英文逗号分隔。第二步设置初始密码并强制首次登录修改。sudo passwd zhangsan sudo chage -d 0 zhangsanchage -d 0这行很多人会漏掉。它的作用是把“上次修改密码日期”归零这样用户一登录就会被强制要求修改密码。新账号发出去的时候初始密码是管理员设置的临时密码不强制改的话小张可能半年都不换一次等于这个密码一直处于半公开状态。第三步写入SSH公钥关闭密码登录。sudo mkdir -p /home/zhangsan/.ssh sudo tee /home/zhangsan/.ssh/authorized_keys EOF ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... EOF sudo chown -R zhangsan:zhangsan /home/zhangsan/.ssh sudo chmod 700 /home/zhangsan/.ssh sudo chmod 600 /home/zhangsan/.ssh/authorized_keys生产环境里密码登录能关就关。有了公钥再配合sshd_config里禁用PasswordAuthentication密码泄露面就少了一大块。这里顺带提醒一句公钥文件的权限如果太宽松比如644sshd会直接拒绝使用这个文件因为任何人都能往里加自己的公钥那还怎么保证安全。第四步验证账号状态。getent passwd zhangsan id zhangsan sudo -l -U zhangsangetent比直接grep /etc/passwd更好用因为它会同时查NSS名字服务开关配置里的所有数据源不光是本地文件。如果以后接入了LDAP或者AD域这套验证方式依然有效。第五步告知用户初始信息。把账号名、初始密码需要单独走安全通道发、服务器地址、登录方式密钥验证一起整理好发给对方同时提醒他第一次登录必须改密码。2.3 骨架目录/etc/skel的价值创建用户的时候-m参数会把/etc/skel目录下的所有文件复制到用户的家目录。默认情况下这个目录一般只放.bashrc、.profile这些基础配置但我们完全可以利用它来统一新用户的环境。比如公司统一用vim可以在/etc/skel/.vimrc里写上一段常用配置新用户一登录就自动拥有这些设定不用每个人手动配一遍。再比如想给新用户一个欢迎信息可以在/etc/skel/.bashrc末尾加几行echo。这里有个细节要注意/etc/skel只对“之后创建”的用户生效已经存在的用户不会被更新。如果想批量把骨架文件推给老用户可以写个脚本手动复制但复制前最好确认不要覆盖用户自己改过的配置。比起直接覆盖更稳妥的做法是只复制那些用户没有的自定义文件。2.4 组策略什么时候建新组什么时候搭上已有组很多新手建组很随意今天想到一个项目就建一个组过两天项目黄了组也不清理到最后/etc/group里一堆僵尸组。我的原则很简单组跟着角色走不跟着个人走。比如你有一台服务器专门跑Web项目那固定组就应该是webdev所有需要开发这台机器的人都被加进这个组。项目临时扩编不要急着为某个一次性需求新建组先看看能否复用已有组。只有当你发现某个权限集合长期存在、多次出现时才考虑单独建组。另外用户的主组默认是它的同名组这本身不是坏事。但如果你的业务特点是多个用户共享同一个数据目录那就需要考虑把他们的主组统一改成项目组模式。比如四个前端都归frontend这个大组管直接给它们设置主组为frontend新文件创建出来默认就是组内可写大家协作会很舒服。唯一要留神的是修改主组后新文件的默认属主依赖umask需要配合setgid目录等方式来保证组写权限这个后面会讲到。3. sudo 和 su给临时管理员发“有限通行证”的正确姿势3.1 su 与 sudo 的本质区别先厘清两个概念。su是“切换用户”你输入su - root整个Shell会变成root的Shell所有后续命令都以root身份执行。关键点是它需要输入的是目标用户的密码。也就是说想让某人有root权限就得把root密码交给他一旦给出去root密码就满天飞了而且谁什么时候用root干了什么你完全没日志可查。sudo的思路不一样它是“以某个用户身份执行单条命令”。用法是sudo cat /etc/shadow执行完这一条命令就结束了当前Shell还是普通用户身份。它验证的是当前用户自己的密码不需要暴露root密码。另外sudo的每次授权行为都会记录到日志里出事了能回溯。所以就管理安全性而言sudo远胜su。我的建议是生产服务器上root密码尽量只有机房带外管理口或极少数核心管理员知道日常运维全部走sudo。3.2 用 visudo 管理授权规则的细节sudo的授权规则写在/etc/sudoers文件里。这个文件语法很讲究写错了轻则sudo不可用重则可能把整个管理通道锁死。所以Linux专门提供了visudo命令来编辑它保存时会自动做语法检查。如果你非要手动改改完一定要跑一下visudo -c做校验。先看一行典型规则zhangsan ALL(ALL) NOPASSWD: /usr/bin/systemctl逐段拆解zhangsan被授权的用户名也可以用%组名来针对整个组。ALL允许在哪台主机上执行单机场景直接填ALL。(ALL)可以以哪个用户的身份执行(ALL)表示可以切换到任意用户。NOPASSWD:执行sudo时免密码。/usr/bin/systemctl允许执行的命令路径。我见过很多人把NOPASSWD用得很泛滥搞得所有sudo操作都免密security几乎等于零。更合理的做法是把“日常高频、低风险”的命令设为免密比如服务启停把“高风险、低频率”的操作保留密码确认比如编辑sshd配置。还有一个容易被忽略的好习惯把自己的自定义规则放到/etc/sudoers.d/目录下一个独立文件里而不是直接堆在/etc/sudoers里。echo zhangsan ALL(ALL) NOPASSWD: /usr/bin/systemctl | sudo tee /etc/sudoers.d/zhangsan这样每个用户或每个项目组的规则互相隔离。至于原因很简单有一次我收到一台交接的服务器所有人都在往/etc/sudoers里加行里面既有老同事留下的deploy账号还有临时借调的实习生账号根本分不清谁是谁。拆分成独立文件后一个账号一个文件删的时候直接删对应文件干净利落。3.3 setuid、setgid 与 sticky bit目录和文件上的隐藏权限位和sudo不同文件系统里还有一套更底层的提权机制就是setuid和setgid位。它们和用户管理的关系极其密切。setuid位用一个s代替x出现在文件属主的执行位上比如rwsr-xr-x。当一个可执行文件带setuid位时普通用户执行它进程会临时获得该文件属主的身份。最经典的就是/usr/bin/passwd$ ls -l /usr/bin/passwd -rwsr-xr-x 1 root root 68208 May 28 2024 /usr/bin/passwd为什么要这么设计因为普通用户要改自己的密码需要写/etc/shadow而shadow文件只有root能写。如果passwd命令没有setuid位普通用户根本改不了密码。所以在可控范围内setuid是必要的。但它也是最常见的提权漏洞点。如果一个root拥有的可执行文件被加了setuid位而它本身又有漏洞普通用户就可能通过它来提权到root。所以定期扫描系统里所有setuid文件是个好习惯sudo find / -perm -4000 -type f 2/dev/nullsetgid位发生在目录上的时候效果是“新创建的文件自动继承目录的属组而不是创建者的主组”。这是多用户协作中非常好用的工具。比如/data/project目录属组设为webdev再设置setgid位无论谁在里面建文件文件属组都会自动变成webdev项目成员就能顺畅地共同读写。sticky bit则主要用在/tmp这类共享目录上加了t位的目录里除了root只有文件自己的属主才能删文件别人就算对这个目录有写权限也删不动别人的文件。这三个隐藏权限位是你理解Linux多用户协作绕不开的底层知识点。4. 删除与清理账号最容易出事的一个环节4.1userdel的局限删账号是最容易被低估风险的操作。很多人以为userdel zhangsan一下就把用户删干净了其实它做的事非常有限——只是把/etc/passwd、/etc/shadow、/etc/group里对应的记录移除。用户的家目录、邮箱文件、crontab任务、以及用户拥有的其他文件统统原地不动。带-r参数会顺手删掉家目录和mail spool但依然不会清理用户在其他地方留下的文件。如果这个用户曾经管理过项目的某个目录删完以后这个目录里所有文件的属主就变成数字UID了。用ls -l看是这样-rw-r--r-- 1 1050 1050 2048 Jul 12 10:22 config.yaml过两天有个新用户建出来系统分配UID正好是1050那这个新用户就莫名“继承”了这些文件的操作权。在多人共享的服务器上这是很严重的数据泄露隐患。真要避免这种情况就不能只靠一个userdel解决。4.2 一个安全的删除流程应该长什么样我的建议是把删除当项目来做至少走下面六步第一步锁定账号防止继续登录。sudo usermod -L zhangsan sudo chage -E 0 zhangsanusermod -L会给shadow里的密码哈希前面加!立即阻止密码登录。chage -E 0把账号过期日期设为0双保险。注意这步只影响新的登录尝试不会踢掉已经登录的会话。第二步终结该用户的残留进程。sudo pkill -u zhangsan # 或者强制杀 sudo pkill -KILL -u zhangsan一般建议先发TERM信号让进程优雅退出等几秒再KILL。如果你不确定有没有漏网之鱼可以复查ps -u zhangsan第三步找出用户所有的文件。sudo find / -user zhangsan 2/dev/null这条命令会在整个文件系统里找出所有属主是该用户的文件。输出可能很长别急着看完就下结论。资料备完、代码提交完、日志归档完再决定哪些需要保留保留的就移交给别人sudo chown -R otheruser:othergroup /data/important/zhangsan/第四步清理定时任务和相关服务。用户自己的crontab用ls /var/spool/cron/看看有没有对应文件有就删掉或转移。现在的systemd系统里用户还可能有自己的systemd用户单元在~/.config/systemd/user/目录这也要一并处理。第五步删除用户及相关文件。sudo userdel -r zhangsan这里的-r会删家目录和mail spool。如果前面你已经手动移走过重要数据这一步就不会丢东西。第六步验证清理结果。getent passwd zhangsan find / -name *zhangsan* 2/dev/null重点确认两件事/etc/passwd里没有该用户了家目录和其他明显归属文件都不在了。4.3 UID复用带来的权限残留接着前面提到的数字归属问题继续讲。最稳妥的办法其实是删完用户不要急着释放UID。如果短时间内不打算把同一个UID分配给新用户你可以暂时让那些残留文件保持数字属主状态。虽然看着不优雅但至少不会出现“新用户自动继承旧用户文件”的乌龙。如果你希望新用户明确接管某些目录就要用chown -R显式把文件归属改过去而不要指望系统自动处理。在UID复用这个问题上系统不会管你是不是同一个“人”它只认数字。4.4 锁账号与删账号怎么选很多场景下锁账号比删账号划算得多。比如同事离职了但短期内可能需要审计他的历史操作或者某个服务账号暂时不用了但配置里还在引用它。这时候推荐的做法是用usermod -L锁密码用usermod -s /usr/sbin/nologin或/bin/false把登录Shell换成不可交互的用chage -E 0设账号过期。这样账号还在系统里文件属主信息不会变成一串数字配置也不用改但任何直接登录行为都会被挡在外面。等确认可以彻底清除了再按前面的6步流程走。5. 账号安全底线与审计习惯5.1 检查系统里是否存在异常账户安全审计这件事平时不做没事做一次能发现一堆陈年旧账。我每次接手一台服务器第一件事就是看用户列表# 查看所有普通用户 awk -F: $31000 /etc/passwd这条命令把UID在1000以上的普通用户全列出来。看完之后问自己几个问题这些人都是谁还有联系方式的用户有几个有没有离职半年了账号还活着的有没有UID是0的非root账户检查UID为0的账户要特别在意。UID为0意味着超级用户权限如果除了root之外还有一个账户也是0那基本可以断定是有人故意留后门awk -F: $30{print $1} /etc/passwd正常的输出应该只有root一行多出来的都有嫌疑。5.2 审计登录记录和sudo日志每天花两分钟看看登录日志比装一堆复杂的安全软件有效得多。几个实用命令# 查看最近成功登录记录 last # 查看最近失败登录记录 lastb # 当前在线用户 who失败登录记录lastb特别值得看。如果发现同一个IP在短时间内尝试几百上千次说明服务器正被扫描或暴力破解。另外sudo的日志一般会进入/var/log/auth.logDebian系或/var/log/secureRHEL系想看谁用了管理员权限直接搜sudo就能找到sudo grep sudo: /var/log/auth.log | tail -20也可以借助journalctl统一查询journalctl -u ssh --since 7 days ago | grep Failed password | wc -l平时不必盯着每一条日志看但养成每周刷一次的习惯很多问题能在周报里发现端倪。5.3 文件层面的一致性检查最后提一个容易被忽略的命令pwck和grpck。这两个命令会遍历/etc/passwd与/etc/group文件检查字段格式是否正确、家目录是否存在、用户主组是否有对应记录。如果文件被误编辑出问题这两个命令会直接报错。比如系统里某个用户的家目录被误删了但/etc/passwd里的记录还在pwck会提示“目录不存在”。这时候要么重建家目录要么删除该用户避免用户登录后跑到一个不存在的路径里。再比如有些用户主组指向的组记录不存在grpck也会报警。这类问题平时不显眼但一旦触发用户可能突然发现自己无法创建文件、无法访问目录排查起来很费劲。定期跑一遍这两个命令属于成本极低、收益很高的维护习惯。另外还有一点别把太多的服务跑在root账号下。我见过很多业务进程图省事启动脚本里写死用root跑导致一个配置错误就能让整个系统暴露在风险中。正确的姿势是给每个服务建独立账号比如nginx跑nginx、postgres跑PostgreSQL、app-runner跑业务应用。就算某个服务被攻破攻击者能拿到的也只是这个服务的有限权限而不是整个系统的root。这也是用户管理在应用层最重要的价值。我在实际维护中最深的体会是真正把用户管理做好的服务器往往不是因为用了多复杂的工具而是管理员对“用户”这个概念本身理解得足够清楚——用户名只是一个翻译层UID才是系统真正在乎的东西账号创建时要规划好权限边界删除时要全盘清理平常还要坚持看日志、查异常。这套基本功打扎实了后面再去碰什么容器、云原生、IAM体系都会轻松很多。