ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux权限管理完全指南:从UID/GID到chmod/sudo实战

Linux权限管理完全指南:从UID/GID到chmod/sudo实战 1. 先搞清楚“我是谁”用户身份与UID/GID1.1 为什么Linux用数字记人UID/GID与passwd文件很多人在Windows下用习惯了图形界面刚转Linux时遇到权限报错第一反应是“我是不是命令敲错了”。其实大部分权限问题都出在一个更基础的环节Linux系统默认不认用户名只认数字ID这个数字就是UID用户ID和GID组ID。你在终端里输入ls -l看到的root root系统真正拿去做判断的是文件记录的UID 0和GID 0。打开/etc/passwd每一行就是一个用户账户字段用冒号分隔。举个实际的例子www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin第一列是用户名第二列是密码占位符真正的密码存在/etc/shadow里第三列UID第四列GID后面是用户描述、家目录、登录Shell。你平时用id命令看到的就是这些数字背后的映射关系id uid1000(zhang) gid1000(zhang) groups1000(zhang),4(adm),27(sudo)这里面有个关键信息用户所属的组分“主组”GID列和“附加组”groups里除了主组之外的那些组。判断权限时系统除了看主组还会把附加组全部拿进去比对。所以一个用户能不能读某个组权限的文件不完全取决于他初始分配到哪个组后补加的附加组同样有效。1.2 root与普通用户权限差距到底有多大root的UID是0在Linux里UID 0拥有最高特权。用一句话概括root和其他用户的差距所有传统权限检查在UID 0面前都直接放行。文件是000权限root照样能读目录没有写权限root照样能建文件进程是别人的root一样能kill。之所以设计成“UID 0特判”是因为系统启动、修复、挂载、调整内核参数这些操作必须有一个不受普通权限约束的入口。但这不意味着你应该整天用root干活。我见过不少部署环境一上来就是rootserver操作一切结果真正出问题时反而更难排查因为你根本不知道正常用户会遇到什么权限错误。最典型的例子你用root把网站目录的属主全改成root、权限改成777网站能跑起来可一旦哪个php-fpm进程以普通用户运行它就无法写日志、无法生成缓存文件排查半天发现所有问题都是root“帮忙”绕过去的。实际工作中root只做两类事情一是系统级维护装软件、改系统配置、管理服务二是收尾修复普通用户搞不定你切root看一眼然后归还环境。日常操作能用普通用户就用普通用户能用sudo就用sudo这个习惯越早养成越好。1.3 进程的身份真正执行操作的不是你是进程这是权限问题里最容易被忽略的一点。你在终端里执行rm file看起来是“你在删文件”实际上真正发起删除操作的是bash这个进程而bash进程的身份才是内核做权限判断的依据。如果你通过sudo su切换到root再执行操作那么bash进程的UID是0如果你用sudo -u www-data执行命令那么该命令的属主身份就是www-data。为了把这个问题讲透需要引入两组概念真实用户IDreal UID和有效用户IDeffective UID。正常情况下两者相同都是你登录时的UID。但一旦涉及SUID权限后面第4节会细说有效UID就会临时变成文件属主的UID。内核在访问文件时看的几乎都是有效UID。所以排查权限问题时第一步永远不是看“我是谁”而是看“我当前这个进程是以什么身份在跑”。比如Docker容器里的进程经常在宿主机看来是root但容器内部的权限映射又是另一套规则这就是为什么容器挂载卷时报Permission denied时第一反应应该是看容器内进程的UID而不是看宿主机的当前用户。2. “我能干啥”的底层规则权限位怎么读怎么算2.1 rwx对文件和目录的含义完全不同大部分新手在权限上踩的第一个坑就是把对“文件”的理解直接套到“目录”上。ls -l看到-rw-r--r--知道这是所有者可读可写、其他人只读可看到drwxr-xr-x这种目录权限时很多人就蒙了——目录的r、w、x到底各代表什么文件层面的r/w/x很直观r代表可读取内容w代表可修改内容x代表可作为程序执行。目录是个完全不同的概念它的r是“可列出目录内容”w是“可在目录内创建、删除、重命名条目”x是“可进入这个目录或穿越它去访问更深的路径”。这里有个非常关键的实操结论删除文件看的是“文件所在目录”的权限不是文件本身的权限。只要你对某个目录拥有w和x权限那么即使目录里的文件是-r--r--r--只读你也可以直接把它删掉或改名。这就是为什么很多人困惑“这个文件我明明没有写权限为什么能删”因为删除操作的判断对象是目录不是文件。同理一个目录只有r权限没有x权限你能ls看到文件名列表但cd进不去也无法ls -l查看详细属性。目录只有x权限没有r权限你不知道里面有什么但如果你恰好知道某个文件名可以直接访问它。所以给网站/代码目录设置权限时至少要有r-x否则web服务连文件都读不到。2.2 权限检查的顺序属主、属组、其他人三选一ls -l输出最开始那10个字符第一个是文件类型后面9个分成三组每组三位文件属主user、文件属组group、其他所有人other。很多人以为权限是叠加的比如自己是属主就同时享有属主权限加上属组权限加上其他权限。大错特错。Linux的权限检查是“三选一”进程的有效UID与文件属主UID相同就只使用user位权限否则看进程的有效GID是否匹配文件属组GID或附加组匹配则只使用group位都不匹配才落到other。我举个例子文件属主是root属组是www-data权限是-rw-r-----。你是www-data组成员但不是root那么你能做的操作就是读因为group位是r--而root那三位rw-跟你没有关系。反过来如果这个文件group位是空的---但other位是r--你作为www-data组成员反而一点都读不了因为匹配了group组之后就不会再落到other了。这个“只取一组、命中即止”的机制让很多“以为叠加”的人栽过跟头。所以在设计权限时要提前想清楚三类身份的边界属主是谁、属组是谁、第三方是谁。最常见的做法是把需要协作的用户都拉进同一个附加组然后把文件属组设置成这个组给group位开权限。2.3 chmod 755/644的数值怎么来你肯定见过chmod 755、chmod 644这种写法这三个数字和rwx位的对应关系其实非常数学。r对应4w对应2x对应1一个数字就是这个用户类别下三个值的和。比如要给属主“可读可写可执行”就是4217要给属组“可读可执行”就是415要给别人“可读可执行”同样5于是chmod 755。反过来看到-rw-r--r--也能心算出数字属主rw-426属组r--4otherr--4对应644。这个换算练熟了以后看文件权限几乎不用过脑子。常用组合我列一下数值rwx位典型用途777rwxrwxrwx所有人可写可执行基本只用于临时共享生产环境要慎用755rwxr-xr-x可执行文件、目录属主可写其他人可读可执行750rwxr-x---目录或脚本组内可读执行外部不可见644rw-r--r--普通文件默认位属主可写其他人只读640rw-r-----配置类文件属主可写组内可读600rw-------私密文件如ssh私钥只允许属主读写400r--------只读文件比如某些证书文件注意一个细节chmod不只支持数字还支持符号模式比如chmod ux file给属主加执行位chmod g-w file去掉属组的写位。生产环境要批量修改时符号模式更直观不容易因为记错数字而误改其他位。3. 实操上手用户、组、文件权限一站式配置3.1 ls -l、chmod、chown、umask这几个命令的组合用法先看ls -l的一个完整输出-rw-r--r-- 1 zhang dev 1024 Feb 20 10:30 report.pdf drwxr-xr-x 2 zhang dev 4096 Feb 20 10:31 uploads第一列是类型加权限第二列是硬链接数目录通常是子目录数加2第三列是属主第四列是属组之后是大小、修改时间、文件名。看权限前要习惯性地用ls -ld 目录名查看目录自身的权限因为ls -l直接看一个目录时列出来的是目录里的内容不是目录本身的权限。日常调整权限最少会用到三个命令chown改属主chgrp改属组chmod改权限。一条命令可以把前两个合并完成chown zhang:dev report.pdf # 同时把属主设为zhang属组设为dev chown -R zhang:dev /data/upload # -R递归修改目录下所有文件 chmod -R gw /data/upload # 递归给属组加写权限还有两个容易被忽略的小技巧chmod --reference模板文件 目标文件可以把目标权限直接改成和模板一样适合批量统一chown --from旧属主:旧属组 新属主:新属组 文件可以只修改符合条件的文件避免误改。这些命令的组合能应付九成以上日常需求。再讲umask。你每次创建文件系统都会用默认最大权限套上一个“权限掩码”。普通文件默认666目录默认777然后用umask值做按位取反再相与。示例umask 022时文件是666 ~022 644目录是777 ~022 755。这就是为什么你新建的文件天然是rw-r--r--新建的目录天然是rwxr-xr-x。想要组内成员默认可以写把umask改成002文件就是664目录就是775。在团队协作的服务器上设置一个合适的umask往往比事后不断chmod更省心。修改方式是在/etc/profile或~/.bashrc里加一行umask 002然后重新登录。3.2 新建用户和用户组的最少踩坑配置创建一个新用户的命令很多人只敲一句useradd zhangsan然后发现新用户登录后没有家目录连命令提示符都怪怪的。这是因为在不同发行版上useradd的默认行为差异很大。稳妥的做法是显式指定useradd -m -s /bin/bash zhangsan passwd zhangsan-m表示创建家目录-s /bin/bash指定登录Shell。之后把用户加进需要的组比如加进sudo管理组Ubuntu/Debian或wheel组CentOS/RHELusermod -aG sudo zhangsan # 或者 gpasswd -a zhangsan docker # 加入docker组以便普通用户运行docker命令注意usermod -aG里的-a表示追加千万别漏掉否则会把用户从其他附加组里踢出来。改完之后用户需要退出重新登录或执行newgrp刷新组关系否则当前会话里id看不到新增的组。新建了用户之后常见的下一步是规划目录。假设你有一个/data/www项目目录想让zhangsan和另一个同事李四都可以编辑但不想让第三方看典型的做法是groupadd dev usermod -aG dev zhangsan usermod -aG dev lisi chown -R root:dev /data/www chmod -R 770 /data/www # 也可以加setgid位让目录里新建文件自动继承dev组 chmod gs /data/www这样不用给任何人root权限也能实现多人协作而且/data/www对外完全封闭。相比一上来chmod 777这个方案安全太多。3.3 用sudo做精细化授权别再轻易切rootsudo的本质是管理员定义“哪些用户、以哪些身份、能执行哪些命令”然后在日志里留下审计记录。配置文件在/etc/sudoers但强烈建议不要直接编辑这个文件而是用visudo或在/etc/sudoers.d/下放一个独立文件。这样既避免语法错误导致sudo整体不可用也方便按团队维护。最常见的授权形式zhangsan ALL(ALL:ALL) ALL这一行的意思是zhangsan可以在任何主机第一个ALL上以任何用户身份括号里的ALL:ALL执行任何命令最后的ALL。如果要限制只能管理某个服务zhangsan ALL(root) /usr/bin/systemctl restart nginx, /usr/bin/systemctl status nginx如果不希望每次执行都输密码可以加上NOPASSWDzhangsan ALL(root) NOPASSWD: /usr/bin/systemctl restart nginx这里有个很容易踩的坑sudo配置里如果命令不是绝对路径会直接报command not found因为sudo不会自动搜索当前用户的PATH。写配置时务必用which systemctl查一下绝对路径再写。我个人的建议是除非是单机自用的服务器否则不要给普通用户配置“完全root权限”。更合理的方式是按运维场景分成几个组比如docker组管容器、deploy组管发布目录、log组管日志查看然后在sudoers里用%组名批量授权。权限粒度越细出问题后能追溯和止损的余地就越大。4. 进阶特殊权限、ACL与Linux隐藏的“权限锁”4.1 SUID/SGID/Sticky Bit三种特殊权限普通rwx之外Linux还有三个特殊权限位分别用s、s、t表示对应的数字位置是4、2、1放在普通权限的前面或对应位置。SUID4只对可执行二进制文件有意义。它让普通用户执行该程序时进程的有效UID临时变成文件属主的UID。最经典的例子是/usr/bin/passwdls -l /usr/bin/passwd -rwsr-xr-x 1 root root 68208 ...普通用户需要修改自己的密码但/etc/shadow这个密码文件只有root能写。机制就是passwd程序带SUID执行过程中临时以root身份修改shadow文件。你可以把这个概念理解成你进了一间只有管理员能进的门但门禁卡上写的是管理员的编号出门后还是你本人。SUID一旦配错比如给bash、vim这些程序加了SUID任何普通用户执行它们都能拿到root权限这是非常严重的安全漏洞。SGID2对目录有特殊含义目录设置了SGID后在目录里新建的文件或子目录会继承该目录的属组而不是创建者自己的主组。这个特性在做团队共享目录时非常实用前面3.2里的chmod gs /data/www就是这个思路。这样无论谁在里面新建文件文件的属组都是dev组内其他人就能继续协作不会出现“我建的文件别人改不了”的尴尬。Sticky Bit1最典型的应用是/tmp目录ls -ld /tmp drwxrwxrwt 20 root root ...目录权限末尾那个t表示粘滞位。在/tmp这种目录里任何人都有写权限可以创建目录项但只有文件属主、目录属主或root才能删除/改名别人的文件。这防止了“别人建了个临时文件被你顺手删掉”的问题。设置方式chmod t /tmp或数字方式chmod 1777 /tmp。4.2 用ACL把权限精确到具体某个用户传统权限只有owner、group、other三档想单独给某个用户授权就非常别扭要么把用户加进组里但会影响所有组内成员要么再用sudo但粒度不够。ACL访问控制列表就是来解决这个问题的它能给任意用户或任意组单独设置权限。查看ACL用getfacl设置用setfacl。比如有一个/data/shared目录想让alice单独拥有读写执行权限其他人保持原样setfacl -m u:alice:rwx /data/shared setfacl -R -m u:alice:rwx /data/shared # 递归如果要让某个文件新建后默认继承ACL可以设置默认ACLsetfacl -d -m u:alice:rwx /data/shared设置完ACL后ls -l末尾会多出一个drwxrwx--- 2 root root 4096 Feb 20 10:31 shared这里要提醒一个ACL和chmod的交互坑当文件有ACL时传统group位的含义会变成ACL mask也就是“被ACL授权的用户和组的最高可达权限”。如果你之后执行chmod g-w可能无意中把所有ACL用户的写权限也砍掉了因为mask被改小了。碰到“我明明setfacl授权了怎么还是没权限”的问题先执行getfacl看mask再调整。4.3 root却删不掉文件chattr与SELinux在作怪有一种情况会让几乎所有Linux新手抓狂我都切到root了执行rm -rf竟然提示Operation not permitted。这不是普通权限问题十有八九是文件被加了不可变属性。查看属性用lsattr解锁用chattrlsattr /path/to/file ----i---------e-- /path/to/file chattr -i /path/to/file # 去掉不可变属性 rm -f /path/to/filechattr i设置不可变属性后即使是root也无法修改、删除、重命名该文件。有些加固过的系统会对关键文件比如/etc/passwd、日志目录加i属性防止恶意篡改。如果你在清理临时文件时遇到Operation not permitted先lsattr看一眼别急着怪系统。另一个“隐藏权限锁”是SELinux。CentOS/RHEL这类系统默认开启SELinux时权限判断除了传统的rwx位还要检查文件的安全上下文type。典型场景nginx报403文件明明有644权限、属主也对但就是读不了。用ls -Z查看上下文ls -Z /var/www/html/index.html -rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 index.htmlweb服务能正常读取的上下文一般是httpd_sys_content_t或httpd_sys_rw_content_t。如果你把文件从别的地方拷进来上下文变成了home_t或user_tmp_tnginx就会拒绝访问。修复方式restorecon -Rv /var/www/html或者临时调整到目标类型chcon -t httpd_sys_content_t /var/www/html/index.htmlrestorecon是按SELinux策略数据库恢复默认上下文chcon是临时直接修改更推荐前者因为下次restorecon还会保持一致。遇到莫名其妙的权限问题用setenforce 0临时关一下SELinux试试如果问题消失基本就能断定是SELinux策略在拦截。不过关掉SELinux只适合排查生产环境还是要找到正确的上下文或布尔值设置。5. 实战权限不足、无法删除、docker/mount场景排查实录5.1 一套通用排查流程从id到namei再到lsattr权限问题千奇百怪但排查路径完全可以套路化。我遇到任何“Permission denied”或“无法删除/修改”都会按这个顺序走第一步确认当前身份。执行id看使用者的UID/GID和附加组执行whoami看有效用户。这一步能排除一半的“我以root登录但网站没权限”这类基础误区。第二步确认目标文件的权限和属主。ls -ld /path/to/file看文件或目录本身的权限。注意路径每一层都要看因为任何一个中间目录缺少x权限都会导致最终无法访问。这里有个非常好用的命令namei -l /var/www/html/index.html它会一层一层列出路径里每个目录/文件的属主和权限哪一段权限不对一目了然。很多“路径越长越容易出问题”的疑难杂症就是靠这一步定位的。第三步检查是否是特殊属性或SELinux。执行lsattr -d /path看是否被加了i执行ls -Z /path看SELinux上下文。如果这两个都正常再看ACLgetfacl /path说实话走到这一步九成五的权限问题都能定位了。剩下极少数可能是挂载选项导致的比如mount时加了noexec或nosuid这些用mount | grep 挂载点就能看到。5.2 文件权限修复实操chown -R后用find按需修正权限修复最常见的错误就是“不管三七二十一整个目录chmod 777”。这样虽然立竿见影但等于把校验门全部打开后患无穷。我更推荐有节奏地修复。场景某个web项目迁移到新机器后页面能打开但上传图片报“目录不可写”日志显示Permission denied。第一步搞清楚web进程运行用户。常见的是www-dataDebian系或nginxRHEL系ps aux | grep -E nginx|php-fpm | grep -v grep进程输出第一列就是运行用户。我遇到过最迷惑的情况是php-fpm和nginx分别用了不同用户导致nginx能读、php-fpm写不了。这种时候先统一它们要么同一个用户要么明确各自职责。第二步把项目目录整体归属到运行用户并保留组权限chown -R www-data:www-data /var/www/myapp chmod -R 755 /var/www/myapp第三步单独给“可写目录”加写权限而不是全站可写find /var/www/myapp -type d -name uploads -exec chmod 775 {} \; find /var/www/myapp -type d -name cache -exec chmod 775 {} \;如果目录里还需要缓存文件、日志文件可以进一步区分目录用775文件用664。这里最关键的思路是“最小可写范围”只有确实需要动态写入的目录才给写权限其他一律只读。5.3 docker挂载卷、网站上传、普通用户mount三个高发场景场景一Docker挂载卷Permission denied这是用Docker最常碰到的坑。你在宿主机创建了/data/mysql目录并chown成自己然后启动MySQL容器docker run -v /data/mysql:/var/lib/mysql mysql:8.0容器内MySQL进程默认以mysql用户运行uid通常是999而宿主机/data/mysql目录属主是你的uid 1000容器内进程对这个目录就没有写权限。常规解法有三个一是直接把宿主目录的属主改成容器内进程的uidchown -R 999:999 /data/mysql二是用docker run --user参数指定以宿主机uid运行比如--user 1000:1000但这要求镜像里的进程允许切换用户。三是在docker-compose.yml里设置user: 1000:1000。我一般优先用第三种因为它把配置固化下来了别人拉下来也能复现不会“这个机器能跑换台机器就挂”。场景二网站上传文件后显示403上传功能正常但访问上传后的图片404或403。用ls -l看上传文件发现属主是www-data权限是644目录是755乍看没毛病但拿namei -l一查发现上传目录某个父级只有r-x中间链断裂了。修复思路很简单给路径上每一层都补上执行权限。另一个常见原因是上传后文件带有SELinux上下文需要restorecon -R一下。场景三普通用户无法mount挂载传统mount命令要求root权限普通用户直接执行会报权限不足。桌面环境可以用udisksctl mount -b /dev/sdb1服务端更稳妥的方式是在/etc/sudoers.d/里做白名单授权zhangsan ALL(root) NOPASSWD: /usr/bin/mount /dev/sdb1, /usr/bin/umount /dev/sdb1注意白名单要精确到具体设备挂载路径不要写裸的/usr/bin/mount否则用户可以用mount --bind做各种奇奇怪怪的事情授权面太宽。5.4 常见权限问题速查表与最小权限原则为了方便快速对照我把高频问题整理成一张速查表现象可能原因排查命令解决办法能列出文件名但cd不进去目录缺x权限namei -lchmod x 目录文件明明有写权限还是改不了父级目录缺w权限ls -ld 父目录给父目录加w权限root也删不掉文件文件被加了不可变属性lsattr 文件chattr -i 文件后删除网站403且权限/属主都对SELinux上下文不对ls -Zrestorecon -Rv 目录Docker容器读写宿主机目录报错容器内uid与宿主机属主不匹配ps aux看容器内用户chown -R 999:999或compose指定user普通用户sudo报command not foundsudoers里没写绝对路径which 命令写完整路径重配sudo同一个组内用户互相改不了文件目录没有SGID继承组权限ls -ld 目录chown -R :组名 目录 chmod gs 目录说到底Linux权限设计其实不复杂核心就三件事身份我是谁、权限位我能干啥、特殊机制谁能绕过规则。只要坚持“最小权限”原则给每个用户只开够用的权限给每个服务建立独立的运行用户绝大多数权限问题都不会发展到让你焦头烂额的地步。在我实际维护服务器的经验里权限故障七成是“目录权限没搞对”或“属主/属组没设对”两成是“临时图方便chmod 777埋下的雷”只有一成是SELinux、ACL这些进阶机制。排查时先看目录再看属主最后才考虑特殊机制顺序对了问题就少了一大半。另外每次改权限前用ls -l和namei -l各看一眼改完后第一时间用实际操作验证别改完就以为完事——权限这东西验证过才算数。
返回列表