Linux用户与权限机制详解:从用户组管理到文件权限配置 1. 先想清楚Linux为什么要搞一套“用户权限”机制1.1 从一次“删库”事故讲起我早期带过一个刚转行的同事他在一台测试服务器上执行了rm -rf /当时所有人都在忙没人拦得住他。为什么他能干出这种事因为他一直用 root 干活权限大到没有边界。Linux 里有一句话叫“root 的权限不是用来日常使用的是用来救命的”这句话用一次付费事故让我彻底记住了。你可能觉得这离自己很远但实际上没有用户和权限体系Linux 根本没法在多用户、多任务的真实环境中生存。服务器上跑着 Web、数据库、定时任务还有几十个人轮流登录如果没有隔离任何一个人手滑都会把整个环境搞瘫。用户和权限就是 Linux 的第一道安全边界它要解决的问题很简单谁可以进来、进来之后能干什么、不能碰什么。那套机制本身并不复杂先通过用户身份确认“你是谁”再通过权限位确认“你能动哪些文件”。整个体系建立在两个基本概念上——用户User和组Group。每个用户都有唯一的 UID每个组也有唯一的 GID文件则记录了它的属主、属组和“其他人”的权限。这套设计从 Unix 时代延续到今天看起来朴素却是最成熟、最稳定的多用户隔离方案。1.2 UGO 三件套与最小权限原则Linux 文件权限的经典模型叫 UGO全称 User、Group、Other。意思是针对每个文件系统会分别记录三类主体的权限文件属主User、属主所在的组Group、以及除前面两者以外的所有人Other。每个主体都能设置三个动作读r、写w、执行x。这套设计背后有一个核心理念叫做“最小权限原则”任何一个进程、任何一个用户只应该拥有完成任务所必需的最小权限多余的一律不给。很多安全事故不是被攻破的而是因为权限开得太大。比如给了用户sudo全部授权等于把整个服务器的钥匙都交了出去。群里有人问为什么 Linux 服务器上的 Web 目录权限最好不能给 777我直接回了一句“777 等于把家门钥匙贴在门牌号下面。”这不是夸张后面我会具体解释为什么写权限落到所有人手里是灾难。1.3 这套机制到底解决了什么问题一个刚接触 Linux 的人最容易迷惑的是明明我自己装的系统为什么动不动就Permission denied这里要先明确一个事实Linux 不是为单机单用户设计的它天生假设这台机器可能被很多人用甚至被同时使用。于是它强制要求你先登录成某个用户再用这个用户的身份去操作系统。这就带来了三个直接效果隔离普通用户不能翻看别人的家目录不能改系统配置文件。追踪系统日志能记录哪个用户做了哪件事出了问题可以回溯到人。降权服务可以用专用账号运行即使被攻破攻击者也拿不到 root 权限。你可以把 Linux 的用户权限体系理解成一栋办公楼root 是楼长有所有房间的钥匙普通用户是在某个工位上班的员工只能进自己的工位区域而权限位就是每扇门上的锁。楼长偶尔来做保洁可以不锁门但长期把整栋楼的大门敞开迟早会出事。所以读者接下来看到的每个命令、每段配置都是围绕这三个效果展开的。看完你会发现权限管理不是一条条命令的死记硬背而是一套“先想清楚谁该拥有什么再动手操作”的方法论。2. 用户和组管理从创建账号到日常切换2.1 useradd 一条命令背后发生了什么先来看最基础的操作新建用户。网上最常见的教程是写一句useradd zhangsan然后passwd zhangsan设密码就完事了。但如果你用的是 Ubuntu 这类 Debian 系系统执行完useradd zhangsan会发现没有家目录而且登录后连命令行提示符都不太对劲。这不是你操作错了是useradd的默认行为在缺省情况下不创建家目录。Debian 系的useradd和 Red Hat 系的useradd默认策略不完全一样前者更保守后者通常会自动创建家目录并设置默认 shell。所以在写脚本批量建用户时一定要带上完整参数不要赌默认值。我平时最常用的一条完整创建命令长这样sudo useradd -m -s /bin/bash -d /home/deploy -G docker,sudo deploy sudo passwd deploy参数解释一下-m自动创建家目录。-s /bin/bash指定登录 shell不指定的话可能拿到的是/bin/sh对普通用户不友好。-d /home/deploy家目录路径默认情况下和用户名一致但可以显式指定。-G docker,sudo把用户加入附加组这里是为了让新用户能执行 docker 命令和 sudo。还有一个常见的隐藏参数是-u可以指定 UID。比如你希望某个账号的 UID 是 1001直接这样写sudo useradd -u 1001 -m -s /bin/bash testuser为什么要手动指定 UID因为有些场景要求文件和账号的 UID 与某个历史遗留目录保持一致。比如你迁移了一套老系统原来文件属主 UID 是 1010新系统建用户时如果不指定系统会自动分配一个 UID文件属主就会变成“无名氏”显示一大串数字。所以做迁移时我一般会先写一个包含用户名、UID、GID、家目录、shell 的清单再批量执行。useradd内部做了什么它并不是只往配置文件里加一行。实际的流程大致是先解析/etc/login.defs和/etc/default/useradd里的默认策略然后往/etc/passwd写用户项往/etc/shadow写密码项如果指定了-G还要往/etc/group里追加用户到相应组最后根据-m参数决定是否从/etc/skel复制模板文件到家目录。排障的时候你按这个顺序去检查文件基本都能找到问题。2.2 密码策略与账号维护创建用户只是第一步密码怎么设置才是真正的安全分水岭。passwd命令大家都用过但有几个细节容易被忽略普通用户改自己密码时旧密码是必须验证的root 改别人密码时不需要知道旧密码。密码在被“确认”之前账号其实是锁定状态。如果你只useradd忘了passwd这个用户是没法登录的这在批量交付账号时尤其容易踩坑。可以在/etc/login.defs里设置全局密码策略比如PASS_MAX_DAYS 90 PASS_MIN_DAYS 7 PASS_MIN_LEN 8PASS_MAX_DAYS控制密码最大有效期90 就是 90 天必须改一次PASS_MIN_DAYS防止用户立刻修改密码绕开历史记录PASS_MIN_LEN是最小长度。虽然现在更推荐用 PAM 做复杂度控制甚至不禁用密码改 SSH 密钥但login.defs还是有它的基础防线价值。维护账号时另外三个命令要记牢usermod -aG docker zhangsan追加附加组注意必须带-a不带的话会把用户从所有附加组里剔除只留这一个组这是新手最容易翻车的地方。userdel -r zhangsan删除用户并清理家目录和邮件池。不带-r的话家目录文件会变成孤儿文件以后想清理还得手动判断属主。getent passwd zhangsan从所有数据源查询用户信息比直接cat /etc/passwd更准确因为会包含 LDAP 等远端用户。还有一个高频需求是锁定账号。员工离职时不需要立刻删除可以先usermod -L zhangsan锁住过段时间确认没有遗留任务再删。解锁则用usermod -U。2.3 从普通用户切到 root 的几种姿势很多从 Windows 过来的人第一个问题就是“我装完 Ubuntu登录进去怎么不是 root”这不是系统坏了而是 Ubuntu 默认直接禁用了 root 密码登录日常操作靠sudo来完成。想切换 root有几种常见姿势按使用场景我区分了一下临时提权命令前面加sudo比如sudo vim /etc/hosts。切换登录用户su -切换到 root 用户环境变量一起切换su不带-只切用户但保留当前环境容易拿到的 shell 环境不完整。先给 root 设密码再直接用 root 登录sudo passwd root设置完后可以用 root 登录但我强烈不建议日常这么做尤其是在生产环境。为什么推荐sudo而不是直接切 root因为 sudo 有日志执行了什么命令都记录在/var/log/auth.log或/var/log/secure里。一个团队五六个人一起管理服务器出了事能查到是哪个账号、哪条命令干的。而 root 的“匿名性”太高一旦大家都在 root 里干活出问题就变成“查无此人”这是运维最忌讳的。如果你用的是 Red Hat 系系统安装时就已经设好了 root 密码可以通过su -切过去。Ubuntu/Debian 系则更多用sudo第一个创建的用户默认在sudo组里。想确认自己有没有 sudo 权限直接跑sudo -l它会列出当前用户能执行的 sudo 规则。3. 文件权限体系看懂 rwx改对 chmod3.1 一个 ls -l 的输出能读出什么用户和组是“人”的概念文件权限是“门锁”的概念。先把最经典的输出拆开看$ ls -l /etc/shadow -rw-r----- 1 root shadow 1245 Mar 12 10:30 /etc/shadow第一列有 10 个字符含义拆解如下位置含义第 1 位文件类型-普通文件d目录l软链接第 2-4 位属主权限r/w/x第 5-7 位属组权限r/w/x第 8-10 位其他人权限r/w/x第三列是属主第四列是属组。上面的/etc/shadow属主 root、属组 shadow权限是rw-r-----也就是属主可读可写shadow 组可读其他人什么都干不了。这个密码文件本来就应该只有 root 能碰所以这样的权限配置是合理的。注意目录的权限和文件的权限同样一个 rwx含义完全不同。我用一个容易理解的类比来说明文件的读r是能看内容写w是能修改内容执行x是能运行。目录的读r是能列出里面有啥写w是能在里面新建和删除文件执行x是能“穿过去”访问里面文件的属性。只给目录 r 不给 x你可以ls看到文件名但cd进去之后访问任何文件都会失败因为你看不到文件的具体 inode 信息。只给 x 不给 r能进去但列不出文件名除非你准确知道文件名否则在里面寸步难行。这两个权限经常一起出现但缺一个的效果完全不同排查问题的时候要留意。3.2 chmod 数字法与符号法的换算逻辑修改权限用得最多的是chmod数字法是最速成的写法。规则是r 记 4w 记 2x 记 1把同一行的三个数字加起来得到一个 0-7 的值。举个例子rwx 421 7rw- 42 6r-- 4--- 0常见的目录权限755就是属主rwx组r-x其他人r-x。文件的644是属主可读写组和其他人只读。那为什么目录默认给 755、文件默认给 644这就引出一个关键问题执行权限对目录意味着“能否穿越”所以目录必须给 x普通数据文件给 x 反而容易招来执行风险。符号法也值得掌握它的格式是[谁][操作][权限]u属主g属组o其他人a所有人增加权限-移除权限覆盖权限chmod ux script.sh # 给属主加执行权限 chmod o-rw secret.txt # 移除其他人的读写权限 chmod a-w readme.txt # 对所有人都去除写权限还有两个容易被忽略的参数-R递归修改比如chmod -R 755 /home/web。这个参数带来便利也带来危险。如果你对一个有很多软链接的目录递归执行chmod -R 777软链接指向的所有目标文件都会被波及。--reference从另一个文件复制权限比如chmod --reference/tmp/template.txt /etc/nginx/nginx.conf批量部署时很好用可以避免手算出错。3.3 umask为什么新文件默认 644、新目录默认 755很多人不理解为什么新建的文件是 644不是 666新建的目录是 755不是 777。答案在umask。umask是一个“权限屏蔽值”。当你创建文件时系统先给一个满权限文件是 666目录是 777再减去 umask 得到最终权限。Linux 默认 umask 通常是 022所以文件666 - 022 644目录777 - 022 755umask什么时候会坑人最典型的场景是上传代码或写日志时如果系统全局把 umask 改成了 002那么新建的文件权限是 664普通用户之间互相可写整个目录用户之间的隔离就被削弱了。另一个常见坑是配置了setgid目录和 ACL 后umask 还会意外地影响新文件对组成员的写权限这个后面讲 ACL 时再展开。查看当前 umaskumask临时修改umask 027修改默认值可以在/etc/profile、/etc/bashrc或/etc/login.defs里改但比较推荐的还是在/etc/login.defs里修改全局 UMASK 字段因为它会同时影响登录会话和系统服务。改完要测试因为不同发行版对 umask 的处理逻辑有差异。权限设置里最需要警惕的是chmod 777。很多网上教程为了让 Web 服务能写目录直接给 777结果上传目录变成任何人都能删改文件的地方。如果再加一层解析漏洞攻击者把 webshell 传进去整台机器就基本失守了。我在服务器上见过太多的uploads/目录是 777一问全是“当时补丁怎么都报错就给权限了”。正确做法是看进程身份如果你的 Nginx/PHP 以www-data身份运行就把目录属主改成www-data权限 755需要写就 775 或 750而不是把所有权限摊给全世界。所谓“最小权限”在 Web 目录这件事上格外体现得淋漓尽致。4. 进阶授权方案ACL、特权位、sudo 与容器权限4.1 ACL给特定用户单独放行传统 UGO 模型有个很大的局限一个文件只能有一个属主、一个属组、一套其他人权限。如果实际场景是“张三要读日志李四要写日志其他人完全不要碰”UGO 就很难优雅地表达。第三方同步工具、监控采集账号、临时合作的同事给完整属主权限太重不给他们又干不了活这时候该上 ACL。ACL 全称 Access Control List它的作用是在传统权限之外再给额外的用户或组设置权限。日常就三条命令setfacl -m u:zhangsan:rw /data/logs/app.log # 给张三读写 setfacl -m g:devteam:r /data/logs/app.log # 给 devteam 组读权限 getfacl /data/logs/app.log # 查看 ACLsetfacl -m是修改-x是删除某条-b是移除全部 ACL。加了 ACL 之后ls -l通常是看不出完整信息的属主权限位后面会多一个加号比如-rw-rw-r--要看清是谁给了什么权限必须用getfacl查看。ACL 有两个实战经验值得记下来第一ACL 对目录可以继承。setfacl -m d:u:zhangsan:rwx /data/upload是给目录设置默认 ACL意思是以后在这个目录下新建的文件自动继承给张三的权限。这比每次新建文件后手动chmod要可靠得多。第二ACL 和 umask 叠加时权限会比预期小。比如设置默认 ACL 让组可写结果新建的文件组写权限没了。原因是有 ACL 的目录新文件创建时 umask 的作用对象变成了 ACL 掩码。解决方法是设置完默认 ACL 之后把 mask 也一起设好setfacl -m m:rwx /data/upload这条命令会把 ACL mask 设为 rwx避免组权限被 umask 拦掉。如果不做这一步调试半天也找不出为什么组写权限丢了。4.2 SUID/SGID/Sticky 三位特殊权限除了 rwx 这三个常规位Linux 还有三个特殊权限平时用得少但理解它们能解释许多“为什么普通用户能执行这个却改不了那个”的问题。先说 SUID。它出现在属主的执行位上显示为s数值是 4。一个可执行程序如果带 SUID那么它在运行时会以文件属主的身份运行而不是执行者的身份。最经典的例子是/usr/bin/passwd$ ls -l /usr/bin/passwd -rwsr-xr-x 1 root root 71416 Apr 1 2024 /usr/bin/passwd这个文件的属主是 root普通用户执行passwd时它会临时以 root 身份运行这样才能写入/etc/shadow。如果没有 SUID普通用户没法改密码。但这也意味着一旦某个 root 属主的程序存在漏洞攻击者可能利用它提权。所以在新部署的环境里我会定期用find / -perm -4000查找所有 SUID 文件检查有没有不该带 SUID 的程序。SGID 在两类地方表现不同。作为可执行文件它运行时继承属组身份作为目录权限它让新建文件的属组自动继承目录的属组而不是创建者的主组。这个特性在做团队共享目录时很实用比如/data/shared属组是devteam设置 SGID 后小组成员在里面创建的文件自动属于devteam别人就不用反复chgrp了。设置方法chmod gs /data/sharedSticky Bit 最常见的位置是/tmp显示为t数值是 1。它限制在目录里只有文件属主、目录属主或者 root 能删除文件避免“谁都能清空别人临时文件”的混乱局面。系统默认给/tmp带上了这个位日常维护中如果你自己搭的共享上传目录不想让大家互相删除也可以加上chmod t /data/upload4.3 sudo 配置与 docker 权限错误的解法sudo 是 Linux 权限管理里“人”和“权限”之间的调节阀门。一个用户能不能 sudo 跑某个命令不是用户自己决定的而是写在/etc/sudoers里。修改这个文件不要直接用 vim 改一定要用visudo它会做语法检查避免你把 sudoers 改坏以至于所有人都无法提权。常见规则解释zhangsan ALL(ALL) /usr/bin/systemctl restart nginx, /usr/bin/journalctl意思是张三可以在任何主机上运行系统ctl 重启 nginx 和 journalctl 这两条命令。如果想给整个 sudo 组放开权限通常看到的是%sudo ALL(ALL:ALL) ALL这是 Debian/Ubuntu 系的默认规则意思是 sudo 组的所有成员可以执行任何命令。这本质上等于把用户提升为 root 权限所以不要把不信任的人随便加进 sudo 组。还有一条我强调过无数次的建议生产环境不要配NOPASSWD。虽然无密码 sudo 很方便但代价是“只要这个账号被入侵对方不需要任何密码就能直接拿到 root”。如果一定要给某个脚本自动化使用也应该限制它只能执行特定命令而不是给ALL。并且脚本里要用绝对路径避免被篡改 PATH 后劫持。说完了 sudo再讲一个几乎每个 Linux 新手都会撞上的问题装了 Docker 之后执行 Docker 命令报permission denied while trying to connect to the Docker daemon socket。原因很简单当前用户对/var/run/docker.sock没有访问权限Docker 客户端必须通过这个 socket 和守护进程通信。常见解决办法有两种第一种是把自己加入 docker 组sudo usermod -aG docker $USER newgrp docker第二条命令是让当前会话立刻生效不用退出重登。但这里我必须多说一句加入 docker 组实际上等于变相获得 root 权限因为 Docker 可以挂载宿主机目录到容器实验环境这样做没问题生产环境的服务器慎加。第二种方案是给管理员配好 sudo平时用sudo docker权限范围更可控日志记录也更清晰。我自己在服务器上是坚决把 docker 组的使用限制在隔离环境里的。5. 权限问题排查实录从 Permission denied 到误操作恢复5.1 文件删不掉的真正原因“为什么我明明有权限写入某个文件却删不掉它”这是日常工单里出现频率极高的一类问题。原因是删除文件依赖的不是文件本身的写权限而是它所在目录的写权限与执行权限。你要在目录里新增或删除一个项必须对目录有写权限。所以即使一个文件模式是 666任何用户都能往里面写内容但如果它所在目录对你是只读的你同样删不掉它。判断方法很简单逐级往上ls -ldls -ld /data /data/logs /data/logs/app.log如果目录权限位正常但你还是删不掉再查两个地方目录是否被设置成了不可变属性lsattr /data/logs如果看到i属性即使 root 也不能删除需要先chattr -i再操作。目录是否有 ACL 掩盖了实际权限getfacl /data/logs。还有一个高频场景是“You need permission”或者 Linux 下类似的 Permission denied其实根因在属主和属组不匹配。比如你用rsync同步了一堆文件过来文件属主是旧的 UID 1000新系统上 1000 对应的却是另一个用户于是你明明觉得自己是文件的主人实际却不是。解决方法是用find /data -user 1000 -exec chown newuser {} \;批量修正或者同步时保留属主信息带-a参数。我自己踩过最哭笑不得的一个坑是某同事上线了一个脚本部署完把整个目录递归 chmod 成 000然后紧急找我恢复。那次教训让我养成了一个习惯凡是涉及批量-R的操作先对目录做一次find ... | head看清里面有什么再加--reference或者按规范重新授权而不是直接对整棵目录树动刀。5.2 权限被改乱后的修复思路万一你已经执行了类似sudo chmod -R 777 /的操作先别慌也别立刻崩溃。修复思路分三步走第一步停止一切不必要的写操作防止权限继续被覆盖。第二步如果是命令误伤用包管理器或配置管理工具恢复关键目录的标准权限。在 Debian/Ubuntu 上可以执行apt --reinstall install base-files但注意这不会把你改错的文件权限全部修好它只恢复部分关键包的基础文件。第三步也是最有效的你平时应该对这些关键目录做过权限基线备份。stat -c %a %U %G %n /etc /var /usr打印出来的权限表导出为一个文件放在安全的地方出事时对照恢复。更稳妥的方案是提前启用配置管理工具比如 Ansible。一个简单的 Ansible playbook 就声明了/etc目录该有什么权限即使线上被改乱也能把状态拉回来。很多人以为 Ansible 只是发布工具其实它也是权限灾难恢复的救生船。另外一个视角是“为什么不建议普通用户随便 chmod”。我在团队里定的准则是能分目录授权的不要全盘授权能用属组解决的不要把所有用户塞进 sudo 组能改配置解决的不要手动改权限。权限不是越宽越好也不是越严越好而是“恰好能让服务跑起来同时不给多余入口”。5.3 忘记 root 密码时的紧急处理忘记 root 密码是另一大类求助。这里给出通用的救援思路不区分发行版细节如果在 Grub 启动界面编辑内核启动项在linux开头那行末尾加上init/bin/bash然后启动。系统会直接进入单用户模式的 shell此时文件系统可能是只读的先重新挂载可写mount -o remount,rw /接着用passwd root重置密码然后重启即可。新版 systemd 发行版也可以用rd.break参数进入 dracut 的紧急 shell操作会稍微繁琐一点。其实思路完全一样拿到一个能写/etc/shadow的环境然后用passwd重置身份凭证。我要提醒的是这套方法物理接触得起作用。如果你的服务器放在机房远程只能通过 SSHroot 密码忘了又没有其他 sudo 用户那就得走带外管理卡。所以部署服务器的第一天就应该把“备用登录路径”准备好比如至少有一个非 root 的 sudo 管理员账号并且记录在安全的地方而不是把所有鸡蛋都放在 root 一个篮子里。5.4 日常权限操作速查表最后把实际运维中最常用的权限相关命令整理成一张表其实用价值高于一段长文字需求命令说明创建用户并设置密码useradd -m -s /bin/bash userpasswd user记得同时设置密码查看用户信息id user显示 UID/GID/附加组修改用户附加组usermod -aG group user-a必须带否则会覆盖原附加组删除用户userdel -r user-r清理家目录普通单独授权setfacl -m u:zhangsan:rw file适合复杂多人协作修改权限chmod 750 dir目录常用 750修改属主属组chown zhangsan:devteam file同时改用户和组查看 ACLgetfacl file带的权限位要看这里搜索系统 SUID 文件find / -perm -4000定期安全检查查看 sudo 权限sudo -l当前用户的 sudo 规则切换 rootsu -环境变量一起切换写在最后我接手过的服务器里一半以上的安全事件和权限设置不当有关而另一半则是“权限卡住业务”导致有人私下放宽权限。这两种问题表面相反根子上都是同一个没有形成一个稳定的、可追溯的授权流程。如果你刚开始学 Linux不要急着把所有操作都放到 root 下跑。先强制自己用一个普通账号日常作业需要的时候再 sudo。即使是自己的笔记本我也建议这么做。用坏一个环境很容易但学会在权限约束下把事办成这个经验会伴随你整个职业生涯。最后送两个小建议第一给服务器的关键目录做一份权限基线档案开箱即配不要等到删库再后悔第二每次给权限之前问自己一句“这个用户真的需要这个权限吗给少了会不会出问题给多了又会带来什么风险”想清楚这两点你离一个靠谱的 Linux 维护者就不远了。