策略即代码、准入控制与细粒度授权工具
一家内容协作平台把下载权限写在页面按钮和单个详情接口里,普通成员从页面上确实看不到下载入口。后来团队增加批量导出任务,后台消费者直接按项目 ID 读取对象存储,没有调用原来的授权判断。攻击者只需构造自己所属项目的导出请求,就能夹带不属于自己的附件。身份认证、网关登录和配置扫描都显示正常,事故仍然发生,因为真正产生副作用的执行点没有消费授权决定。
另一家企业在外包人员离场后删除了目录组关系,身份系统也立即禁止新登录;已经建立的长连接、网关 allow 缓存和关系授权副本却继续接受旧身份。安全团队在控制台看到“撤销成功”,业务端仍能读取敏感报表。问题不是少了一条 deny 规则,而是撤销事实、策略版本、数据新鲜度、缓存失效和连接终止没有共同的完成定义。
先认清一次授权到底发生了什么
认证回答“调用者是谁”,授权回答“这个主体能否在此刻对这个资源执行这个动作”。最小请求不是一个模糊的 role=admin,而是 principal / action / resource / context 四元组。principal 来自服务端验证过的身份;action 是稳定的业务动作,如 invoice.approve,而不是随路由变化的 HTTP 方法;resource 带类型、标识和必要的业务版本;context 只放策略真正依赖且来源可信的环境事实。
请求进入策略决策点 PDP 后,策略 policy 与事实数据 data 在一个明确 revision 或 snapshot 上产生 decision。策略可以表达规则,数据可以来自目录、关系图、业务属性或环境信号;二者版本不同,结果就不可比较。PDP 只负责计算。API 中间件、RPC interceptor、消息 consumer、批量任务和长连接上的策略执行点 PEP 才负责阻止副作用。PDP 返回 allow 而 PEP 没执行,等价于没有授权保护。
trusted identity + server-side resource + normalized action + trusted context
-> policy revision + data snapshot
-> PDP: allow | deny | error + reason + freshness
-> PEP: enforce before side effect
-> audit: decision_id + revision + PEP result
-> revocation: invalidate caches and in-flight access一条可审计链至少能把 request_id、decision_id、PEP 标识、策略或模型 revision、数据新鲜度、决定和实际执行结果关联起来。日志不能记录 bearer token、完整 JWT、原始关系路径或资源内容。安全团队需要知道“谁在什么版本下被允许”,不需要把全部敏感输入复制到日志平台。
四类工具解决的是四种不同问题
配置合规检查处理静态或渲染后的文件:输入是 Terraform、Kubernetes YAML、Dockerfile 或供应链清单,结果通常进入本地命令、pre-commit 或 CI。Conftest 与 OPA/Rego 很适合回答“这份配置是否违反团队规则”,但 CI 通过不会自动保护运行中的 API,也不会扫描已经绕过流水线创建的对象。
Kubernetes 准入发生在 API Server 持久化资源之前。ValidatingAdmissionPolicy/CEL、Gatekeeper 和 Kyverno 判断的是 Kubernetes 请求与对象,并可补充存量审计、变更或生成能力。它们的 PEP 是准入链,不是业务服务里的“用户能否下载合同”。一个 Pod 被允许创建,也不代表 Pod 内的调用者拥有业务数据权限。
嵌入式授权把 PDP 放进应用进程或紧邻应用的运行时。Cedar、Casbin 以及相应的托管或混合方案适合低延迟的属性、角色和领域规则。好处是网络跳转少,代价是宿主必须负责策略分发、快照原子切换、多实例收敛、日志和故障语义。语言或库能算出结果,不代表完整控制平面已经存在。
集中式关系授权把 object / relation / subject 关系作为一等数据,擅长对象共享、组织继承、组嵌套以及“列出我能访问的资源”。OpenFGA 与 SpiceDB 适合 ReBAC 和反向查询,但不能因此被当成任意业务规则语言。复杂风险评分、时段限制与关系图组合时,可能需要策略引擎和权限数据库协作;组合链任一依赖失败都不能被另一路宽泛 permit 静默覆盖。
因此不能用“规则数量”“DSL 是否易读”或单次延迟把四类工具横向排成一张总榜。它们保护的对象、执行时机、数据模型、列表能力、新鲜度语义和故障半径不同。正确的比较单位是同一个业务风险在候选架构中的完整证据链,而不是产品功能勾选数。
从一条最小正反路径开始
初次接入可以选一个无敏感数据的测试资源 document:demo,服务端从测试身份解析 user:alice,把 document.read 映射到唯一 action。正向路径授予 Alice 阅读关系或满足 permit 条件,经真实 PEP 请求资源,预期业务读取成功,并能用同一 decision_id 找到 PDP revision 与 PEP 执行记录。
反向路径不能只测“换个用户名得到 deny”。依次测试未登录主体、跨租户资源、未知 action、缺少强制 context、PDP timeout、畸形响应、旧 revision 和旁路后端地址;所有路径都不得产生读取、写入或导出副作用。随后撤销授权,用候选工具支持的新鲜度机制循环请求,直到同一会话和已建立连接稳定拒绝,记录从权威撤销提交到 PEP 拒绝的时长。
{
"principal": { "type": "user", "id": "alice" },
"action": "document.read",
"resource": { "type": "document", "id": "demo" },
"context": { "tenant": "sandbox", "purpose": "verification" },
"expected": "deny_after_revocation"
}这组实验不依赖某个特定 DSL,却能暴露 action 映射遗漏、跨租户缓存、错误时放行、旧策略副本和撤销不完整。真实落地时应固定引擎版本、策略或模型 revision、数据 snapshot、输入摘要、退出码和预期结果,由隔离环境运行并保存产物;文档中的示例是测试合同,不是运行结果。
接进项目时先封住所有副作用入口
项目应提供窄而稳定的授权接口,例如 authorize(principal, action, resource, context),业务代码不能自行拼接角色字符串。主体从认证中间件取得,tenant 与 resource 由服务端查询,action 由 endpoint、RPC、consumer 到业务动作的版本化映射生成。浏览器传来的 user_id、tenant、owner 或模型 ID 都不能直接成为可信事实。
PEP 清单要覆盖同步 API、批量导出、异步任务、定时器、后台管理接口、GraphQL resolver、文件直链和长连接。列表接口还要验证查询结果与单项 Check 语义一致,避免“页面逐项过滤正确、导出先拉全库再漏过滤”。当 PDP 返回 deny、error、timeout、未知 obligation 或缺 revision 时,高风险动作默认失败关闭;错误与拒绝在监控上分开,在执行上都不放行。
策略和关系变更不要在请求线程里做脆弱的双写。业务事实先与 outbox 或意图日志一并提交,再由幂等 consumer 更新授权系统;资源在关系确认前保持不可见。删除路径先阻断新访问,再清关系、内容和缓存。这样才能区分“业务提交成功但授权同步待处理”和“授权已生效”,也为重放、补偿与回滚留下状态。
选型要看执行时机、数据形状和新鲜度
如果目标是阻止不合规配置进入仓库或流水线,先选配置策略测试;如果目标是阻止不合规 Kubernetes 对象被 API Server 接受,进入准入策略;如果每次业务调用都需要低延迟属性判断且规则规模可控,评估嵌入式 PDP;如果核心问题是大规模对象共享、继承和反向列表,再评估集中式关系授权。
接着比较部署故障域。本地或 sidecar PDP 能在控制服务短暂断网时继续按已签名快照决策,但要承担大量实例的 revision 收敛;集中服务便于统一数据与审计,却把网络、负载均衡和 datastore 纳入每次授权延迟。选型记录必须包含 PEP timeout 预算、允许的旧版本年龄、撤销暴露目标、列表峰值、策略发布方式和退出数据格式。
只有当属性规则与关系图都不可替代时才组合两套系统。组合前先固定求值顺序:关系系统返回最小关系事实,策略引擎组合可信 context;任一依赖错误时得到 deny/error。不要为了“未来可能复杂”提前引入双系统,额外的 revision、缓存、日志、迁移和 on-call 成本往往比 DSL 差异更早拖垮团队。
故障要按证据层分型
“策略测试通过但线上越权”先查 PEP 覆盖和 action 映射,不要先改策略;“刚撤销仍 allow”先查目标 revision、新鲜度模式、各层缓存与长连接,不要靠等待固定秒数;“多副本结果不同”先按 revision 摘除旧副本,不能用多数投票掩盖版本分裂;“List 与 Check 不一致”要核对模型、分页 snapshot、context 和业务后过滤。
PDP 返回 200 也可能是错误结果,健康检查必须包含已知请求的深度探针。新策略激活失败时保留上一批准 revision,但高风险 action 超过最大旧版本年龄后应拒绝或摘流。日志后端故障可以使用有界缓冲,缓冲积压、丢弃和恢复要有指标;不能让无限队列拖垮授权进程,也不能把日志失败自动解释为允许。
权限、容量、成本和长期治理
策略仓写权限、策略发布权限、关系写权限、决策日志读取权限和审计删除权限应分离。生产服务使用短期工作负载身份或可轮换凭证,禁止把管理 token 放进业务配置和示例。break-glass 使用独立强身份、窄 action、短时有效、双人批准和自动回收,PDP 故障不能自动把普通请求升级为紧急权限。
容量模型至少拆出决策 QPS、列表 QPS、策略大小、关系总量、关系写入速率、图深度与分支、PIP 延迟、缓存命中率、审计事件量和撤销事件峰值。平均延迟不足以定容,要观察 p95/p99、超时率、旧 revision 实例数、影子队列丢弃率和撤销完成时间。成本还包括 datastore、跨区流量、日志索引、策略评审、业务改造、值班与迁移退出,不能只比较授权服务节点价格。
团队发布策略时固定不可变 revision,经过正反 fixture、历史语料回放、差异分类和影子流量,再按 tenant、action、resource type 小步切换。一个未解释的 deny -> allow 就应阻断,不可被总体一致率掩盖。退出时必须能导出策略或模型、关系与实体、PEP action 映射、租户映射、黄金语料、审计保留和凭证撤销清单;只有源码而没有生效 revision 证据,无法重建真实授权系统。
沿着问题进入 23 个学习单元
下面的路径按决策问题组织。总览提供共同语言;四个子家族分别处理策略运行时、Kubernetes 准入、嵌入式授权和集中式关系授权;最后三篇收束发布、一致性与生命周期治理。
策略即代码、准入控制与细粒度授权工具。授权策略证据模型与工具选型。策略运行时与策略工程
OPA 与 Rego。OPA 部署、Bundle 与决策日志。Conftest 配置策略测试
Kubernetes 准入策略。ValidatingAdmissionPolicy 与 CEL。Gatekeeper
Kyverno。VAP、Gatekeeper 与 Kyverno 选型迁移。嵌入式应用授权
Cedar。Casbin。Oso Cloud 与 Polar
集中式细粒度授权。Zanzibar 风格 ReBAC 建模。OpenFGA
