4. 架构原理总览:控制平面与数据平面分离、策略执行点(PEP)、策略决策点(PDP)
在“策略即代码”资源配额模型中,架构设计的核心原则是控制平面与数据平面分离。这一原则将策略的决策逻辑与执行动作解耦,从而在分布式系统中实现策略的统一管理、高可用与低延迟执行。本章将详细阐述该架构的两个关键组件:策略执行点(PEP)与策略决策点(PDP),并剖析其在故障排查中的实践意义。
4.1 控制平面与数据平面分离
控制平面与数据平面的分离是构建可扩展、可维护策略系统的基石。其核心思想是将“做什么决策”与“如何执行决策”分开。
| 维度 | 控制平面(Control Plane) | 数据平面(Data Plane) |
|---|---|---|
| 核心职责 | 策略管理、决策计算、状态同步 | 策略执行、数据转发、资源调度 |
| 关键组件 | 策略决策点(PDP)、策略仓库、审计日志 | 策略执行点(PEP)、资源代理、Sidecar |
| 性能要求 | 高可用、强一致性(最终一致性可接受) | 低延迟、高吞吐、高并发 |
| 故障影响 | 策略更新延迟、新策略无法生效 | 资源请求被错误拒绝或放行,影响业务 |
| 典型技术 | OPA、Kyverno、Casbin、自定义Webhook | Kubernetes API Server、Envoy、自定义准入控制器 |
故障排查提示: 当出现策略未按预期生效时,首先应判断故障发生在控制平面还是数据平面。例如,策略更新后长时间未生效,优先排查控制平面的同步状态;若策略生效但执行结果错误,则重点排查数据平面的执行逻辑。
4.2 策略执行点(PEP)
策略执行点(Policy Enforcement Point, PEP) 是数据平面的核心组件,负责拦截资源请求,并向策略决策点(PDP)发起决策查询,根据返回的决策结果执行相应的动作(允许/拒绝/修改)。
- 位置: 通常嵌入在资源请求的必经路径上,如 Kubernetes 的准入控制器、API 网关、服务网格的 Sidecar 代理。
- 职责:
- 请求拦截: 捕获所有资源创建、更新、删除等操作。
- 上下文构建: 提取请求的元数据(用户、命名空间、资源类型、标签等),构建决策请求上下文。
- 决策查询: 将上下文发送至 PDP,等待决策结果。
- 动作执行: 根据 PDP 返回的决策(Allow/Deny/Undefined)执行相应操作,如放行、拒绝或触发告警。
- 缓存与降级: 在 PDP 不可用时,使用本地缓存策略或执行默认动作(如拒绝所有请求),防止系统雪崩。
常见故障模式: PEP 与 PDP 之间的网络延迟或中断会导致决策超时。若 PEP 未实现合理的超时与降级策略,将导致整个数据平面阻塞,引发大规模服务不可用。建议为 PEP 设置
timeout: 500ms 并配置降级策略(如 deny_on_timeout: true)。
4.3 策略决策点(PDP)
策略决策点(Policy Decision Point, PDP) 是控制平面的核心组件,负责根据预定义的策略规则和请求上下文,计算并返回决策结果。PDP 本身不执行任何动作,只负责“思考”。
- 位置: 通常作为独立服务部署,或嵌入在控制平面组件中(如 Kubernetes 的 API Server 内置的 RBAC 控制器)。
- 职责:
- 策略加载: 从策略仓库(如 ConfigMap、Git Repo、对象存储)加载最新的策略规则。
- 上下文解析: 解析 PEP 发送的请求上下文,提取决策所需的属性。
- 规则引擎执行: 使用规则引擎(如 Rego、CEL、JavaScript)匹配策略规则,计算决策结果。
- 决策返回: 将决策结果(Allow/Deny/Undefined)及可选的原因描述返回给 PEP。
- 审计日志: 记录所有决策请求与结果,用于事后审计与故障排查。
性能关键指标: PDP 的决策延迟直接影响数据平面的吞吐量。在资源配额模型中,PDP 需要处理大量并发请求。建议对 PDP 进行性能基准测试,确保 P99 延迟低于 10ms。常见优化手段包括:策略预编译、规则索引、请求上下文缓存。
4.4 架构总览:PEP 与 PDP 交互流程
下图展示了在 Kubernetes 环境中,PEP(准入控制器)与 PDP(OPA 策略引擎)之间的典型交互流程。
4.5 故障排查实践要点
理解 PEP 与 PDP 的分离架构后,故障排查可以更有针对性。以下是几个关键实践要点:
- 链路追踪: 在 PEP 与 PDP 之间注入 Trace ID,实现请求级别的全链路追踪。当决策结果异常时,可以快速定位是 PEP 的上下文构建错误,还是 PDP 的策略计算错误。
- 决策日志: PDP 应输出详细的决策日志,包括输入上下文、匹配的策略规则、决策结果及原因。这是排查“为什么拒绝”或“为什么允许”的第一手资料。
- 策略模拟: 在 PDP 中提供策略模拟接口(Dry-Run),允许运维人员在不影响生产环境的情况下,测试策略变更的效果。这能有效避免因策略错误导致的大规模故障。
- 缓存一致性: 当 PEP 启用本地缓存时,需关注缓存与 PDP 最新策略的一致性。缓存过期时间(TTL)设置不当会导致策略生效延迟。建议使用 Watch 机制或短 TTL(如 30s)来保证时效性。
代码示例:PEP 请求 PDP 的伪代码(Go 风格)
// PEP 端决策查询
func enforce(ctx context.Context, req *Request) (*Decision, error) {
// 构建决策上下文
input := map[string]interface{}{
"user": req.User,
"action": req.Action,
"resource": req.Resource,
"namespace": req.Namespace,
}
// 向 PDP 发起查询,设置超时
ctx, cancel := context.WithTimeout(ctx, 500*time.Millisecond)
defer cancel()
decision, err := pdpClient.Query(ctx, "resource_quota", input)
if err != nil {
// 降级策略:超时或 PDP 不可用时,默认拒绝
log.Warn("PDP query failed, applying deny-by-default", "error", err)
return &Decision{Action: Deny, Reason: "PDP unavailable"}, nil
}
return decision, nil
}
4.6 架构总结
控制平面与数据平面的分离,以及 PEP 与 PDP 的明确分工,为策略即代码模型提供了坚实的架构基础。这种设计不仅提升了系统的可扩展性与可维护性,还为故障排查提供了清晰的边界:
- 数据平面故障: 表现为 PEP 执行异常,如请求被错误拦截或放行。排查重点在 PEP 的配置、网络连通性、缓存状态。
- 控制平面故障: 表现为策略更新不生效或决策结果错误。排查重点在 PDP 的策略加载、规则引擎执行、审计日志。