ARTICLE DETAIL

资讯详情

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

Linux文件访问控制全解:从rwx权限到ACL配置实战

Linux文件访问控制全解:从rwx权限到ACL配置实战 带新人时我经常发现很多人学 Linux 命令行能记住几百个命令可一遇到“控制对文件的访问”就卡壳。明明登录了服务器却进不了目录明明在同一组写不了共享文件想给别人开放一个目录又怕打开过大权限埋下隐患。Linux 入门阶段文件访问控制就是一道分水岭它不难但如果不把权限模型、命令逻辑和常见坑串起来很容易靠试错去“凑权限”最后凑出一堆风险。这篇文章我会从最基础的 rwx 权限位讲起再讲到特殊权限位、umask 和 ACL最后用一个真实的多角色目录配置案例把整个过程走一遍。适合刚接触 Linux、被 Permission denied 折磨过的朋友也适合需要给团队共享目录做隔离的运维新手。内容尽量按我实际操作的顺序来写该提醒的地方都会点出来。1. 权限模型的第一课rwx 谁都会写但目录和文件完全是两码事1.1 九个权限字符背后的二进制逻辑先在终端里执行ls -l你会看到类似这样的输出-rw-r--r-- 1 root root 1024 Apr 10 10:30 readme.txt drwxr-xr-x 2 root root 4096 Apr 10 10:31 scripts第一列有 10 个字符。第 1 个字符表示文件类型-是普通文件d是目录l是符号链接。后面 9 个字符分成三组每组三个分别代表文件属主user、文件属组group、其他用户other的权限。每个组里按顺序是 r读、w写、x执行没有对应的权限就用-占位。这 9 个字符不是凭空设计的它对应着系统里真正存储的 9 个二进制位。r 的位权是 4w 是 2x 是 1三组各自加和后就是一位八进制数。这就是为什么你总会看到 644、755、700 这种三位数字。rw-r--r--拆开是110 100 100八进制就是 644rwxr-xr-x是 755。计算本身没什么技术含量但我建议你养成一个习惯看到权限字符串脑海里立刻把它转成数字。比如-rwx--x--x就是用户 7组 1其他 1也就是 711。日常判断一个配置脚本权限够不够用转成数字以后会快很多。1.2 目录上的 rwx含义和文件完全不同很多新手把文件权限的概念直接套到目录上结果遇到了各种奇怪问题。文件上的 r 是读取文件内容w 是修改文件内容x 是执行该文件。但目录本质上是一个“目录项列表”所以它的权限含义完全不同读权限r允许列出这个目录里有哪些名字。也就是ls能看到文件名。写权限w允许在这个目录里创建、删除、重命名文件或子目录。执行权限x允许“穿过”这个目录也就是cd进去并且访问里面文件的元数据和内容。关键来了如果目录只有 r 没有 x你确实能用ls列出一堆文件名但因为无法访问这些文件的 inode 元数据想stat某个文件或者用cat读内容都会失败。反过来只有 x 没有 r你能cd进去但ls看不到任何名字只有你确切知道某个文件名时才能直接访问它。我习惯用一个类比来记目录的 x 是房间钥匙r 是房间里物品的清单w 是往房间里搬东西或扔东西的许可。只有钥匙才能进门只有清单才能知道有什么想动里面的东西才需要 w。所以目录权限常见的组合是 755、750、700几乎不会单独给 6因为只给读不给执行目录基本没法正常用。2. 改权限的三板斧chmod、chown、chgrp 的正确用法2.1 chmod 用数字还是符号实际项目里怎么选chmod有两种写法。数字法直接给整组权限赋值chmod 750 /srv/project chmod 644 readme.txt符号法则更适合微调。比如给脚本加上执行权限chmod ux run.sh把属主设为可读可写、属组只读、其他无任何权限chmod urw,gr,o file.txt我自己的习惯是在脚本和部署文档里一律用数字法因为表达完整、可复现别人看到 750 就知道最终状态是什么。临时调试时用符号法比如chmod x这种操作不需要计算整个权限值。这里有一个必须强调的坑chmod -R递归修改时会把目录下所有文件都改一遍。如果目录里放了符号链接GNU 的 chmod 默认不会跟随命令行直接指定的符号链接但遍历过程中遇到的符号链接一般也不会去改链接指向的目标。不过为了保险包含符号链接的目录改权限时我建议先用ls -l看一遍确认没有链接指向不该改权限的文件。另外永远不要用chmod -R 777这种“管道工式”的解法。权限配置的目标是最小够用而不是让所有人都畅通无阻。一个所有人可写的目录等于把文件系统的安全门拆了别人塞一个恶意脚本进去你根本发现不了。2.2 chown 和 chgrp决定“谁的文件”和“哪些人的文件”权限位只是数字这些数字必须绑定到具体用户和组上才有意义。查看文件归属用ls -l输出里第 3 列是属主第 4 列是属组。修改归属用chownchown zhangsan:dev /srv/projectchown 用户:组中间的冒号也可以只写一半。chown zhangsan file只改属主chown :dev file只改属组等于chgrp dev file。GNU 的 chown 还支持--from当前属主:当前属组比如把原来属于旧账号的文件改给新账号避免误伤。普通用户能执行的 chown 操作很有限只能把自己拥有的文件的属组改成自己所属的组不能随意把属主改成别人。这是防止你把文件“甩锅”给其他用户进而绕过配额或审计。真正需要大范围调整归属的只有 root 或者有 sudo 权限的管理员。chgrp的单独价值在于快速把文件“借”给某个组使用。比如临时要让运维组读取一堆日志但不想改属主直接chgrp -R ops /var/log/app chmod -R gr /var/log/app这里同样要注意递归和符号链接的问题。GNU chown/chgrp 默认不跟随命令行上的符号链接但-R遍历时可能跟随路径中的链接。想明确修改符号链接本身的归属用-h参数比如chown -h user symlink。3. 特殊权限位、setgid 继承和 umask隐藏的默认规则3.1 SUID、SGID、Sticky 位到底在干什么除了 rwxLinux 还有三个特殊权限位。它们的数字位权分别是 4、2、1写在普通权限前面。比如4755表示设置了 SUID 的 7552770表示设置了 SGID 的 7701777是设置了粘滞位的 777。SUID 的效果是当一个可执行文件执行时进程的有效用户 ID 变成该文件的属主而不是发起者。最典型的例子是/usr/bin/passwdls -l /usr/bin/passwd -rwsr-xr-x 1 root root 59976 Feb 20 08:00 /usr/bin/passwd普通用户执行 passwd 要修改/etc/shadow这个文件只有 root 能写。如果没有 SUID普通用户根本改不了密码。设置 SUID 后passwd 运行时以 root 身份执行才有权限写 shadow 文件。但 SUID 也是最容易被滥用的位。给一个脚本或程序设置 SUID等于让普通用户执行时获得属主身份的权限如果是 root 属主就是提权。现在很多系统默认忽略脚本上的 SUID 位或者会在运行环境里清掉它所以给脚本设 SUID 往往不生效反而带来困惑。我的建议是除非你明确知道自己在做什么否则不要给任何文件加 SUID。检查系统里有哪些 SUID 文件可以用find / -perm -4000 -type f 2/dev/nullSGID 有两个层面的作用。对可执行文件效果类似 SUID不过是把有效组 ID 变成文件的属组。对目录SGID 的作用更常用在该目录下新建的文件或子目录自动继承目录的属组而不是创建者当前的主组。这个特性在团队共享目录里非常实用。Sticky 位的作用是防止用户删除不属于自己的文件。典型位置是/tmpls -ld /tmp drwxrwxrwt 20 root root 4096 Apr 10 10:00 /tmp/tmp是所有人可写777的如果没粘滞位任何用户都能删除别人的临时文件。加了 t 位以后只有文件属主、目录属主和 root 能删除。设置方法chmod t /shared/temp chmod 1777 /shared/temp3.2 umask为什么你新建的文件总是 644你可能早就注意到touch 一个新文件权限总是rw-r--r--也就是 644mkdir 一个新目录权限总是rwxr-xr-x也就是 755。这是 umask 在起作用。系统在创建文件时会请求一个默认权限文件是 666目录是 777然后让创建进程的 umask 对结果做一次“扣除”。扣除不是简单的减法而是按位取反再与运算。比如 umask 是 022二进制000 010 010对文件 6660666 ~0022 0644对目录 7770777 ~0022 0755umask 里的某一位是 1就代表新建对象对应权限位上不允许出现该权限。022 意味着属组和其他用户没有写权限但读和执行目录保留。查看当前 umask 用umask命令临时改umask 002团队协作时umask 002很有用。它意味着新建文件是 664、目录是 775属组有写权限组内同事可以直接修改你创建的文件。如果想让别人完全看不到可以用umask 077。如果希望某个目录下所有用户创建的文件都自动继承一个统一策略单靠 umask 不够。因为每个用户的 umask 由自己的 shell 配置决定。你可以在/etc/profile、/etc/bashrc或用户自己的~/.bashrc里设置但更常见的做法是配合第 3.1 节说的目录 SGID 位目录2770属组是 dev那么组内用户新建的文件自动归 dev 组再配合 umask 002文件就是 664大家都能协作。4. ACL当“三类人”不够用时用最小粒度解决问题4.1 为什么还需要 ACL 这种东西传统权限模型只有属主、属组、其他这三类角色。但真实项目里需求通常更复杂一个目录开发组要读写运维组只要读某个外包同事只允许读某一个子目录另外有一个备份用户需要读和执行但不需要写。用传统权限实现要么创建一堆中间组要么把权限放宽到“其他用户可读”最后都会变成权限漏洞。ACL访问控制列表就是来解决这个问题的。它可以给任意一个用户或组单独设置权限而不受“属主/属组/其他”这个框架限制。现代主流的 ext4、xfs、btrfs 文件系统默认都支持 ACL不需要额外做太多配置。老一点的系统可能在挂载参数里需要acl但现在默认基本都带。查看一个文件或目录的 ACL 用getfacl /srv/project设置用setfacl。比如给用户 zhangsan 读写权限给 dev 组读执行权限setfacl -m u:zhangsan:rwx /srv/project setfacl -m g:dev:r-x /srv/project-m是 modifyu:开头是用户g:开头是组。删除某一条 ACLsetfacl -x u:zhangsan /srv/project清空所有扩展 ACLsetfacl -b /srv/project4.2 默认 ACL 和 mask 的坑给目录设置默认 ACL 后目录下新建的文件或子目录会自动带上对应规则。写法是在原有条目前加一个d:setfacl -m d:u:zhangsan:rwx /srv/project这个超级实用。比如共享目录里要让 zhangsan 对以后所有新建的子目录和文件都有访问权一行默认 ACL 就搞定。否则每次新建子目录都要重新 setfacl迟早会漏。但有个概念必须理解mask。ACL 里的 mask 是所有“命名用户”和“命名组”权限的上限。ls -l 里属组那一组权限显示的就是 mask。设了一条 ACL比如u:zhangsan:rwx但目录当前的 mask 只有r-x那 zhangsan 实际生效的权限就是r-x写权限被 mask 掐掉了。想知道生效权限可以用getfacl -e查看有效权限。避免这个问题的方法是设置 ACL 时顺手把 mask 也显式设好setfacl -m m:rwx /srv/project还有一个常见坑备份和迁移。tar 备份时不加--acls不会保留 ACLrsync 同步需要加-X参数才会传输 ACL。很多人在服务器迁移后发现权限“变了”找半天才发现是 ACL 丢了。5. 实操案例给一个多角色项目目录配置细粒度权限5.1 先把需求写清楚再动命令下面我以一个常见的 Web 项目目录为例完整演示怎么落地权限配置。假设目录是/srv/project里面有代码、配置文件和日志子目录。需求是开发组 dev 对整个目录可读可写可进入并且在这个目录下新建的文件自动归 dev 组。运维组 ops 可以进入和读取所有文件但不能修改。用户 backup备份程序的服务账号可以进入并读取但也不需要写。其他用户一律无权访问。如果不用 ACL你只能要么给“其他用户”一个全局权限要么建一堆中间组。有了 ACL需求一步到位。我对这种配置的流程固定分四步先建组和用户再设传统权限位然后补 ACL最后换个用户实际验证。5.2 一步步执行并验证第一步确认用户和组存在。没有的话先建groupadd dev groupadd ops useradd -G dev zhangsan usermod -aG dev lisi注意useradd -G和usermod -aG的区别。第一次给新用户加附加组用-G没问题但给已有用户追加组一定要用-aG否则会把用户从原来的附加组里踢出去。组信息是登录时加载的如果用户已经登录改完组后需要重新登录或者执行newgrp dev临时刷新。第二步设置目录归属和传统权限mkdir -p /srv/project chown root:dev /srv/project chmod 2770 /srv/project2770里的 2 就是 SGID。目录属组设成 devSGID 保证 dev 组用户新建的每个子文件都自动归 dev 组。770 表示属主和属组都有完整权限其他用户无任何权限。第三步给 ops 组和 backup 用户加 ACLsetfacl -m g:ops:r-x /srv/project setfacl -m u:backup:r-x /srv/project setfacl -m d:g:ops:r-x /srv/project setfacl -m d:u:backup:r-x /srv/project前两条是当前目录的访问规则后两条是默认 ACL确保以后新建的子目录和文件也带上同样的规则。如果你希望 backup 用户能执行目录里某些备份脚本可以给对应脚本单独加执行权限chmod 750 /srv/project/backup.sh setfacl -m u:backup:r-x /srv/project/backup.sh第四步用getfacl确认最终结果getfacl /srv/project输出里能看到 owner 权限、mask 和若干条命名用户/命名组的 ACL。如果发现某条权限被 mask 截断再调整 masksetfacl -m m:rwx /srv/project最后要真的切换用户去验证。比如用su - zhangsan模拟开发组成员尝试在/srv/project下 touch 一个文件然后ls -l看归属确认文件属组是 dev 而不是 zhangsan 自己的主组。再用su - backup -s /bin/bash试试能不能修改文件。备份用户带-s /bin/bash是因为很多服务账号默认 shell 是/sbin/nologin不加会直接登不进去。5.3 别忘了日志目录和服务运行账号Web 项目里日志目录往往需要单独处理。你不能让代码目录里所有文件都能被开发随手改但日志目录可能需要让应用服务写入。我通常这样设计mkdir -p /srv/project/logs chown root:appuser /srv/project/logs chmod 2750 /srv/project/logs2750 表示属主和属组可读写执行其他无权限同时 SGID 让日志文件自动继承 appuser 组。然后给 dev 组只读权限setfacl -m g:dev:r-x /srv/project/logs如果应用的运行用户也需要访问代码目录但你又不想给它 shell 登录权限直接把运行用户加入 dev 组即可usermod -aG dev appuser这样服务运行时的文件读写权限和人的权限就统一管理了。6. 常见故障与排查技巧Permission denied 的完整排查思路6.1 从 id 到挂载参数一个环节一个环节查遇到权限问题时我有一套固定的排查顺序不靠瞎猜。第一步执行id确认当前用户和它所在的组。很多权限问题不是权限本身错了而是用户压根不在预期组里。改过组以后没重新登录id里看不到新组这是最常见的低级问题。第二步用ls -ld查看目标路径本身用ls -l查看文件。注意是-ld只列目录本身不是ls -l内容。第三步用getfacl看 ACL 和 mask。有时候 ls 显示的权限看起来对但 ACL mask 把命名用户的写操作拦了。第四步检查父目录链路上的每一层 x 权限。Linux 访问文件时路径上每一个目录都需要对应的执行权限少一个都进不去。比如/home/zhangsan/data/home、/home/zhangsan、/home/zhangsan/data三层都要能穿过。第五步查挂载参数。mount | grep /srv看看有没有ro、nosuid等限制。某些共享存储挂载后权限位逻辑跟本地不太一样会出现“权限明明对了但就是写不进去”的情况。第六步如果以上都查不出来看 SELinux。执行getenforce如果结果是Enforcing再看ausearch -m avc -ts recentSELinux 报的 AVC 拒绝信息会告诉你具体是什么上下文被拦截。这不是什么玄学需要区分的是SELinux 的上下文不是普通 rwx 权限它管的是进程、文件、端口的类型标签。症状可能原因排查命令处理方向能 ls 文件名但 cat 报错目录只有 r 没有 xls -ld /path给目录加 x能进目录但无法创建文件目录缺 w 或 ACL 受限getfacl /path加 w 或调 mask改了组还是没权限登录会话未刷新组id重新登录或 newgrp文件属组不对目录没设置 SGIDls -ld /dirchmod gs权限看起来是 777 但仍写不了文件系统只读或 ACL mask 限制mount、getfacl调挂载参数或 mask备份/迁移后 ACL 丢失工具未带 ACL 参数检查 tar/rsync 参数加--acls、-X6.2 我踩过的三个真实坑第一个坑是团队共享目录我图省事直接chmod -R 777。当时只是想让同事能临时放文件结果某天发现目录里多了别人上传的恶意脚本幸好没执行。后来我把共享目录改成了 2770 加 ACL再也没出过类似问题。权限这种事宽进严出永远比事后补救省心。第二个坑是给一个自研脚本加了 SUID以为这样普通用户就能以管理员身份执行。结果在 CentOS 上怎么做都不生效查了文档才知道现代系统出于安全考虑普遍忽略脚本上的 SUID。正确的做法是写一个启动器或者在 sudoers 里给指定用户精确授权。从那以后我再也没给任何脚本设置过 SUID检查系统 SUID 文件也是定期任务。第三个坑是迁移服务器时用 tar 打包解包事后发现一堆文件的属主变成了打包时的账号ACL 全丢。tar 默认并不会保存所有属性需要组合参数tar --acls --xattrs --same-owner -czf backup.tar.gz /srv/project解包时同样带上这组参数。rsync 同步时用rsync -a -X-X就是同步 ACL。7. 给新手的几条经验权限配置不是配完就算完它需要沉淀成文档和审计习惯。我每配置完一个目录都会先执行getfacl -R /srv/project /srv/project.acl.bak这种操作把当前 ACL 快照存下来。后续如果发现权限异常可以用 diff 对比快照快速定位是哪一次变更引入的问题。还有一件事我也反复提醒自己尽量不用 root 去测权限。每次配置完我习惯用不同的普通用户去实际验证一遍“我能访问”和“张三能访问”是两回事。只有模拟过不同角色的真实账号才敢确认配置生效。最后想说的是Linux 文件访问控制没有多高深核心就是权限位、特殊位、umask、ACL 这几个工具的组合使用。关键是遇到 Permission denied 时不要上来就chmod 777按照上面那套排查顺序走一遍很多问题三分钟内就能定位。多踩几次坑你就形成自己的直觉了。
返回列表