本节摘要:Linux 每个文件有三组权限(属主、属组、其他人)各三种能力(读、写、执行),加上文件类型位构成 ls 长格式开头的十位串。本节从一次"服务读不了自己数据"的属主事故讲起,逐位拆解权限串,覆盖数字与符号两种修改方式、目录权限的特殊语义、特殊权限位与权限继承的工程实践。
某团队做存储迁移,把应用的数据目录从旧机器拷到新机器——用的是 2.4 节讲过的 tar,权限位保住了,但有一个环节出了岔子:解包时用的账号是 deploy,而应用进程用专用账号 svc-app 运行。启动服务,立刻报错:
FATAL: cannot open data file: Permission denied
权限拒绝。deploy 一看是权限问题,大手一挥:
sudo chmod -R 777 /data/app
服务果然起来了。三天后安全扫描报告标红:生产数据目录全员可写,属高危项。而更隐蔽的问题是,777 把三类人的权限全部拉满,等于把权限模型整个废掉——任何一个能登录这台机器的账号都能改业务数据。复盘时定性很清楚:为了绕过五分钟的排查,付出了系统性的安全代价。
正确解法其实只要一条命令:把属主改成应用账号即可。属主对了,权限位原样保留,各归其位:
sudo chown -R svc-app:svc-app /data/app
这个故事里 777 是反面教材,但它如此常见,以至于值得专门分析一遍为什么它总在深夜被敲出来,以及每次应该用什么替代它。
ls 长格式的第一列有十个字符,很多人背过"rwx 读写执行"就止步了,其实它结构非常工整。拿一个例子:
-rw-r----- 1 svc-app svc-app 2048 Aug 16 06:00 orders.db drwxr-x--- 2 svc-app svc-app 4096 Aug 16 06:00 backup
第一位是文件类型:横杠是普通文件,d 是目录,l 是符号链接。链接、块设备、字符设备、管道、套接字各有字母,运维最常打交道的就这三个。
后九位三个一组,分别问三个问题:属主能干什么、属组能干什么、其他所有人能干什么。每组三位从左到右是读、写、执行。第一条例子翻译成人话:普通文件;属主能读能写;属组只能读;其他人什么都不能。第二条:目录;属主全能;属组能进能列;其他人禁入。
目录的权限语义和文件不同,这是新手最大的困惑源。对目录而言,执行位的意思是"能否进入与穿越",读位是"能否列目录清单",写位是"能否在里面创建删除条目"。所以出现了一种看似矛盾的存在:一个目录你可以进入、可以读写里面的文件,却不能 ls 列表——因为你有执行位没有读位。反之,能列目录却进不去(有读无执行)也成立。判断目录权限时把三个位翻译成"进、列、增删",一切就通了。
再回看开篇事故的报错:服务进程以 svc-app 身份读 orders.db,文件属主已经是 svc-app 但属组权限只有 r 的情况之外——真实场景里是属主为 deploy 而 svc-app 落在"其他人"一组,其他人位是三个横杠,所以拒绝。权限检查的逻辑是按"你是谁"选组、按组读位,一查便知。
数字法把每组三位当二进制:r 是 4、w 是 2、x 是 1,加起来一个数字,三组三个数字。754 就是属主 rwx、属组 r-x、其他 r--。数字法快,适合批量与脚本;符号法按角色增减,语义清楚,适合精修单个位:
chmod u+x deploy.sh chmod g-w config.yaml chmod o= secrets.key
三条分别是:给属主加执行、从属组减写、把其他人的权限清零。符号法的价值在于只动指定位,不碰其他位——这在调优已有权限时比数字法安全,数字法每次都要把九位全部重写,漏想一位就改错。
属主与属组的修改用 chown,冒号分隔用户与组:
sudo chown svc-app:svc-app orders.db
只改组还有专门的 chgrp。这些修改为什么需要 root 或属主权限?因为权限模型本身就是系统安全的墙,谁能改墙谁就必须是被信任的人——这是第 4 章治理话题的引子。
⚠️ 常见坑:chmod 加 R 递归时对文件和目录一视同仁,而目录需要执行位才能进入。批量给目录加读位却没加执行位,等于把整个子树锁死。稳妥做法是用大写 X 选项代替小写 x——它只给目录与已有执行位的文件加执行,文件不会误伤。
九位之外还有三位特殊位,遇到时认得出即可。
setuid 位(属主执行位变 s):进程执行时以文件属主身份运行而非发起者身份。典型例子是改密码的命令——普通用户改密码要写 root 才能写的影子文件,靠的就是这个位。它威力大也危险,安全扫描通常盯着系统里所有 setuid 文件的清单,多出来一个陌生的就要问为什么。
setgid 位(属组执行位变 s):对目录设置后,里面新建的文件自动继承目录的属组而非创建者的主组。团队共享目录靠它统一归属,是协作场景的实用位。
粘滞位(其他人执行位变 t):设在目录上后,用户只能删除自己的文件。公共可写目录(比如临时目录)人人在里面写,但没有粘滞位的话 A 可以删 B 的文件,有了它各自的文件各自负责。ls 看到的临时目录权限串末位是 t,现在你知道它是谁了。

把本节知识串成一次标准修复。场景:应用账号 svc-app 报无法读取配置目录 /opt/app/conf,目录是 root 装包时创建的。诊断三连:
ls -ld /opt/app/conf id svc-app sudo -u svc-app cat /opt/app/conf/app.conf > /dev/null && echo 可读 || echo 不可读
drwx------ 2 root root 4096 Aug 16 05:00 /opt/app/conf uid=998(svc-app) gid=998(svc-app) groups=998(svc-app) 不可读
第一条输出说明病灶:属主 root,权限 700,svc-app 落在"其他人",权限全无。第三条用应用账号身份直接验证访问,复现报错——用当事人的身份测试,是权限排错的黄金动作,比反复脑内推演可靠。修复:
sudo chown -R root:svc-app /opt/app/conf sudo chmod -R g+rX /opt/app/conf
属组改成应用组、给组加读与大写 X 执行。再跑一次验证命令,输出"可读",收工。注意修复方案的选择:不动属主(配置文件归 root 管理更符合最小权限)、只把组权限开到恰好够用——770 都嫌多,这才是 777 的正确替代品。
临时本机调试、且机器上没有你不信任的账号时,可以用,用完改回来。除此之外没有正当场景。生产环境见到 777 应视为待修项。替代口诀:属主对、属组对、权限位开到刚好够用,三步走完 777 就没有出场机会。
三个可能。一是目录路径上某一层缺执行位——权限检查发生在整条路径的每一级,终点对了中间某层断了照样拒绝;二是文件被强制访问控制体系拦截,那套体系与这里的自主权限是叠加关系,普通权限全绿也可能被策略挡下;三是文件有不可变属性,连 root 的普通写入都会被拒。逐层查路径权限,是第一反应。
umask 决定新建文件的默认权限:新文件以全权限减去 umask 得到初始位。系统默认通常让文件落在 644、目录落在 755,对多数场景是合理起点。团队需要统一收紧(比如共享环境要 640)时再改,个人机器别折腾——默认值是几十年沉淀的平衡点。
在三位数字前面再加一位:4 是 setuid、2 是 setgid、1 是粘滞位。比如 2770 表示 setgid 加常规三组。四位数字看着唬人,拆开读就是"特殊位加九位常规",和十位串一一对应。
权限模型最终要服务于业务流程,而不是反过来。举一个完整的例子说明两者怎么咬合。一个小团队的应用发布流程:发布账号 deploy 负责解包新版本到版本目录,每个版本一个带日期的子目录;应用账号 svc-app 对版本目录只读——它能跑代码但不能改代码;发布完成后切换软链接(2.1 节的模式)指向新版本;配置文件归 root 属主、应用组只读。这套结构下,任何一个账号单点失守,破坏都被圈住:deploy 被攻破改不了运行配置(root 属主),svc-app 被攻破改不了代码本身(无写位)。权限设计的目标就是这样:让"攻陷一个账号"不等于"攻陷整个系统"。做这类设计时先画角色表——谁能读什么、谁能写什么、谁都不该碰什么——表格画完,chmod 的参数自己就出来了。先想角色后想命令,顺序不能反。
遇到 Permission denied,按顺序问四个问题:我是谁(id 看身份与组);文件认谁(ls 长格式看属主属组);我落在哪组(对照九位串找到适用组);路径全通吗(沿途每级目录的执行位)。四问答完,九成的权限问题当场定位。剩下的一成,往强制访问控制与不可变属性想。
权限话题还有一层更广的视野:本节讲的是单机权限模型,而现代系统的权限问题往往跨机器——谁能登录哪台机器、谁能访问哪个服务接口、谁能读哪个数据库表。这些问题的解法各不相同,但设计哲学一脉相承:身份明确、授权最小、动作留痕。把本节的十位权限串读懂,将来面对任何权限体系——云平台的资源策略、代码仓库的分支保护——你会发现它们都是同一个思想在不同尺度的重演。学透一个小模型,胜过浅识十个大系统。
权限模型认识透了,下一章把它放到更大的图景里——用户、组、sudo 授权,一套完整的治理体系。
再补充一个实战中的高频小场景:脚本权限。从网上下载或自己写的脚本,直接执行报"权限拒绝",九成是执行位没开。chmod 加 x 是每日动作,但要克制——给脚本加执行位前想一眼这脚本从哪来、内容看过了没有。执行位意味着"允许系统把它当程序跑",对一个来历不明的文件加执行位,等于给陌生人发了通行证。配套习惯:下载的脚本先 cat 看一遍再执行,这个动作只要十秒,却是供应链安全的第一道闸。
关于权限还有个日常沟通层面的提醒:给同事解释权限问题时,尽量用"谁能做什么"的句式而不是直接报数字。说"部署账号能读写、团队其他人只读、外人不可见",对方立刻明白;说"七百五十四",只有懂行的人能翻译。文档与工单里同理,数字写完括号里带一句人话,半年后回看省一半脑力。权限是给人用的系统,表达它的方式也该照顾人。