1 为何先弄清「谁在访问」
在 S6 中,你已经能用终端定位路径、看退出状态,也能把命令接进管道。现在遇到 Permission denied,先别反复换命令。路径存在,只表示系统里有这个名字;当前进程能否走到它、能否读取它,还要经过权限检查。排查的起点是把“我想操作什么”补成“哪个身份,沿哪条路径,对哪个对象,做什么操作”。
例如,云主机控制台显示你是实例的管理者,并不意味着 SSH 登录后的 Linux 用户就是 root。镜像可能默认创建 ubuntu、ec2-user 或 deploy,让它们通过受控的 sudo 规则管理系统。这是云平台账号和主机内账号的分工:前者决定谁能管理云资源,后者决定进程在操作系统里能做什么。SSH 密钥证明你有权登录某个账号,也不会把那个账号自动变成管理员。
$ whoami
deploy
$ id -u
1001
$ cat /etc/shadow
cat: /etc/shadow: Permission denied
这里拒绝读取口令相关文件是合理边界,不能据此判断 SSH 登录失败。也不要因为 cat 失败就先改文件权限:业务日志、服务配置、私钥的访问要求本来就不同。先确认对象的用途,再判断这个用户是否应该有读取能力,才知道拒绝是在保护系统,还是配置漏了一步。
最小权限是一种日常运维习惯:看日志只获得读日志的能力,部署只获得必要的发布能力,修改系统配置才临时提权。它能缩小误操作影响,也让交接记录说得清楚。记录“给 deploy 所在的 app 组读取日志的权限”,比记录“权限有问题,改到能用了”更容易复查。
本课的样例采用 Linux 上的本地用户、普通文件和目录;用户名与编号属于示例主机。以下终端块是教学用的示例记录,不要求你在真实服务器上创建同名账号。每次分析都先用 id 固定访问者,再读路径和权限;如果基础权限已经允许但仍失败,再寻找额外规则。

2 用户、组与身份:uid、gid
账号是系统保存的身份记录,进程则带着凭据运行。账号名方便人记忆,内核进行常规文件权限检查时主要依据数字:uid 标识用户,gid 标识组。文件也保存数字形式的属主和属组;ls 通常把数字翻译成名字。名字相同但来自不同主机,不能保证数字相同,迁移文件后看到意外的属主时尤其要注意这一点。
$ id
uid=1001(deploy) gid=1001(deploy) groups=1001(deploy),27(sudo)
$ id -u
1001
$ id -G
1001 27
这份输出中,deploy 的 uid 是 1001,主组的 gid 是 1001,组集合里还包含 sudo。主组通常参与决定新建文件的属组,但父目录的继承规则等设置也可能影响结果;它不是访问现有文件时唯一能匹配的组。附加组让同一用户同时参与多个协作范围,例如部署组和日志阅读组。检查现有文件的组权限时,进程的主组和附加组都可能匹配文件属组。
/etc/passwd 可以理解为本地账号的索引,其中记录名字、uid、主 gid、家目录和登录 shell 等信息。例如 1 条记录可以是 deploy:x:1001:1001:Deploy user:/home/deploy:/bin/bash。这里的 x 不是权限位,也不是明文密码;本课不需要打印整个文件。附加组的信息通常另有来源,企业主机还可能通过集中身份服务查询账号,不能仅凭这条记录断言全部组关系。
需要特别区分“账号数据库已更新”和“现有进程已拿到新凭据”。管理员把 deploy 加入 app 组后,早先启动的 SSH shell 不会自动刷新它的附加组列表。从这个旧 shell 启动的命令一般继续继承旧列表。id deploy 查询指定账号的组信息,裸 id 则观察当前执行进程继承的身份;两者暂时不同并不奇怪。权限修复后应建立新的登录会话,并在那个会话里运行裸 id。
服务进程也是如此。你用 deploy 登录,不代表应用也以 deploy 运行;服务可能一直以 app 身份工作。排查时要问清楚报错来自交互命令、部署工具还是服务本身。把登录者的 id 当成所有进程的身份,会让本来正确的权限看起来难以解释。
如果变更的是服务账号的组,重新登录 deploy 并不会更新已经运行的应用。应按服务管理流程,在允许的维护时机让服务重新取得凭据,并核对新进程的实际身份;不要为了验证一次权限变更就随意中断生产任务。账号记录、交互会话、后台进程是相关但不同的观察对象,排查记录应写明你检查了哪一个。
3 权限位:r、w、x 对文件与目录的不同含义
r、w、x 的含义取决于对象类型。普通文件的 r 允许读取数据,w 允许修改数据,包括截断或重写内容,x 允许把文件作为程序执行。给文本加 x 不会替它生成有效的程序格式;执行脚本还涉及解释器能否读取内容等条件。反过来,只想查看日志,通常不需要给日志文件加 x。
目录保存名字到对象的关联,因而它的权限管理的是目录中的条目。目录 r 允许列举名字,目录 x 允许搜索、穿过目录并访问已知名字的对象,目录 w 允许更改条目,例如创建、删除或重命名。实际创建和删除通常还需要该目录的 x。把目录的 x 简单理解成“执行这个文件夹”,容易错过路径访问的关键。
| 权限 | 普通文件 | 目录 |
|---|---|---|
| r | 读取数据 | 列举条目名字 |
| w | 改写、截断数据 | 更改条目,通常配合 x |
| x | 尝试作为程序执行 | 搜索名字、进入和穿过目录 |
目录有 x、没有 r 时,知道确切文件名的人可能仍能访问那个文件,但不能随意列目录。目录有 r、没有 x 时,可能看见名字,却无法取得条目的完整属性或读取内容。因此,看到名字不等于能打开文件,列目录失败也不等于每个已知文件都无法访问。
$ ls -ld notes
drwx--x--- 2 app app 4096 Oct 29 10:00 notes
$ ls notes
ls: cannot open directory 'notes': Permission denied
$ cat notes/status.txt
service ready
上例假设访问者属于 app 组,且 status.txt 本身允许该组读取。组在 notes 上只有 x,所以按已知路径读取成功,列名字失败。若文件没有组读权限,最后的 cat 仍会被拒绝。每一层回答不同问题,不能把目录和文件权限互相替代。
删除文件也值得单独辨认:删除通常是修改父目录条目,而不是改写文件内容。即使文件不可写,拥有父目录相应权限的人仍可能删除它;即使文件可写,没有父目录的相应权限也未必能删除它。把重要文件设为只读,并不能代替保护其父目录。
例如某个练习目录为 deploy 所有且模式为 700,内部 draft.txt 为 deploy 所有且模式为 400。直接重写这个文件会因缺少文件 w 被拒绝,但 deploy 仍能删除目录中的这个名字,因为父目录允许它修改条目。这里假定没有 sticky bit、不可变属性等额外限制。验证时应在可丢弃的练习目录观察,并把“改写内容”和“删除名字”分别记为不同动作;不能拿删除成功证明文件内容可写,也不能拿文件只读推断备份一定安全。
共享目录还可能有 sticky bit,在 ls -ld /tmp 中常见末尾的 t。它为删除或重命名增加规则:即使大家都能在目录里创建条目,通常也只有文件属主、目录属主或具有相应特权的进程能删除或重命名该条目。这是共享目录的删除规则,不会让其中的文件内容自动保密。

4 读权限:ls -l 与符号/八进制表示
先把一行长列表拆开读。ls -l 的信息依次包括类型与权限、硬链接数、属主、属组、大小、修改时间和名字。普通文件首字符是 -,目录是 d;后面的 9 个位置分成属主、属组、其他人各 3 位。权限字符串后的 + 可能提示扩展 ACL,需要另查,不能当成多出的一位 rwx。
$ ls -ld /var/log/app /var/log/app/app.log
drwxr-x--- 2 app app 4096 Oct 29 10:00 /var/log/app
-rw-r----- 1 app app 128 Oct 29 10:02 /var/log/app/app.log
第 2 行文件的属主 app 有 rw,属组 app 有 r,其他人没有权限。符号表示里,u 指属主,g 指属组,o 指其他人,a 指这 3 类。这里的 u 不是“当前执行命令的用户”:你执行 chmod u+w 时,改变的是目标对象属主这一栏。
八进制用 r=4、w=2、x=1 相加,每位数字对应一类。644 拆成 6、4、4,即 rw-r--r--:属主可读写,属组和其他人只读。755 拆成 7、5、5,即 rwxr-xr-x:属主全部允许,另外 2 类可读与执行或搜索。600 是 rw-------,只让属主读写,常用于由单个账号使用的私钥。640 则是 rw-r-----,适合明确的组内只读共享。
这些数字不能脱离对象类型判断。755 用于目录时,允许其他人列名字并穿过;用于程序时,允许其他人读取和执行。600 用于私钥文件可以合理,用于需要进入的目录则连属主也缺 x。同样的数字表达相同位,产生的操作含义却不同。
普通权限检查按身份选择一栏:如果进程的有效 uid 匹配属主,就检查 u;否则若进程的有效 gid 或附加组匹配属组,就检查 g;都不匹配才检查 o。选中后不会因为该栏不允许,就继续借用另一栏。假设一个文件为 ----r-----,属主没有读权限,组有读权限;属主自己的普通进程仍不能靠“我也在这个组里”绕过去。实际系统的 ACL 和特权会补充这套模型,但不能把普通 3 栏理解成任选其一。

5 改权限与属主:chmod、chown 的边界
chmod 改权限位,不改身份。文件属主通常可以修改自己的文件权限,具有相应特权的管理员也可以修改;仅仅属于文件的组,并不意味着你可以执行 chmod。下例在练习目录中由属主操作:先用符号方式表达“让组能读、撤掉其他人的读”,再用八进制方式完整指定普通权限。
$ ls -l settings.conf
-rw-r--r-- 1 deploy deploy 96 Oct 29 10:10 settings.conf
$ chmod g+r,o-r settings.conf
$ ls -l settings.conf
-rw-r----- 1 deploy deploy 96 Oct 29 10:10 settings.conf
$ chmod 600 settings.conf
$ ls -l settings.conf
-rw------- 1 deploy deploy 96 Oct 29 10:10 settings.conf
符号方式适合表达有限变化,未指明的位保持原样;八进制方式适合落实已经明确的目标模式。例如想保留现有执行位而仅增加组读,使用 g+r 更能表达意图。想把一份仅供属主使用的普通配置固定为 600,数字方式更便于复核。不要为了记住数字而忽略目标对象,批量把目录也改成 600 会立刻破坏进入能力。
chown 改属主或属组。普通用户不能随意把文件转让给另一个用户;改变属主通常需要管理员权限。属主在条件允许时可用 chgrp 把文件改到自己所属的组。涉及服务账号时,先确认目标用户和组存在,再由有权执行的管理员完成修改,并立即检查结果。
$ ls -l /srv/app/settings.conf
-rw-r----- 1 deploy deploy 96 Oct 29 10:10 /srv/app/settings.conf
$ sudo chown root:app /srv/app/settings.conf
$ ls -l /srv/app/settings.conf
-rw-r----- 1 root app 96 Oct 29 10:10 /srv/app/settings.conf
修改后 app 组可读但不能写,root 是属主。若 deploy 不属于 app,它也许从此读不了刚才创建的文件,这正说明属主与权限是一起决定访问结果的。别把 chown 当成没有副作用的“整理名字”。
保存文件时也要观察工具实际执行的动作。有的程序直接打开原文件并改写,需要文件的 w;有的编辑器先在同目录创建临时文件,再重命名覆盖原路径,还需要父目录的 w 与 x。因此“文件明明可写,编辑器却保存失败”并不矛盾。先看报错是否指向临时文件或重命名,再决定该改文件还是目录,不能只把原文件的写位加上后就宣布修复。
递归操作前必须核实树的边界。chown -R 作用于错误路径,可能把发布目录之外的配置、数据和密钥都换掉属主。至少先打印工作目录,用明确的目标路径检查 ls -ld,记录原来的属主、属组和模式;涉及挂载点或链接的树还要先理解其结构。本课的修复都指向明确对象,不靠扩大权限来掩盖身份判断错误。
6 root、sudo 与最小权限习惯
root 的 uid 是 0。这个数字身份在通常的主机环境中拥有广泛特权,许多普通文件权限拒绝对它不起同样作用;但不能因此认为所有操作都必然成功,文件系统只读挂载等条件依然可能阻止写入。本课用普通用户观察报错,再在必要时提权检查或修改,避免让管理员能力遮住真正的问题。
sudo 是受策略约束的提权入口,不是“这一行看起来危险就加上”的前缀。常见用法只把某次命令以 root 身份执行,命令结束后原来的 shell 仍是普通用户。是否允许执行、是否要求认证,由主机的 sudo 策略决定。
$ id -u
1001
$ sudo id -u
0
$ id -u
1001
很多主机要求输入调用者自己的密码来确认身份,而不是索取 root 密码。策略也可能配置 NOPASSWD,让某些授权命令无需再次输入密码;已有认证缓存也可能使一次 sudo 没有提示。没有密码提示不代表所有命令都获准,更不能据此推断当前 shell 已经变成 root。
在共享主机上,每个人日常直接登录 root 是值得追问的信号。大家共享同一个身份时,文件很容易变成只有 root 能维护,也更难从账号层面区分操作者。普通账号登录、按需 sudo,能保留工作的身份上下文,并减少把系统路径误当练习目录的机会。sudo 的命令记录能帮助追溯,但并不是完整审计的替代品。
例如读取业务日志失败,应先确定你是否属于日志阅读组。sudo cat 可能证明管理员能读,却没有证明普通用户权限修复成功。如果你的工作长期要求读这些日志,应设置适当的组访问边界;如果只是获准进行一次应急检查,可以按既有管理流程临时提权。验证修复时始终回到实际报错的身份,否则“管理员能做”会被误记成“用户已经能做”。
7 常见坑:目录缺 x、组不对、误 chmod 777
访问 /var/log/app/app.log 时,要先穿过 /、/var、/var/log 和 /var/log/app,然后才轮到文件的读权限。每个父目录都需要匹配身份下的 x,哪怕文件本身是 644。目录的 r 主要服务于列名字,知道完整路径时并不要求所有父目录都能列举。排查“能看到文件名却打不开”,应逐层找搜索权限的断点。
$ ls -ld /var/log/app
drwxr----- 2 app app 4096 Oct 29 10:20 /var/log/app
$ cat /var/log/app/app.log
cat: /var/log/app/app.log: Permission denied
若访问者属于 app 组,这里的 r-- 依然缺 x。不要只盯着最后一个文件加读权限,它还没有机会参与检查。逐层查看路径,比在当前目录不断重试更有用。相对路径还受当前工作目录影响,因此把报错命令中的相对路径换算清楚,也是承接 S6 的必要步骤。

另一类常见情况是文件属组正确,但访问者不在该组,或者旧 shell 还保留旧凭据。管理员说“已经加过组”之后,应检查新会话的裸 id,而不是仅凭用户名猜测。更改组前也要确认这个组代表的权限范围:加入 app 组可能同时开放其他配置和目录,不能只看眼前的单个日志。
777 会向所有人开放读、写、执行或搜索,尤其是全员可写目录,会扩大创建、替换和删除条目的能力。某些依赖配置或发布文件的程序,还可能读入别人替换的内容。把文件设成 777 也无法解释原先究竟在哪层失败,因此它既扩大影响,也抹掉了排查线索。正确处理应针对缺失的身份或权限位,并保留变更前状态。
家目录 755 也需要结合内容判断。它允许其他用户列出顶层文件名并穿过目录,即使私钥内容被 600 保护,项目名、备份名等仍可能暴露。若确实只供本人使用,可考虑 700;但先确认 Web 服务或协作者是否需要穿过该目录。目录权限不能只凭“这个数字常见”决定,开放名字、开放内容和允许改动是不同的需求。
8 案例:同一文件两人结果不同
1 台主机上,app 账号运行应用,deploy 账号负责发布。应用持续写入 /var/log/app/app.log,app 自己能读取,deploy 却收到拒绝。管理员先确认这里的日志不含限制 deploy 查看之外的敏感信息,且 app 组就是这台主机约定的运维阅读组;随后对照双方身份和对象属性。
$ id
uid=1001(deploy) gid=1001(deploy) groups=1001(deploy),27(sudo)
$ ls -ld /var/log/app /var/log/app/app.log
drwxr-xr-x 2 app app 4096 Oct 29 10:30 /var/log/app
-rw-r----- 1 app app 128 Oct 29 10:31 /var/log/app/app.log
$ cat /var/log/app/app.log
cat: /var/log/app/app.log: Permission denied
本例的父目录均允许 deploy 穿过,问题落在文件上。文件模式是 640,属主和属组都是 app。deploy 的 uid 不匹配属主,组集合也没有 app,只能按 o 的 --- 判断。app 的进程匹配属主 rw-,所以读到的是同一份内容,却得到不同结果。这不是命令行为不稳定,而是检查时输入的身份不同。
管理员确认授权后执行下面的成员变更。-aG 中的 -a 表示追加附加组;省掉它,使用 -G 重新设置列表,可能意外移除原有附加组。组成员变更是账号管理操作,需要相应权限,不由日志阅读者自行绕过。
$ sudo usermod -aG app deploy
$ id deploy
uid=1001(deploy) gid=1001(deploy) groups=1001(deploy),27(sudo),1002(app)
deploy 保留原连接以防交接中断,另外建立新的 SSH 登录。在新连接里验证当前凭据,再读取原路径:
$ id
uid=1001(deploy) gid=1001(deploy) groups=1001(deploy),27(sudo),1002(app)
$ cat /var/log/app/app.log
2026-10-29T10:31:00+08:00 INFO service ready
文件仍为 640,改变的是访问者匹配到的类别。这个结果只授予 app 组读,不授予 deploy 写日志内容;应用仍通过属主的 w 写入。实际服务还要检查日志轮转是否继续生成 app:app、640 的新文件,否则今天可读、轮转后又失败,说明生成规则和访问方案还没有保持一致。
为什么新日志会丢掉组读权限?没有默认 ACL 时,新文件的普通权限由创建程序请求的模式再扣除进程 umask 中屏蔽的位。例如程序请求 666,umask 为 027,结果就是 640;若 umask 为 077,结果则是 600,deploy 即使仍属于 app 组也读不了。umask 不是给权限做加法:程序若只请求 600,把 umask 改为 027 也不会替它增加组读位。它也不会追溯修改已经存在的文件。
因此要区分谁创建了下一份日志。应用自行新建时,应检查应用进程的 umask 和创建方式;轮转工具创建替代文件时,应检查其创建模式与属主、属组设置。在 deploy 的终端里运行 umask 027,只会影响这个 shell 及随后继承它的子进程,不能改变已运行服务或独立轮转任务的行为。验收应在受控轮转后重新检查新日志的属性,并分别确认 app 能继续写、deploy 能读且不能写;若服务仍持有旧日志的打开句柄,还需按服务支持的方式重新打开日志,避免把旧文件仍在增长误判为新文件权限正确。
9 排查案例:Permission denied 却说不清卡在哪一层
另 1 台主机也有同名路径,同事能看日志,deploy 不能。这里重新取证,不能照搬上一例的结论。同事可能是文件属主,也可能用了 sudo;“同事可以”只是比较线索。下面每个块都标明执行身份,命令后的输出按同一次现场状态组织。
第 1 步在报错的 deploy 会话里重现,并固定进程凭据。主组和附加组中已经有 app,说明“漏加组”不能直接作为本次结论。
$ cat /var/log/app/app.log
cat: /var/log/app/app.log: Permission denied
$ id
uid=1001(deploy) gid=1001(deploy) groups=1001(deploy),27(sudo),1002(app)
$ id -u
1001
$ id -G
1001 27 1002
第 2 步查看路径各层。ls -ld 的 -d 查看目录自身,避免把目录内容列表误当成目录权限。deploy 能检查 app 目录条目,但不能穿过它来取得内部文件属性;因此这一块保留了真实的失败,而不是假装普通用户总能列出整条路径。
$ ls -ld /var /var/log /var/log/app /var/log/app/app.log
ls: cannot access '/var/log/app/app.log': Permission denied
drwxr-xr-x 14 root root 4096 Oct 29 09:00 /var
drwxr-xr-x 10 root root 4096 Oct 29 09:00 /var/log
drwxr----- 2 app app 4096 Oct 29 10:40 /var/log/app
第 3 步用 namei -l 按路径逐层显示,补上容易忽略的根目录。此命令在部分精简系统中没有预装,可以改为逐个 ls -ld 检查 / 以及后续目录。这里最深处的拒绝与上一块一致。
$ namei -l /var/log/app/app.log
f: /var/log/app/app.log
drwxr-xr-x root root /
drwxr-xr-x root root var
drwxr-xr-x root root log
drwxr----- app app app
app.log - Permission denied
第 4 步由有权管理员补查对象元数据,用 stat 固定数字模式,避免漏看字符位置。普通 deploy 当前不能取得文件属性,所以这次使用 sudo 只为了取证;它不代表 deploy 已能读日志。stat 给出的 app 目录 740 与文件 640,是定位所需的最后 2 项证据。
$ sudo stat -c '%a %U %G %n' / /var /var/log /var/log/app /var/log/app/app.log
755 root root /
755 root root /var
755 root root /var/log
740 app app /var/log/app
640 app app /var/log/app/app.log
把排查分成 4 个分支,就能解释下一步依据。先查所有父目录对该身份是否有 x;有任意一层缺失,先修这一层。父目录都能穿过,再查文件是否给选中的类别 r;例如 app 组成员遇到 600 文件,组读位确实缺失。如果文件有 g+r,但访问者组列表不含 app,就回到成员授权与会话刷新。如果这些证据都应允许却仍被拒绝,再考虑 ACL 等额外访问规则,不能无限重复 chmod。
每修复一层,都用同一身份重复原来的读取命令。父目录缺 x 与文件缺 r 可以同时存在,第一处修复后出现新的拒绝,不一定说明前一步无效。保留前后输出,继续向路径深处核对即可。这样的顺序也避免一次改动多处后无法判断哪项真正必要;若对象一直由程序重新生成,还要核对失败文件是不是已被新对象替换。
本次 deploy 匹配 app 组,根目录、var 和 log 都可穿过,app 目录的组位却是 r--。文件已有 g+r,权限检查在到达它之前就停了。修复是为这个目录补组搜索权限;不需要扩大文件权限,更不需要换属主。经确认 app 组确实应该访问该目录,管理员记录原模式 740,执行:
$ sudo chmod g+x /var/log/app
$ ls -ld /var/log/app /var/log/app/app.log
drwxr-x--- 2 app app 4096 Oct 29 10:40 /var/log/app
-rw-r----- 1 app app 128 Oct 29 10:41 /var/log/app/app.log
$ stat -c '%a %U %G %n' /var/log/app /var/log/app/app.log
750 app app /var/log/app
640 app app /var/log/app/app.log
若现场核实目录和普通日志文件都缺少计划内的组读权限,可以对这 2 个明确对象使用 sudo chmod g+rX /var/log/app /var/log/app/app.log。大写 X 只对目录,或原先已有任意执行位的文件,增加相应执行位;本例普通日志原为 640,所以不会因此变成可执行文件。它不修改属组,也不能修复路径上其他目录的问题;使用前仍要检查每个目标的原状态。
修复后另开普通用户 shell 检验,尤其在同时发生过组成员变更时,新登录能避免旧凭据干扰。本次只改了目录模式,本来就属于 app 的进程无需靠重新登录获得这个权限,但仍要把验证身份写清楚。
$ id
uid=1001(deploy) gid=1001(deploy) groups=1001(deploy),27(sudo),1002(app)
$ cat /var/log/app/app.log
2026-10-29T10:41:00+08:00 INFO service ready
$ stat -c '%a %U %G %n' /var/log/app/app.log
640 app app /var/log/app/app.log
ACL 只在需要时补查。例如 ls -l 带 +,或者普通权限预测与现场结果不符,可请管理员执行 getfacl -p /var/log/app /var/log/app/app.log。命名用户或组的 ACL 条目以及 mask 会影响有效权限;某个命名用户条目也可能使“按属组应能读”的推断失效。没有安装该工具不意味着没有 ACL。若 ACL 也无法解释,再交由管理员核查安全模块等限制,不在没有证据时扩大普通权限。
工单最终应写明:deploy 当前已属于 app;原目录 740 缺 g+x,改为 750;文件保持 640;普通会话读取成功。明确记录没有采用 chmod -R 777:递归开放会波及不相关文件,并向其他人交出写入能力。修复的价值在于把一次拒绝解释清楚,并留下可复查的授权变化。
放进方案里
给一个小服务写运行方案时,先把访问者分成管理员、应用账号 app 和部署账号 deploy,再列出对象与动作。以下矩阵假设 deploy 已获准加入 app 组,因此也能读取组内配置;若配置含不应交给部署者的秘密,就必须拆分组或交付方式,不能继续套用同一组。私钥由 deploy 单独使用,不交给应用进程。
| 对象 | 属主:属组 | 模式 | 允许的主要动作 |
|---|---|---|---|
/etc/app/service.conf | root:app | 640 | 管理员修改,app 组读取 |
/var/log/app/app.log | app:app | 640 | app 写入,app 组读取 |
/home/deploy/.ssh/deploy_key | deploy:deploy | 600 | deploy 读取和维护 |
矩阵还要配父目录约定:/etc/app 为 root:app、750,/var/log/app 为 app:app、750,deploy 的家目录与 .ssh 均为 deploy 所有、700。把这些路径逐层写清,能避免文件模式正确但仍走不到目标。日志轮转和发布流程应保留约定的属组与模式,新建对象也要纳入验收。
验收在实际使用者的新登录或相应运行环境中进行。先用 id 记录用户与组,再用 ls -ld 查看矩阵对象及父目录,用 namei -l 确认整条路径;允许读取的对象要实际读取,私钥只验证可读状态,不把内容打印进工单。还应以未授权的测试账号确认配置和日志读取被拒绝,并确认 deploy 不能改写只读配置,避免只验证成功路径。没有专门测试账号时,记录尚未完成的反向验收,不用管理员身份代替。
变更前保存各对象的模式、属主、属组及已有 ACL。发现过度开放时,按对象恢复到已记录的目标状态,再复验允许与拒绝2 类操作;若撤销组成员资格,要处理仍带旧组凭据的会话或进程。私钥一旦可能被别人读取,收回权限只能阻止后续访问,还需按密钥流程更换并撤销旧凭据。方案最后留下执行者、时间、验证身份与结果,让维护者能够复现判断。
10 小结:走向 S8
用户与权限问题,要先固定进程身份,再沿路径定位访问被拒绝的位置。uid、gid 和附加组决定匹配哪类普通权限,目录的搜索权限与文件的读写权限分别负责不同环节。chmod 修改权限位,chown 修改归属,sudo 则让一次操作使用获准的提权身份。把修复限制在明确对象和所缺能力,并用原报错身份复验,才能把“能用了”变成有依据的交付。S8 将进入 shell 脚本基础,把这些身份、路径和模式检查组织成可以重复执行的检查步骤。
下一课转向 S8 Shell 基础:把本章验收过的结论带进后续主题,写成可检查的方案约束。