4. OPA 与 Rego 语言基础:OPA 架构、Rego 语法入门、基本规则编写、数据查询与决策输出
4.1 OPA 架构与核心组件
Open Policy Agent (OPA) 是一种开源的、通用策略引擎,它将策略决策与业务逻辑解耦。在云原生和 CI/CD 场景中,OPA 作为独立的服务或库运行,接收结构化的查询(输入 + 数据),输出策略决策结果。
核心设计理念: OPA 不负责执行策略(如拒绝 Pod 创建),只负责做出决策(如“是否允许该 Pod 创建”)。执行动作由调用方(如 Kubernetes API Server、CI/CD 工具)完成。
4.1.1 OPA 架构分层
4.1.2 关键组件说明
| 组件 | 角色 | CI/CD 场景示例 |
|---|---|---|
| 输入(input) | 每次查询时传入的临时数据 | 流水线构建请求的 JSON:{"kind":"Deployment","metadata":{"name":"web-app"}} |
| 数据(data) | 全局持久化数据,可热加载 | 资源配额表、团队白名单、环境标签 |
| Rego 策略 | 声明式规则集合 | deny[msg] { ... } 规则 |
| 决策输出 | 查询结果,通常为布尔值或结构化 JSON | {"allow":false,"reason":"CPU 配额超限"} |
架构要点: OPA 将策略从代码中剥离,通过统一的 input + data → decision 模型,使 CI/CD 流水线中的资源配额校验、安全合规检查、环境准入控制等策略实现集中管理和热更新。
4.2 Rego 语法入门
Rego 是 OPA 专用的声明式查询语言,灵感来源于 Datalog。Rego 的核心是规则(Rule)和查询(Query),所有逻辑都围绕“数据是什么”而非“如何计算”展开。
4.2.1 基本语法元素
| 语法元素 | 说明 | 示例 |
|---|---|---|
| 标量 | 字符串、数字、布尔值 | "prod"、42、true |
| 变量 | 以 _ 或小写字母开头 |
name、cpu_limit、_ |
| 引用 | 访问嵌套数据 | input.metadata.name、data.quotas |
| 数组/对象 | 复合数据结构 | ["a","b"]、{"key":"val"} |
| 集合推导 | 从集合中筛选 | { x | x := data.items[x.cpu > 1] } |
4.2.2 规则定义
Rego 规则分为完整规则和部分规则。完整规则返回单个值,部分规则返回集合或对象。
# 完整规则:返回布尔值
allow := true {
input.role == "admin"
}
# 部分规则:返回集合(所有违规消息)
deny[msg] {
input.cpu > data.quotas.max_cpu
msg := sprintf("CPU 配额超限: %v > %v", [input.cpu, data.quotas.max_cpu])
}
# 部分规则:返回对象
team_quotas[team] = quota {
data.teams[team]
quota := data.quotas[team]
}
常见陷阱: Rego 中变量名区分大小写,且变量一旦绑定即不可变。不要尝试在规则内对同一变量多次赋值,这会导致评估失败。
4.3 基本规则编写与数据查询
4.3.1 规则编写模式
在资源配额场景中,规则通常遵循“默认允许 + 显式拒绝”模式。OPA 的决策输出通过 allow、deny、warn 等规则名约定来组织。
# 默认允许
default allow := false
# 显式允许条件
allow {
input.namespace == "default"
input.cpu <= data.quotas.default.cpu
}
# 拒绝规则
deny[msg] {
input.cpu > data.quotas.default.cpu
msg := "CPU 请求超过默认配额"
}
deny[msg] {
input.memory > data.quotas.default.memory
msg := "内存请求超过默认配额"
}
4.3.2 数据查询与决策输出
OPA 通过 REST API 或 Go 库接收查询。查询时需提供 input 和可选的 data 覆盖。决策输出是查询路径对应的规则结果。
| 查询方式 | 请求示例 | 响应示例 |
|---|---|---|
| 完整规则查询 | POST /v1/data/example/allow |
{"result":true} |
| 部分规则查询 | POST /v1/data/example/deny |
{"result":["CPU 请求超过默认配额"]} |
| 自定义输出 | POST /v1/data/example/decision |
{"result":{"allowed":false,"reasons":[...]}} |
# 自定义决策输出规则
decision := {"allowed": allow, "reasons": deny} {
true # 始终执行
}
# 查询 /v1/data/example/decision 时返回:
# {"result":{"allowed":false,"reasons":["CPU 请求超过默认配额"]}}
CI/CD 集成要点: 在流水线中,通常将
input 设为构建请求的 JSON 描述,data 加载全局配额表。OPA 返回的 deny 集合若不为空,则流水线中断并输出错误消息。
4.4 资源配额策略的 Rego 实现示例
以下是一个完整的资源配额校验策略,适用于 CI/CD 流水线中的部署请求审核。
package deployment.quota
# 默认拒绝
default allow := false
# 允许条件:命名空间在配额表中且资源未超限
allow {
data.quotas[input.namespace]
input.cpu <= data.quotas[input.namespace].cpu_limit
input.memory <= data.quotas[input.namespace].memory_limit
}
# 拒绝原因:命名空间不存在
deny[msg] {
not data.quotas[input.namespace]
msg := sprintf("命名空间 %v 未定义配额", [input.namespace])
}
# 拒绝原因:CPU 超限
deny[msg] {
data.quotas[input.namespace]
input.cpu > data.quotas[input.namespace].cpu_limit
msg := sprintf("CPU 配额超限: %v > %v", [input.cpu, data.quotas[input.namespace].cpu_limit])
}
# 拒绝原因:内存超限
deny[msg] {
data.quotas[input.namespace]
input.memory > data.quotas[input.namespace].memory_limit
msg := sprintf("内存配额超限: %v > %v", [input.memory, data.quotas[input.namespace].memory_limit])
}
# 结构化决策输出
decision := {"allowed": allow, "reasons": deny}
4.4.1 数据与输入示例
# data.quotas 数据
{
"default": {"cpu_limit": 4, "memory_limit": 8192},
"production": {"cpu_limit": 16, "memory_limit": 32768},
"staging": {"cpu_limit": 8, "memory_limit": 16384}
}
# input 输入
{
"namespace": "production",
"cpu": 12,
"memory": 24576
}
# 决策输出
{
"allowed": true,
"reasons": []
}
最佳实践: 将配额数据存储在 OPA 的
data 层(如通过 ConfigMap 或 Bundle 加载),避免硬编码在规则中。这样更新配额时无需修改策略代码,只需更新数据源即可。
4.5 本章小结
- OPA 架构 采用分层设计:调用层 → 查询层 → 策略引擎层 → 数据层,实现策略与执行分离。
- Rego 语法 以声明式规则为核心,支持完整规则、部分规则、集合推导和自定义输出。
- 规则编写 遵循“默认拒绝 + 显式允许 + 拒绝原因”模式,确保安全合规。
- 数据查询 通过 REST API 传入
input和data,OPA 返回结构化决策结果。 - 资源配额策略 示例展示了如何在 CI/CD 流水线中校验命名空间、CPU 和内存配额。