主题
03 - 权限隔离与删除传播
一句话:权限必须在检索之前发生而不是在结果里筛,删除必须追上向量、缓存和已经发出去的引用三条路径而不是只删库里的行;代价是延迟与止血的不对称——拒服务秒级、清索引分钟级、备份副本只能等保留期,所以必须另备一个能立刻停下一整个知识域的开关。
一、谁负责判权限
判断“这次请求能看到哪些内容”发生在 Knowledge Broker,一个数据面上的独立服务,不是网关插件,也不是市场平台的一部分。
分工只有一句:网关知道自己是谁在调用、市场知道谁订阅了什么,只有 Broker 知道这份文档的这一段你能不能看。把这件事塞进网关插件,等于把所有策略写进同一份配置,改一处要整体发版;塞进市场平台,等于让控制面站到调用链路上,市场发布会直接打断检索。
引擎侧也有权限字段,那是存储层兜底,不是企业授权边界:企业授权变化频繁、粒度到文档与密级,引擎的账号级隔离跟不上。
二、粒度:露在外面的三级,藏在里面的三级
| 层级 | 是否对产品可见 | 作用 |
|---|---|---|
| 租户 | 是 | 企业级隔离,跨租户绝对不可见 |
| 项目 / 工作空间 | 是 | 部门与业务线级别的资源归属 |
| 知识库 | 是 | 授权与订阅的基本单位 |
| 文档 | 部分(共享 / 私有两态) | 单篇可见性 |
| 密级 | 否,只做服务端过滤与降权 | 内部 / 机密 / 受限三档 |
| 生效状态与权威源 | 否,只做服务端过滤 | 现行 / 待复审 / 已废止;该主题的权威源是哪一份 |
密级不外露是有意的:一旦给客户端一个“密级筛选器”,就等于允许有人试探更高一档的内容。同一逻辑也管拒答回执——涉密内容被过滤时统一回“无结果”,“因权限未纳入”这句话只进管理台与审计。否则一句诚实的拒答就成了存在性探测器,能被人用来枚举哪些机密文档存在。
代价随之而来:业务方会问“明明有这份文件为什么查不到”。处置是把排查做成管理台的正式能力(按请求标识查被过滤原因),而不是在用户侧松口。
检索范围由 Broker 派生,不接受客户端指定。 注入检索请求的过滤条件共六项:租户、项目、文档、密级、生效状态、权威源标记。请求里带的知识库 ID、租户 ID、用户 ID 一律按当前签名上下文重新计算,客户端传的值不参与决定能看到什么。
“废止不召回”与“冲突提示”都靠这六项执行,不靠删库:删了就查不到,但“保留可追溯、被追问历史时受控给出”这两件事会同时失效。同理,答案里提示“该主题存在多个说法”也依赖权威源标记随检索结果返回,否则只能靠模型自觉,不可测也不可验收。
三、动作维度:能看不等于能改,更不等于能给别人看
权限不止可见性一维。生产上必须分开四个动作,合成一格就会出事:
| 动作 | 含义 | 谁能持有 |
|---|---|---|
| 只读 | 检索与问答可见 | 按知识域授权 |
| 编辑 | 上传、改写、下线文档 | 内容负责人 |
| 发布 | 让文档进入默认检索、变更权威源标记 | 知识库管理员 |
| 转授 | 把可见范围扩给他人、他部门,或让某个 Agent 接入 | 数据所属部门负责人,且需管理员会签 |
管理台侧要有明确的角色权限矩阵并默认拒绝:有哪些角色、每个角色能点哪些端点、未列组合一律拒绝。只写“管理端点按角色白名单放行”不够——角色集合与改白名单的权限落在谁手里,这两问答不上来等于没有矩阵。上表的“双人会签”必须是系统强制(两个不同主体分别签署,缺一不生效),不能是流程约定(同一个工单上点两次同意)。
四、自报字段一律不认
身份来源只有一条:网关验证企业身份体系签发的令牌后,派生出租户、主体、消费者三个标识,向下游传递。下游收到与签名上下文不一致的自报字段,直接拒绝,并记一条审计。
不选“静默忽略”而选“拒绝”,理由是失败方式不同:忽略会让调用方以为自己传的窄范围生效了,实际落到更宽的范围,出事后两边日志都对得上,只有结果错;拒绝会在第一次调用就暴露问题,代价是存量调用方要改错误处理分支。
请求头上同类字段在入口直接剥离,不允许覆盖平台注入的值——这条规则跟“不信任客户端”是同一件事的两面。拒绝事件本身也带主体标识,属个人信息处理,保留期按第十节的统一口径管,不因“只是个 403”而豁免。
五、临时授权:必须带过期,过期还要追引用
跨部门查一次敏感资料,正确解法不是永久扩权,而是临时授权。它要有四条语义,缺一条就会变成长期授权:
| 要素 | 约定 |
|---|---|
| 有效期 | 必带截止时间,不设永久默认;到期由系统回收,不靠人记得去收 |
| 权限版本 | 每一次授予与回收都推进权限快照版本,缓存随之整体失效 |
| 范围 | 到知识域或文档集,不给整库;转授不在临时授权能力内 |
| 到期之后 | 已发出的引用按新版本复核,失效即变占位提示——否则临时授权在会话历史里永久留存 |
六、删除要追上三条路径
删一份文档、撤一个人的权限、回收一个订阅,动作不同,但都必须落到同样三个地方:
- 向量与元数据:先写墓碑标记不可召回,再由异步任务物理删除,任务记录影响条数与完成时间;保留期内可查“删到哪了”。
- 缓存:缓存键强制包含租户、密级与权限版本号。版本号一涨,旧键结果整体作废,不需要精确定位哪些缓存属于这份文档——精确失效看似更省,实际总会漏掉一条。
- 引用:会话历史里已经给出的引用不删用户读过的原文,但渲染时按当前权限复核,失效就替换为占位提示。答案本身是用户读过的内容,硬删会让会话变得不可解释;这条与个人信息的删除权存在真实冲突,处置见第十一节。
收敛窗口的四段口径(目标值与状态分列,不混成一句话):
| 阶段 | 目标 | 当前状态 |
|---|---|---|
| 停止新调用可见 | 秒级,量级十秒内 | 设计目标,待演练确认 |
| 缓存不再返回旧结果 | 不超过版本刷新周期,分钟以内 | 设计目标 |
| 向量与元数据物理清理 | 分钟级(与解析队列同档) | 设计目标 |
| 备份内副本 | 不宣称立即消失,到期销毁密钥 | 依赖保留期策略,见第十一节 |
把这四件事混成一句“删除已生效”,是这类系统最常见的一句话事故。
法务保留是这套状态机上唯一的例外:标记为保留的文档物理删除被挡住,只停用可见性,且保留审批与删除审批必须是两个人。
七、紧急切断:止血动作要单独设计
前几节都默认判定链是活的。真实事故需要第三种动作:不问原因,立刻停——发现某文档正在被越权读取、某知识域内容整体存疑、某上游连接被滥用时,需要的是分钟级以内的止血。
生产形态是两下,不需要自研开关:
- 网关侧下掉该知识产品 / 该租户 / 该工具的路由,入口秒级切断;
- Broker 侧把对应权限快照版本置为失效,已发出的引用与缓存同时不再可信。
配套三件,缺一等于没做:
- 生效计时:从执行到“同一条查询返回无结果”的实测耗时进验收证据(见 06),不能只写在预案里;
- 降级语义:Broker 或权限源不可用时按 fail-closed 处理——拿不到快照就拒绝。这条必须用演练验证,不是术语表里的定义;它的真实代价是控制面抖动会放大成全员不可用,要提前与业务约定提示语与恢复顺序;
- 故障表补两行:Broker 故障、审计存储故障各自“必须不丢什么、允许丢什么”。审计存储不可用时宁可阻塞放行也不能丢事件,这条与其他组件不同,得单独写。
八、入库扫描与内容合规审核是两件事
上一版把两件事混在一起写了,它们防的对象不同、由谁提供也不同。
| 层 | 防什么 | 谁提供 | 落点 |
|---|---|---|---|
| 注入与恶意特征扫描 | 文档内容反过来指挥模型、文件本身有害 | 自研检查 + 病毒扫描 | 命中进隔离数据集,不参与默认检索 |
| 内容合规审核 | 涉政、暴恐、侵权与无授权转载、可再用许可缺失、个人信息裸露 | 引擎不提供,需外部内容安全服务或人工判定 | 入库前判定 + 出口侧对生成内容再校验一次 |
一句诚实话:RAGFlow 不提供内容审核能力。这一层要么接入外部服务并写清“命中即隔离或拒答、误放行留审计”,要么如实写“尚未承担”,并在入库四分里把高风险内容类型直接拒收(见 08)。把毒文档防护当内容安全,是私有化场景里最容易被法务一票否决的地方。
出口侧还有一条与防泄漏直接相关:答案不复述原文整段。引用只回片段标识与页码坐标,正文按段限量取回,单主体对单文档设累计取回量阈值,超阈值触发二次授权;整篇导出不是工具面动作,走管理台,需独立授权与双人确认,并在审计里记“累计取回量”字段。缺这条,四个只读动作循环一遍就能拼出整篇——只读权限不等于不可导出。
九、来路可疑的文档先进隔离区
默认策略:入库前扫描(格式白名单、大小与页数上限、恶意特征、合规检查);命中注入或合规问题进隔离数据集,不参与默认检索,等人工判定;外部来源(网页、网盘同步、第三方系统)一律按“数据”处理,其内容不作为指令执行,回答时也不照抄其中的指示性文字;可信度低的来源在检索打分里降权;管理员强制放行必须留审计。
代价两条:误拦会把正常文档挡在库外,业务会当成“东西丢了”,所以隔离区必须可查、可解释;外部依赖新增一次,出站策略就要改一次,这条运维成本不会因为“只是个文档系统”而免除。
十、三本账对不上时以谁为准
| 记录 | 内容 | 权威范围 |
|---|---|---|
| 网关计量事件 | 谁、以何身份、调了哪个工具、结果码、用量 | 调用事实与计量的唯一权威源 |
| Broker 决策记录 | 放行了什么范围、过滤掉多少、拒绝原因 | 权限决策的权威 |
| 引擎日志 | 检索参数、命中片段 | 仅作补充证据 |
对账不平以网关事件为准,下游可以重放聚合,不允许反向改原始账本。三本账粒度天然不同——网关看不见“这次过滤掉几段”,所以要先定义可接受差异,再谈对账,否则天天误报。拒绝事件单独标记:不计费,但要能按调用方统计拒绝率,撤订后仍在打的就是从这里看出来的。
审计要能回答一句话:“谁在什么时候,以谁的身份、用谁的工具,取走了哪份文档哪一段、哪一版。”最小字段:身份三件套、产品与订阅、权限版本号、工具名、查询哈希、文档与片段 ID、页码与坐标、密级与生效状态、决策与原因、返回条数、累计取回量、耗时。原文与个人信息不进审计表,只存哈希或加密快照;表本身只追加,应用账号没有改删权限。
十一、个人信息与保留期:三处各管各的
三张表各自存的东西不同,不能共用一句“按企业规则处理”。
| 数据 | 存什么 | 保留与删除规则 |
|---|---|---|
| 审计表 | 决策与字段,不含原文 | 按合规年限,只追加;到期清理需留证据 |
| 会话历史 | 用户读过的答案与引用标识 | 用户可行使删除权;删除只影响历史展示,不撤销已发生的事实(事实在审计表里) |
| 引用快照 | 片段标识 + 版本 + 哈希,不缓存正文 | 渲染时按当前权限复核;撤权后变占位,原文不额外留存 |
加密快照仍属个人信息——能打开就能还原,因此必须写清谁能走脱敏查看这条路径、审批人是谁、密钥归谁,“按角色脱敏查看”在没有角色清单前等于没写。
保留期四要素,缺一即不可执行:谁定义(合规角色,不是平台默认)、配在哪(单一配置项,不散落各服务)、谁执行(到期清理任务及其监控)、如何证明(到期清理的留档证据)。“备份副本到期销毁密钥即可”这句是否等同法律意义上的删除,属法务判定,不由架构默认成立。
十二、旁路要一次堵干净
四件事是一套,缺任意一件其余三件形同虚设:
- 网络策略默认拒绝,客户端只能到网关,引擎管理端口与内部端口不对用户网段开放;
- 引擎与模型服务的密钥由密钥系统托管、在网关或 Broker 注入,员工与 Agent 手里只有平台凭证;
- 出站访问走显式允许清单与受控代理,带解析后地址校验与 DNS 重绑定防护——引擎自带的出站限制是护栏,不能改代码绕过去;
- 管理入口独立收口,带多因素与临时授权通道,公开端点逐项复核。
代价讲明白:每加一个外部依赖都要改一次出站策略,代理抖动会直接打断解析和向量化任务。这套东西不会让系统变快,它只是把已经识别出的越权路径变成有明确判定点的设计问题——密级标错、入库时权限归位失败这类,仍要靠抽检兜住,不能说从此没有越权。