2. Rego语言基础:Rego语法概览、规则定义、查询与数据模型

Rego 是 Open Policy Agent (OPA) 的策略语言,专为在云原生环境中表达策略而设计。它脱胎于 Datalog,是一种声明式查询语言。理解 Rego 的语法、规则定义方式、查询机制以及数据模型,是编写有效策略即代码(Policy as Code)的基石。本章将系统性地介绍这些核心概念,为后续与 Helm Chart 的集成实战打下坚实基础。

2.1 Rego语法概览

Rego 的语法简洁且高度可读,其核心思想是“将策略视为对数据的查询”。一个 Rego 文件(通常以 .rego 为后缀)由 包声明、导入语句 和 规则定义 组成。

关键语法特征:
  • 声明式: 你描述“想要什么”,而非“如何计算”。
  • 基于文档模型: 输入(input)和数据(data)都是嵌套的 JSON 文档。
  • 不可变数据: 变量一旦被赋值,在同一作用域内不可更改。
  • 迭代与推导: 使用 some 关键字进行迭代,使用推导式(Comprehensions)构建集合。
语法元素 示例 说明
包声明 package kubernetes.admission 定义规则所属的命名空间,用于组织策略。
导入 import data.kubernetes.pods 导入其他包中的数据或规则,简化引用路径。
注释 # 这是一条注释 单行注释,用于解释策略逻辑。
标量值 "nginx", 80, true 字符串、数字、布尔值。
复合值 {"name": "app", "port": 8080} 对象(Object)、数组(Array)、集合(Set)。
变量 deployment_name 以字母或下划线开头,用于绑定值。
引用 input.request.operation 通过点号或方括号访问嵌套文档中的值。
数组推导式 [x | x := data.containers[_]; x.image] 从集合中筛选并转换数据,生成新数组。

2.2 规则定义:策略的核心

规则是 Rego 的基本构建块。一个规则定义了一个布尔值、一个值或一个集合。规则可以是有条件的,也可以是无条件的。

2.2.1 规则类型

  • 完整规则(Complete Rules): 为规则名赋予一个单一值。如果规则体为真,则规则为真;否则为假(或未定义)。
  • 部分规则(Partial Rules): 定义一个从键到值的映射,类似于一个函数或字典。常用于定义允许的操作列表或配置映射。
  • 默认规则(Default Rules): 为规则提供一个默认值,当其他规则体都不满足时使用,避免未定义错误。
最佳实践: 在编写策略时,优先使用部分规则来构建可组合的策略片段,然后使用完整规则进行聚合判断。这有助于提高策略的可读性和可维护性。
# 完整规则:判断是否允许部署
package example

default allow = false  # 默认拒绝

allow = true {        # 如果满足以下条件,则允许
    input.request.operation == "CREATE"
    input.request.kind == "Deployment"
    input.request.name == "allowed-app"
}

# 部分规则:定义允许的镜像仓库列表
allowed_registries = {"docker.io/verified", "gcr.io/my-company"}

# 部分规则:检查镜像是否来自允许的仓库
valid_image(image) = true {
    registry := split(image, "/")[0]
    allowed_registries[registry]
}

# 完整规则:结合部分规则进行决策
allow = true {
    input.request.operation == "CREATE"
    valid_image(input.request.object.spec.template.spec.containers[_].image)
}

2.2.2 规则体与表达式

规则体由一系列表达式组成,表达式之间是逻辑与(AND)关系。如果所有表达式都为真,则规则体为真。表达式可以是:

  • 等式: x = 5 或 x == 5。在 Rego 中,= 用于赋值和比较,== 仅用于比较。
  • 不等式: x != 5
  • 比较: x > 3, y <= 10
  • 成员关系: x = ["a", "b"][_] 或 "a" in ["a", "b"]
  • 函数调用: count(list) > 0, split(image, "/")

2.3 查询与数据模型

Rego 的策略评估本质上是一个查询过程。OPA 将输入文档(input)和外部数据(data)加载到内存中,然后执行 Rego 查询,返回结果。

2.3.1 数据模型:input 与 data

理解 input 和 data 的层级结构是编写策略的前提。

  • input: 代表当前请求的上下文。在 Kubernetes 准入控制场景中,它通常是 AdmissionReview 对象的 JSON 表示,包含 request.operation、request.object(被操作的资源)等字段。
  • data: 代表 OPA 加载的所有外部数据。这包括:
    • 通过 opa run -d 加载的 JSON 或 YAML 文件。
    • 通过 Bundle API 分发的策略包和数据。
    • 通过 data.kubernetes.* 路径访问的 Kubernetes 集群状态(当 OPA 与 Kubernetes 集成时)。
Rego 数据模型与查询流程 input (请求上下文) data (外部数据与策略) 规则 (Rules) (策略逻辑) 查询引擎 (评估与推导) 查询结果 (布尔值/对象/集合) 说明 策略即是对 input 和 data 的查询

2.3.2 查询示例

假设我们有一个简单的 Rego 策略,用于检查 Deployment 的副本数是否大于 3:

package example

# 规则:检查副本数是否合规
replica_count_valid = true {
    input.replicas > 3
}

当我们向 OPA 发送查询请求时,需要提供 input 文档:

# 查询请求 (JSON)
{
  "input": {
    "replicas": 5
  }
}

# 查询结果 (JSON)
{
  "result": {
    "example/replica_count_valid": true
  }
}

如果 input.replicas 为 2,则规则体不满足,查询结果中 example/replica_count_valid 将为 false(或未定义,取决于规则定义)。

2.4 迭代与推导式

在处理 Kubernetes 资源时,经常需要遍历数组或对象。Rego 提供了强大的迭代机制。

2.4.1 使用 some 关键字

some 关键字用于声明局部变量,并用于迭代集合中的元素。

package example

# 检查所有容器镜像是否来自允许的仓库
allow = true {
    some container
    container := input.containers[_]  # 迭代 containers 数组
    startswith(container.image, "docker.io/verified/")
}

2.4.2 推导式(Comprehensions)

推导式允许你从一个集合中构建一个新的集合(数组、对象或集合)。这在数据转换和过滤时非常有用。

package example

# 获取所有容器的镜像名称列表
container_images = [image |
    some container
    container := input.containers[_]
    image := container.image
]

# 获取所有使用 "latest" 标签的容器名称
latest_containers = {name |
    some container
    container := input.containers[_]
    container.image == "nginx:latest"
    name := container.name
}
注意: 推导式中的变量作用域是局部的。在推导式外部无法访问推导式内部声明的变量。推导式的结果是一个新的集合,不会修改原始数据。

2.5 内置函数与聚合

Rego 提供了丰富的内置函数,用于字符串处理、正则匹配、时间操作、加密等。聚合函数如 count、sum、max、min 等,常用于对集合进行统计分析。

函数类别 常用函数 用途示例
字符串 startswith, endswith, contains, regex.match 检查镜像名称是否以特定前缀开头。
聚合 count, sum, max, min, any, all 统计 Deployment 中容器的数量,或检查所有容器是否都设置了资源限制。
集合 union, intersection, difference 合并多个允许的端口列表,或找出禁止的端口。
编码 base64.decode, json.marshal, yaml.unmarshal 解码 Secret 中的 Base64 数据,或解析 YAML 格式的注解。
Rego 规则评估流程 1. 解析 (语法分析) 2. 编译 (生成IR) 3. 加载数据 (input & data) 4. 评估 (执行查询) 策略决策 (allow / deny / 自定义) 关键点 评估结果取决于 input 和 data

2.6 本章小结

本章涵盖了 Rego 语言的核心基础:

  • 语法概览: 包、导入、注释、标量与复合值、变量与引用。
  • 规则定义: 完整规则、部分规则、默认规则,以及规则体中的表达式逻辑。
  • 查询与数据模型: input 和 data 的层级结构,以及如何通过查询获取策略决策。
  • 迭代与推导式: 使用 some 和推导式高效处理集合数据。
  • 内置函数: 利用丰富的函数库简化策略逻辑。

掌握这些基础后,你将能够阅读和编写基本的 Rego 策略。在下一阶段,我们将把这些知识应用到 Helm Chart 的集成中,实现真正的策略即代码部署。