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 策略引擎如何将输入数据与规则结合,最终输出决策结果。理解这一流程有助于定位策略编写中的问题。

Rego 策略评估流程 输入数据 input.request 外部数据 data.roles Rego 规则 package service_mesh.authz allow { ... } OPA 策略引擎 规则匹配与决策 决策输出 输入:HTTP请求、用户信息 服务网格流量属性 外部:角色定义、策略库 服务拓扑信息

4.5 本章小结

本章介绍了 Rego 语言的三大基础模块:

  • 语法基础:包、导入、注释和关键字构成了 Rego 文件的骨架。
  • 规则与表达式:完整规则、部分规则和布尔规则提供了不同的策略表达方式;AND/OR 逻辑组合和迭代机制使规则能够处理复杂场景。
  • 标量值与复合值:字符串、数字、布尔值、null 以及对象、数组、集合构成了策略操作的数据基础。