4. OPA 策略引擎基础:Rego 语言简介、OPA 架构、数据与查询模型
在云原生安全基线体系中,OPA(Open Policy Agent)是策略决策的核心引擎。本章将深入 OPA 的底层原理,包括其声明式策略语言 Rego、组件化架构以及独特的数据与查询模型,为后续在 Istio 中集成 OPA 进行容量水位巡检奠定基础。
4.1 OPA 整体架构与组件
OPA 采用解耦的“策略决策”与“策略执行”分离架构。它本身不执行任何操作(如拒绝请求、杀死 Pod),而是根据输入和策略数据返回决策结果(Allow/Deny)。
核心架构组件:
- 服务(Service):对外暴露 HTTP/gRPC 接口,接收来自 Envoy、Kubernete API Server 或其他客户端的查询请求。
- 策略引擎(Engine):核心决策单元,加载并评估 Rego 策略。
- 数据存储(Data Store):存储基础策略数据(如白名单、配额、集群状态快照),支持 Bundle 拉取和增量更新。
- Bundle 系统:将策略和数据打包为 tar.gz 文件,通过 HTTP 或 OCI 分发至 OPA 实例。
- 决策日志(Decision Logs):记录每一次策略评估的输入、输出和元数据,用于审计和调试。
架构要点:OPA 不存储业务数据,只存储策略和策略依赖的静态数据(如集群节点数、Pod 资源限制)。业务数据(如当前 CPU 使用率)通过查询请求的
input 字段传入。
4.2 Rego 语言基础
Rego 是 OPA 的声明式查询语言,灵感来源于 Datalog。它专注于“策略即代码”,通过规则(Rules)定义策略逻辑。
4.2.1 核心语法元素
| 元素 | 语法示例 | 说明 |
|---|---|---|
| 规则(Rule) | allow { input.role == "admin" } |
定义一条策略规则,当条件满足时规则为真。 |
| 变量(Variable) | user := input.user |
使用 := 声明并赋值局部变量。 |
| 迭代(Iteration) | some i; input.items[i].value > 10 |
使用 some 关键字遍历集合或数组。 |
| 默认值(Default) | default allow = false |
为规则设置默认值,避免未定义错误。 |
| 内置函数(Built-in) | count(input.pods) > 5 |
提供 count、split、time.now_ns 等函数。 |
4.2.2 完整策略示例:检查 Pod 资源限制
package istio.capacity
# 默认拒绝
default allow = false
# 规则:如果 Pod 设置了 CPU 和内存限制,则允许
allow {
input.kind == "Pod"
input.spec.containers[_].resources.limits.cpu
input.spec.containers[_].resources.limits.memory
}
# 规则:如果 Pod 没有设置限制,生成一条违规消息
violation[msg] {
input.kind == "Pod"
container := input.spec.containers[_]
not container.resources.limits.cpu
msg := sprintf("容器 %v 未设置 CPU 限制", [container.name])
}
violation[msg] {
input.kind == "Pod"
container := input.spec.containers[_]
not container.resources.limits.memory
msg := sprintf("容器 %v 未设置内存限制", [container.name])
}
常见陷阱:Rego 中的
_ 是匿名变量,用于忽略不需要的值。在迭代容器时,input.spec.containers[_] 会匹配所有容器,但不会绑定具体索引。如果需要索引,使用 some i; input.spec.containers[i]。
4.3 数据与查询模型
OPA 的数据模型分为三个层次:全局数据(data)、输入数据(input)和规则输出(output)。理解这三者的关系是编写正确策略的前提。
4.3.1 数据层次对比
| 层次 | 来源 | 生命周期 | 典型内容 |
|---|---|---|---|
| data | Bundle 加载、API 推送、文件加载 | 持久化,随 OPA 重启或 Bundle 更新而变 | 集群节点列表、服务白名单、配额阈值 |
| input | 每次查询请求的 JSON 负载 | 仅当前请求有效 | 当前 Pod 的 CPU 使用率、请求的 HTTP 方法 |
| 规则输出 | Rego 规则评估结果 | 每次查询动态计算 | allow、violation、deny 等自定义规则 |
4.3.2 查询模型:Partial Evaluation 与完整评估
OPA 支持两种查询模式:
- 完整评估(Full Evaluation):客户端发送完整
input,OPA 返回最终决策(true/false)。适用于实时准入控制。 - 部分评估(Partial Evaluation):客户端不提供
input,OPA 返回一个“剩余条件”表达式。适用于预计算和策略编译优化。
4.4 策略分发与 Bundle 机制
在生产环境中,OPA 策略通过 Bundle 进行分发。Bundle 是一个包含策略文件(.rego)和数据文件(.json)的压缩包,OPA 客户端定期从远端 Bundle 服务器拉取并加载。
Bundle 结构示例:
bundle.tar.gz
├── .manifest # 元数据文件,包含版本号、根包名
├── policies/
│ ├── main.rego # 主策略文件
│ └── utils.rego # 工具函数
└── data/
├── clusters.json # 集群静态数据
└── quotas.json # 配额数据
OPA 支持多种 Bundle 分发方式:
- HTTP Bundle:OPA 定期轮询 HTTP 端点,下载并解压 Bundle。
- OCI Bundle:将 Bundle 打包为 OCI 镜像,通过容器镜像仓库分发。
- Kubernetes ConfigMap:将 Bundle 内容挂载为 ConfigMap,OPA 通过文件系统监听变化。
最佳实践:在 Istio 容量巡检场景中,建议将集群节点规格、Pod 资源配额等静态数据放在 Bundle 的
data/ 目录中,将实时 CPU/内存使用率通过 input 传入。这样既保证了策略的灵活性,又避免了频繁更新 Bundle。