3、动态策略的核心概念

好,咱们进入第三章。这一章要聊的,是动态策略最核心的几个概念。说白了,就是搞清楚「策略怎么动起来」、「谁来做决策」、「谁来执行」。我见过不少团队,一开始就把这几个角色混在一起,结果出了问题都不知道该找谁。

3.1 什么是动态策略

动态策略,不是指策略本身会「自动变魔术」。它的核心是:策略的评估和执行,发生在运行时。

静态策略,比如你写死在配置文件里的 role: admin,系统启动时加载一次,后面就不变了。动态策略不一样——每次请求过来,系统都会根据当前上下文(用户、时间、地点、设备、风险等级……)重新算一遍。

一句话总结:静态策略是「写死」的,动态策略是「算出来」的。

举个例子。一个普通员工在工作时间访问内部CRM系统,静态策略直接放行。但如果是凌晨3点,从海外IP登录,动态策略就会触发额外校验——比如要求二次认证。这就是「运行时」的意义。

我个人习惯把动态策略拆成三个要素:

  • 策略定义:用什么规则来描述「谁在什么条件下能做什么」
  • 策略评估:在请求发生时,把规则和上下文一起算
  • 策略执行:根据评估结果,决定放行还是拒绝

这三个要素,分别对应三个关键组件:PDP、PEP,以及策略本身。咱们一个一个说。

3.2 策略决策点(PDP)

PDP,全称 Policy Decision Point。它的职责很纯粹:做决策。

你给它一个请求上下文,它给你一个决策结果。至于这个结果怎么执行,它不管。

我记得有一次帮客户做权限治理,他们自己写了一个权限校验模块,里面既写决策逻辑又写执行逻辑,耦合得死死的。后来要加一个「临时提权」的场景,改了一个月。这就是典型的PDP和PEP没分开。

PDP的核心能力包括:

  • 策略解析:把策略定义(比如JSON、YAML、或者DSL)加载成可执行的规则
  • 上下文匹配:把请求中的属性(用户角色、资源类型、环境信息)和策略条件做比对
  • 决策输出:返回 Permit、Deny、NotApplicable、Indeterminate 等结果

一个小建议:PDP 应该是无状态的。每次决策只依赖输入的上下文和策略,不依赖上一次的结果。这样才好做水平扩展。

3.3 策略执行点(PEP)

PEP,全称 Policy Enforcement Point。它的职责也很纯粹:执行决策。

PDP 说「放行」,PEP 就放行。PDP 说「拒绝」,PEP 就拒绝。它不负责判断「为什么拒绝」,只负责「怎么拒绝」。

在实际系统中,PEP 通常嵌入在网关、API 中间件、或者应用层拦截器里。比如:

  • Nginx 的 lua 脚本里调用 PDP 接口
  • Spring Cloud Gateway 的过滤器里集成 PDP 客户端
  • Kubernetes 的准入控制器里调用 OPA

我曾经踩过一个坑:PEP 在拿到 Deny 结果后,直接返回 403,但没记录任何审计日志。结果安全审计的时候,根本查不到是谁在什么时间触发了拒绝。后来我强制要求:PEP 必须把每一次决策结果(包括 Permit 和 Deny)都写入审计日志。

注意:PEP 不要自己做「二次决策」。比如 PDP 返回 Deny,PEP 觉得「这个用户好像很重要」,就偷偷放行了。这是大忌。PEP 必须无条件执行 PDP 的决策。

3.4 运行时策略评估

运行时策略评估,是动态策略的「发动机」。它发生在每次请求到达时,流程大致如下:

  1. 请求到达 PEP:用户发起访问请求
  2. PEP 构造上下文:提取用户、资源、环境等信息
  3. PEP 向 PDP 发起决策请求:带上上下文
  4. PDP 加载策略:从策略库中获取当前生效的策略
  5. PDP 执行匹配:逐条评估策略条件
  6. PDP 返回决策:Permit / Deny / 其他
  7. PEP 执行决策:放行或拒绝,并记录审计日志

这个流程看起来简单,但实际落地时,性能是关键。你想想看,每次请求都要走一遍这个流程,如果 PDP 响应慢,整个系统的延迟就上去了。

我见过一个方案:PDP 把策略编译成二进制规则,然后用缓存加速匹配。效果不错,延迟从 50ms 降到了 5ms 以内。

3.5 三者关系图

下面这张图,展示了 PDP、PEP 和策略库之间的协作关系。我建议你多看几遍,理解清楚每个组件的边界。

PDP、PEP 与策略库协作关系图 PDP、PEP 与策略库协作关系 用户/客户端 PEP 策略执行点 PDP 策略决策点 策略库 策略定义存储 审计日志 决策记录 访问请求 决策请求 决策结果 加载策略 记录日志 说明: PEP 负责拦截请求和执行业务动作,PDP 负责计算策略结果,策略库负责存储和版本管理。

3.6 核心概念对比

为了帮你快速区分这几个概念,我整理了一张对比表。嗯,这张表我建议你保存下来,做架构设计时经常用得上。

组件 职责 典型实现 常见误区
策略定义 描述权限规则 JSON、YAML、Rego、XACML 把策略写死在代码里
PDP 根据上下文做决策 OPA、AuthzForce、自研引擎 在PDP里混入执行逻辑
PEP 执行决策结果 网关过滤器、拦截器、Sidecar 绕过PDP自己做决定
运行时评估 在请求时实时计算 缓存+编译+匹配 忽略性能,导致高延迟

3.7 避坑指南

最后,分享几个我亲身踩过的坑,希望能帮你少走弯路。

我曾经犯过的错:

  • PDP 和 PEP 混在一起:导致策略变更时需要同时改两处代码,维护成本翻倍。
  • PDP 做成有状态:上线后发现决策结果依赖上一次请求,水平扩展后出现「同一个用户,不同结果」的诡异问题。
  • 忽略审计日志:被安全团队追着问「谁在什么时间访问了什么资源」,答不上来。
  • 策略库没有版本管理:有一次误删了一条策略,回滚花了两个小时。