4. OPA 与 Rego 语言入门:OPA 架构、Rego 语法基础、策略查询与数据模型
本章是 OPA 策略引擎的入门实战章节。你将理解 OPA 的组件架构、掌握 Rego 语言的核心语法,并学会如何通过数据模型与查询机制将策略集成到 Kubernetes 多集群发布流程中。学完本章,你将能够独立编写并测试基础的 OPA 策略。
4.1 OPA 整体架构
OPA(Open Policy Agent)是一个开源的、通用的策略引擎,它将策略决策与业务逻辑解耦。在云原生环境中,OPA 作为独立的服务运行,接收来自任何系统(如 API 网关、Kubernetes API Server、CI/CD 流水线)的查询请求,并基于预定义的策略和输入数据做出决策。
架构要点:OPA 将策略(Rego 代码)与数据(JSON 输入)分离。每次决策请求都包含一个
input 对象,OPA 引擎根据策略规则对 input 和内置的 data 进行求值,最终返回决策结果。
4.2 Rego 语言基础
Rego 是 OPA 专用的声明式查询语言,灵感来源于 Datalog。Rego 的核心思想是:你描述策略应该是什么样子,而不是如何执行它。Rego 中的每条规则都是一个逻辑断言。
4.2.1 基本语法元素
| 语法元素 | 说明 | 示例 |
|---|---|---|
| 包(Package) | 用于组织策略的命名空间 | package kubernetes.admission |
| 规则(Rule) | 策略的核心单元,返回布尔值或集合 | allow { input.namespace == "prod" } |
| 字面量 | 字符串、数字、布尔值、对象、数组 | "nginx", 8080, true |
| 变量 | 以 _ 或小写字母开头,不可变 |
image_name := input.containers[0].image |
| 引用(Ref) | 访问嵌套数据,使用点号或方括号 | data.roles["admin"] |
| 数组/对象推导 | 类似 Python 的列表推导式 | [x | x = input.ports[_]; x > 1024] |
4.2.2 规则类型与模式
Rego 规则主要分为两类:完整规则(Complete Rule)和部分规则(Partial Rule)。完整规则返回一个单一值;部分规则返回一个集合或对象,通常用于定义允许列表或黑名单。
# 完整规则:返回布尔值
package example
default allow = false
allow {
input.role == "admin"
input.action == "delete"
}
# 部分规则:返回一个集合
allowed_images := {"nginx:1.21", "redis:6.2", "alpine:3.15"}
valid_image {
input.image in allowed_images
}
关键概念:Rego 中的
:= 用于赋值(声明新变量),== 用于比较,= 用于统一(同时进行赋值和比较)。在规则体中,所有条件必须同时满足(逻辑与),多个规则体之间是逻辑或的关系。
4.3 策略查询与数据模型
OPA 通过 HTTP API 对外提供策略查询能力。理解数据模型是编写正确策略的前提。OPA 的数据模型分为三个层次:全局数据(data)、输入数据(input)和内置数据(built-in)。
4.3.1 数据模型层次
| 数据源 | 访问方式 | 内容说明 | 生命周期 |
|---|---|---|---|
| 全局数据(data) | data.<package>.<rule> |
所有加载的策略规则和外部数据 | 持久化,随策略加载更新 |
| 输入数据(input) | input.<field> |
每次查询请求携带的上下文 | 每次请求独立 |
| 内置数据 | builtin.<function> |
OPA 内置函数,如 regex.match |
固定,随 OPA 版本变化 |
4.3.2 查询方式
OPA 支持两种查询模式:决策查询(Decision Query)和数据查询(Data Query)。在多集群 Operator 发布场景中,最常用的是决策查询。
- 决策查询:通过
POST /v1/data/<package>发送,返回策略决策结果。适用于准入控制、权限校验等场景。 - 数据查询:通过
GET /v1/data/<path>获取 OPA 中存储的完整数据。适用于调试和审计。 - 部分求值:通过
POST /v1/compile对策略进行部分求值,生成可重用的决策条件。适用于大规模策略分发。
4.3.3 实战:编写一个简单的准入控制策略
以下示例展示了一个用于 Kubernetes 准入控制的 OPA 策略,它检查 Deployment 的镜像是否来自受信任的仓库。
# 文件: check-registry.rego
package kubernetes.admission
# 默认拒绝
default deny = false
# 定义受信任的镜像仓库前缀
trusted_registries := {
"docker.io/company/",
"registry.internal.company.com/"
}
# 拒绝规则:如果镜像不在受信任列表中,则拒绝
deny {
input.request.kind.kind == "Deployment"
some container in input.request.object.spec.template.spec.containers
not trusted_image(container.image)
}
# 辅助规则:检查镜像是否以受信任前缀开头
trusted_image(image) {
some prefix in trusted_registries
startswith(image, prefix)
}
# 允许规则:如果通过了所有拒绝检查,则允许
allow {
not deny
}
常见陷阱:Rego 中
some 关键字用于声明局部变量,在遍历数组或集合时必须使用。忘记使用 some 会导致变量作用域错误,使规则意外求值为 true 或 false。另外,注意 not 运算符的优先级,建议使用括号明确分组。
4.4 本章小结
- OPA 采用 策略与数据分离 的架构,通过 REST API 接收查询并返回决策。
- Rego 是 声明式 策略语言,规则由包、规则头和规则体组成,支持完整规则和部分规则。
- 数据模型分为
data、input和内置函数三层,理解数据来源是编写正确策略的基础。 - 查询方式包括决策查询、数据查询和部分求值,在多集群场景中决策查询最常用。
- 通过 辅助规则 和 集合推导 可以编写可读性强、易于维护的策略代码。