系统设计面试:设计一个多租户授权策略服务
题干与适用场景
一个 B2B 平台有多个业务服务,每个团队都在重复实现“用户能否访问资源”的判断。现在需要统一的多租户授权策略服务,支持角色、资源关系和属性条件,策略更新后要能追踪版本,且不能因为中心服务短暂故障就让租户越权。
题目重点是授权决策链路与一致性边界。不要只画一个策略数据库;要说明调用方如何带上下文、策略如何发布、缓存何时失效,以及拒绝或超时如何影响请求。
面试官考察什么
面试官会看你能否区分策略决策点(PDP)与业务服务中的执行点(PEP),能否设计租户隔离、版本传播和可解释审计。OPA 文档强调把决策从执行代码中解耦;Zanzibar 论文则展示了在大规模授权检查中维护因果顺序与低延迟的取舍。
回答前要澄清的问题
先问请求量、延迟目标、策略复杂度、租户数量、资源关系深度和一致性要求。还要问策略作者、审批流程、撤权生效时限、是否允许离线评估、决策日志的敏感字段,以及业务服务能否安全地 fail closed。
30 秒回答框架
我会先定义授权模型和“不允许越权”的不变量,再画 PEP、PDP、策略存储、分发和审计链路。策略按租户版本化发布,PDP 在本地或同区域缓存已批准版本;请求带主体、动作、资源和必要上下文。撤权等高风险变更要求版本确认,PDP 不可用时默认拒绝敏感操作。最后用 p99 延迟、策略传播延迟、拒绝误报和审计完整性验证系统。
分步骤深入分析
第一步:定义授权对象和策略输入
统一请求形状为 subject、action、resource、context,并为资源和租户使用不可歧义的命名空间。RBAC 解决角色授予,ABAC 处理部门、设备、时间等属性,关系型授权处理“用户是文档协作者”。策略语言应能表达 allow、deny、优先级和条件,避免业务服务各自拼接规则。
第二步:划分 PEP、PDP 和策略管理面
PEP 留在 API 网关或业务服务,负责收集可信身份和执行 allow/deny;PDP 只负责评估并返回决定、策略版本和可选原因;管理面负责编辑、校验、审批、发布和回滚。OPA 将策略决策与策略执行解耦,并支持本地或网络部署;选择部署方式要结合延迟和可用性。
第三步:设计多租户存储与版本发布
策略、资源关系和属性数据都带 tenant_id,并在读取路径强制校验租户。发布生成不可变版本和校验摘要,先在沙箱评估,再分批分发到 PDP。发布记录作者、审批者、时间和影响范围;撤权或安全策略可以提高优先级,要求旧版本在短时间内失效。
第四步:处理一致性、缓存与撤权
缓存键至少包含 tenant、subject、action、resource 和 policy_version,不能只按用户 ID。允许缓存低风险 allow,但对撤权、管理员变更和敏感资源设置短 TTL 或强制版本检查。PDP 返回决策使用的版本,业务服务可以拒绝过旧版本。跨区域部署要传播版本水位,而不是假设缓存同时更新。
第五步:设计故障模式和安全默认值
PDP 超时、策略分发延迟、属性源不可用和日志管道拥塞都要有明确行为。敏感写操作、权限变更和数据导出默认 fail closed;低风险只读可在带期限的已批准缓存上继续。绝不让调用方把“网络错误”当成 allow。限制策略大小、递归关系深度和单租户 QPS,避免策略成为拒绝服务入口。
第六步:审计、可解释性与观测
每次决定记录 decision_id、租户、主体摘要、动作、资源摘要、结果、策略版本和延迟;敏感输入脱敏或哈希。日志应能回答“谁在何时依据哪个版本被允许”,同时不能成为新的数据泄露面。监控 p50/p95/p99、缓存命中、版本传播延迟、deny 比例、超时和重试;对异常 deny 或策略回滚触发告警。
高质量示范回答
我会把授权服务拆成业务服务里的 PEP、同区域 PDP 集群和独立管理面。请求携带主体、动作、资源与可信上下文;PDP 根据租户隔离的 RBAC、关系和属性策略返回 allow/deny、decisionid 和 policyversion。策略编辑先校验和测试,再生成不可变版本,按租户和区域分发,支持回滚。
缓存键包含租户、主体、动作、资源和版本。普通读取可使用短 TTL 的 allow,撤权、权限变更和数据导出要求版本确认;若 PDP 返回的版本落后于业务服务要求,调用方拒绝请求。PDP 超时或属性源不可用时,敏感操作 fail closed,不能把错误当成允许。
每个决定记录租户、主体摘要、动作、资源摘要、结果、版本和延迟,并对输入脱敏。核心指标是 p99 延迟、缓存命中率、策略传播延迟、过期版本拒绝数、错误率和审计完整性。这样既把策略从业务代码中集中管理,也保留了执行点的安全边界。
常见错误与改进
- 只有一个“权限微服务”:补出 PEP、PDP、管理面和分发链路。
- 只说 RBAC:说明属性和资源关系如何进入策略。
- 缓存只按用户:加入租户、资源、动作和策略版本。
- 超时直接放行:敏感操作应 fail closed,并区分低风险缓存。
- 日志记录完整请求:脱敏输入,保留可追踪的 decision_id 和版本。
追问及应对
How quickly must a revocation take effect?
Classify revocations by risk. For administrator, export, and sensitive-data actions, require a fresh policy version or a short bounded propagation window; lower-risk reads can use a measured TTL. State the target and monitor it.
Should PDP run locally or as a shared service?
Use local or same-zone PDP for latency and failure isolation, with a shared management plane for policy distribution. A central network PDP can simplify updates but adds a dependency to every request; choose per workload and test the failure mode.
How do you prevent one tenant from reading another tenant’s policy?
Put tenant identity in the authenticated request, enforce it in storage and cache keys, and test cross-tenant queries as a release gate. Never trust a tenant identifier supplied only by the caller payload.
How do you debug an unexpected deny?
Return a decision_id and policy version, then inspect redacted inputs, matching rules, attribute freshness, and propagation state. Do not expose sensitive policy internals to end users; give operators a controlled explanation view.