4. Rego语言基础(一):Rego语法基础、规则与表达式、标量值与复合值
Rego 是 OPA 的策略语言,专为在复杂环境中表达细粒度访问控制规则而设计。本章将系统讲解 Rego 的核心语法基础,包括规则与表达式的构成,以及标量值与复合值的操作方式。掌握这些基础是编写高效、可维护策略的前提。
4.1 Rego 语法基础
Rego 是一种声明式查询语言,其核心思想是 “策略即代码”。与命令式语言不同,Rego 不描述“如何做”,而是描述“应该是什么”。OPA 引擎负责将 Rego 规则与输入数据(input)和外部数据(data)进行匹配,最终输出决策结果。
4.1.1 基本语法元素
| 语法元素 | 说明 | 示例 |
|---|---|---|
| 包(Package) | 用于组织规则,避免命名冲突 | package service_mesh.authz |
| 导入(Import) | 引入外部数据或模块 | import data.service_mesh.roles |
| 规则(Rule) | 策略的核心单元,定义决策逻辑 | allow { ... } |
| 注释 | 单行使用 #,多行使用 /* */ |
# 这是注释 |
| 关键字 | 如 true、false、null、some、with |
some i; x > 0 |
提示:Rego 中的变量名必须以小写字母或下划线开头,而规则名可以大写开头。例如
allow 是规则名,user_id 是变量名。
4.1.2 包与导入机制
每个 Rego 文件通常以 package 声明开头。包路径对应 OPA 数据模型中的层级结构。例如,package service_mesh.authz 表示该文件中的规则可以通过 data.service_mesh.authz 路径访问。
package service_mesh.authz
import data.service_mesh.roles
import input.request
# 规则定义
allow {
roles[input.request.user] == "admin"
}
import 语句用于将外部数据或模块引入当前作用域。导入后,可以直接使用短名称引用,无需写完整路径。
4.2 规则与表达式
规则是 Rego 策略的基本构建块。每条规则定义了一个逻辑条件,当条件满足时,规则被评估为 true,否则为 undefined(在 Rego 中,false 和 undefined 是不同的概念)。
4.2.1 规则类型
| 规则类型 | 语法 | 返回值 | 示例 |
|---|---|---|---|
| 完整规则 | r = v { body } |
单个值 | max_score = 100 { true } |
| 部分规则 | r[x] = v { body } |
键值对集合 | user_roles[user] = role { ... } |
| 布尔规则 | r { body } |
true 或 undefined |
allow { user == "admin" } |
4.2.2 表达式与逻辑组合
规则体由一系列表达式组成,表达式之间默认是 AND 关系。可以使用 ; 或换行分隔多个表达式。OR 关系通过定义多条同名规则实现。
# AND 关系:所有条件必须同时满足
allow {
input.method == "GET"
input.path == "/api/v1/data"
input.user == "admin"
}
# OR 关系:任一条件满足即可
allow {
input.user == "admin"
}
allow {
input.user == "operator"
input.method == "POST"
}
关键点:在 Rego 中,变量一旦被赋值,在同一规则体内不能再次赋值。这称为“单一赋值”原则,有助于保持策略的确定性。
4.2.3 迭代与集合推导
使用 some 关键字可以引入局部变量进行迭代。结合集合推导,可以高效地处理列表和对象。
# 使用 some 迭代数组
has_admin {
some user
input.users[user] == "admin"
}
# 集合推导:筛选出所有管理员
admins[user] {
some user
input.users[user] == "admin"
}
4.3 标量值与复合值
Rego 支持多种数据类型,分为标量值和复合值两大类。理解这些数据类型及其操作是编写复杂策略的基础。
4.3.1 标量值
| 类型 | 说明 | 示例 |
|---|---|---|
| 字符串 | 双引号包裹的文本 | "service-a" |
| 数字 | 整数或浮点数 | 8080、3.14 |
| 布尔值 | true 或 false |
true |
| null | 空值 | null |
4.3.2 复合值
| 类型 | 语法 | 示例 |
|---|---|---|
| 对象(Object) | { "key": value } |
{"name": "svc-a", "port": 80} |
| 数组(Array) | [val1, val2, ...] |
["GET", "POST", "DELETE"] |
| 集合(Set) | { val1, val2, ... } |
{"admin", "operator"} |
注意:集合(Set)与对象(Object)都使用花括号
{},但集合的元素没有键名。Rego 通过上下文区分两者:如果花括号内的元素是键值对形式,则为对象;否则为集合。
4.3.3 复合值操作示例
# 对象访问
svc := {"name": "service-a", "port": 8080}
svc_name := svc["name"] # "service-a"
svc_port := svc.port # 8080
# 数组索引
methods := ["GET", "POST", "PUT"]
first_method := methods[0] # "GET"
# 集合成员检查
allowed_roles := {"admin", "operator"}
is_allowed := allowed_roles["admin"] # true
# 嵌套结构
topology := {
"services": [
{"name": "frontend", "upstream": ["backend"]},
{"name": "backend", "upstream": ["database"]}
]
}
frontend_upstream := topology.services[0].upstream # ["backend"]
4.4 Rego 数据模型与策略评估流程
下图展示了 Rego 策略引擎如何将输入数据与规则结合,最终输出决策结果。理解这一流程有助于定位策略编写中的问题。
4.5 本章小结
本章介绍了 Rego 语言的三大基础模块:
- 语法基础:包、导入、注释和关键字构成了 Rego 文件的骨架。
- 规则与表达式:完整规则、部分规则和布尔规则提供了不同的策略表达方式;AND/OR 逻辑组合和迭代机制使规则能够处理复杂场景。
- 标量值与复合值:字符串、数字、布尔值、null 以及对象、数组、集合构成了策略操作的数据基础。