3. Rego 语言入门(一):Rego 语法基础、关键字、注释、标量类型、复合类型

Rego 是 OPA 的策略语言,专为在复杂 JSON/YAML 数据上表达策略逻辑而设计。它脱胎于 Prolog 与 Datalog,但更贴近云原生场景。本章从零开始,建立你对 Rego 语法骨架的认知。

3.1 语法基础:声明式查询与规则

Rego 是声明式语言:你描述“想要什么”,而非“如何计算”。核心单元是 规则(Rule),每条规则定义一组逻辑条件,返回一个值或布尔结果。

关键概念:Rego 中一切皆表达式,表达式求值结果为 true 或 false。规则本质是“如果条件成立,则结论成立”。

一个最简单的 Rego 规则示例:

# 规则:如果 x 大于 5,则 allowed 为 true
allowed {
    x := input.value
    x > 5
}

当 input.value 为 10 时,allowed 返回 true;否则为 undefined(即不匹配)。

3.2 关键字(Reserved Keywords)

Rego 保留以下关键字,不可用作变量名或规则名:

关键字 用途说明
package 定义策略包名,用于模块化
import 导入其他包或数据
as 配合 import 使用,起别名
default 为规则设置默认值,避免 undefined
not 逻辑取反
with 模拟数据覆盖,用于测试
some 声明局部变量,用于迭代
every 全称量词,检查集合中所有元素
if 规则条件分隔符(可选,增强可读性)
contains 用于定义集合生成规则
提示:if 和 contains 是 Rego v0.48+ 引入的语法糖,使规则更接近自然语言。旧版本使用 = 或隐式 true。

3.3 注释(Comments)

Rego 使用 # 作为单行注释,不支持多行注释块。注释应紧贴被说明的代码,保持策略可读性。

# 这是单行注释
package example

# 检查用户是否属于 admin 组
allow {
    input.role == "admin"
}

3.4 标量类型(Scalar Types)

Rego 支持四种标量类型,它们是构建复杂策略的原子单元:

类型 示例 说明
字符串 "hello"、"v1.2.3" 双引号包裹,支持转义
数字 42、3.14、-1 整数和浮点数,无精度限制
布尔值 true、false 逻辑判断基础
空值 null 表示缺失或空值

标量类型可直接用于比较和赋值:

# 标量类型使用示例
version := "1.2.3"
count := 100
is_valid := true
metadata := null

3.5 复合类型(Composite Types)

Rego 提供四种复合类型,用于建模结构化数据(如 Kubernetes 资源、CI 构建产物元数据):

类型 语法 示例 特点
对象(Object) {} {"name": "app", "ver": 1} 键值对,键必须是字符串,值任意
数组(Array) [] [1, 2, 3]、["a", "b"] 有序列表,索引从 0 开始
集合(Set) {} 但元素无重复 {"x", "y", "z"} 无序、唯一元素,无键
复合嵌套 任意组合 [{"a": [1,2]}, {"b": set()}] 对象/数组/集合可无限嵌套
注意:集合(Set)与空对象字面量语法相同 {},但 Rego 编译器会根据上下文自动区分。空集合写作 set()。

复合类型操作示例:

# 对象访问
artifact := {"name": "app.jar", "size_mb": 45}
artifact.name   # 结果为 "app.jar"

# 数组索引
tags := ["stable", "signed", "scanned"]
tags[0]         # 结果为 "stable"

# 集合成员检查
allowed_regions := {"us-east-1", "eu-west-1"}
allowed_regions["us-east-1"]  # 结果为 true

3.6 类型体系总览图

下图展示了 Rego 类型体系的层级关系,帮助你快速建立全局认知:

Rego 类型体系结构图 Rego 数据类型 标量类型(Scalar) 字符串 数字 布尔值 null 复合类型(Composite) 对象(Object) 数组 集合(Set) 复合类型可无限嵌套:对象包含数组,数组包含集合,集合包含对象…… 所有策略数据(input、data)均以复合类型传入 OPA

3.7 复合类型实战:构建产物元数据建模

在 CI/CD 流水线中,构建产物信息通常以 JSON 形式传入 OPA。下面是一个典型的数据结构,融合了所有复合类型:

# 模拟 input 数据:构建产物元数据
input := {
    "artifact": {
        "name": "backend-service.jar",
        "size_mb": 128,
        "checksum": "sha256:abc123..."
    },
    "build_info": {
        "job": "build-backend",
        "pipeline_id": "12345",
        "tags": ["production", "signed", "scanned"]
    },
    "allowed_regions": {"us-east-1", "eu-west-1", "ap-southeast-1"},
    "vulnerabilities": [
        {"cve": "CVE-2024-1234", "severity": "HIGH"},
        {"cve": "CVE-2024-5678", "severity": "MEDIUM"}
    ]
}

对应的 Rego 策略片段:

# 检查产物是否在允许区域部署
deny[msg] {
    region := input.build_info.tags[_]   # 数组迭代
    not input.allowed_regions[region]     # 集合成员检查
    msg := sprintf("区域 %v 不在允许列表中", [region])
}

# 检查是否存在高危漏洞
deny[msg] {
    vuln := input.vulnerabilities[_]
    vuln.severity == "HIGH"
    msg := sprintf("高危漏洞: %v", [vuln.cve])
}
最佳实践:在编写 Rego 策略前,先画出输入数据的 JSON 结构图,明确哪些字段是对象、数组、集合。这能大幅减少类型误用导致的策略错误。

3.8 本章小结

至此,你已掌握 Rego 的语法骨架:

  • 声明式规则:用条件描述策略,而非步骤
  • 10 个核心关键字:package、import、default、not、some、every、if、contains、as、with
  • 4 种标量类型:字符串、数字、布尔值、null
  • 3 种复合类型:对象、数组、集合,支持无限嵌套