2. OPA 基础回顾:Rego 语言核心语法、策略包结构、数据文档与查询

在深入 OPA 与日志平台的集成测试之前,必须牢固掌握 Rego 语言的基础。Rego 是 OPA 的原生策略语言,专为在复杂 JSON/YAML 数据上进行声明式查询与规则评估而设计。本节将系统梳理 Rego 的核心语法、策略包结构以及数据文档与查询机制,为后续的权限规则编写与测试奠定基础。

2.1 Rego 语言核心语法

Rego 是一种声明式查询语言,其语法受 Datalog 启发,但扩展了对现代数据格式(如 JSON)的原生支持。理解其核心语法是编写有效策略的前提。

2.1.1 规则(Rules)

规则是 Rego 的基本构建单元。一个规则定义了一个决策或一个值。规则分为完整规则和部分规则。

  • 完整规则:返回单个值(布尔值、字符串、数字等)。
  • 部分规则:返回一个集合或对象,通常用于定义一组允许的操作或资源。
# 完整规则:判断用户是否为管理员
default is_admin = false
is_admin {
    input.user.role == "admin"
}

# 部分规则:定义允许的操作集合
allowed_actions[action] {
    action := input.user.actions[_]
    action != "delete"
}

2.1.2 迭代与变量

Rego 使用 some 关键字和匿名变量 _ 进行迭代。变量在规则体中被赋值,且一旦赋值即不可变。

  • some i:声明一个局部变量,用于遍历数组或集合。
  • _:匿名变量,用于忽略不需要的值。
  • :=:赋值操作符,用于将值绑定到变量。
# 遍历用户角色列表,检查是否包含 "auditor"
has_auditor_role {
    some role
    input.user.roles[role] == "auditor"
}

# 使用匿名变量忽略索引
any_admin {
    input.users[_].role == "admin"
}

2.1.3 内置函数与聚合

Rego 提供了丰富的内置函数,用于字符串处理、集合操作、时间比较等。聚合函数如 count、sum、max 等常用于统计与校验。

函数类别 示例函数 说明
字符串 startswith(str, prefix) 检查字符串是否以指定前缀开头
集合 union(set1, set2) 返回两个集合的并集
时间 time.now_ns() 返回当前时间的纳秒级时间戳
聚合 count(array) 返回数组或集合中的元素数量
# 使用内置函数校验日志来源
valid_log_source {
    startswith(input.log.source, "app-")
}

# 聚合:检查违规操作数量是否超过阈值
violation_count := count([op | op := input.operations[_]; op.status == "violation"])
threshold_exceeded {
    violation_count > 5
}
提示:Rego 中的规则体由多个表达式组成,表达式之间是逻辑与(AND)关系。同一规则体内多个同名规则之间是逻辑或(OR)关系。

2.2 策略包结构

策略包(Package)是 Rego 中组织策略的基本单元,类似于其他语言中的命名空间。一个包可以包含多个规则、导入语句以及元数据注释。合理的包结构有助于策略的模块化、复用与测试。

2.2.1 包声明与导入

每个 Rego 文件以 package 关键字开头,声明该文件所属的包。通过 import 关键字可以引入其他包中的规则或数据。

package platform.logs.access_control

import data.platform.logs.common
import future.keywords.if
import future.keywords.in

# 使用导入的规则
allow if {
    common.is_authenticated(input.user)
    input.action in ["read", "write"]
}

2.2.2 推荐的包组织方式

在日志平台权限规则测试场景中,建议按功能模块或资源类型组织包结构,以提升可维护性。

包路径 职责 包含规则示例
platform.logs.auth 用户认证与身份校验 is_authenticated, _valid
platform.logs.rbac 基于角色的访问控制 allowed_roles, user_has_role
platform.logs.audit 审计日志过滤与告警 sensitive_operation, audit_required
platform.logs.common 通用工具与辅助规则 is_internal_ip, time_in_window

2.2.3 元数据注释

Rego 支持使用 # METADATA 注释块为规则添加描述、标题、自定义属性等,便于生成文档和策略审计。

# METADATA
# title: 允许管理员读取审计日志
# description: 仅当用户角色为 admin 且操作类型为 read 时允许访问审计日志
# custom:
#   severity: high
allow_audit_log_read {
    input.user.role == "admin"
    input.operation == "read"
    input.resource.type == "audit_log"
}
最佳实践:在日志平台项目中,每个策略包应包含一个 main 规则作为该包的入口点,便于 OPA 查询时统一调用。

2.3 数据文档与查询

OPA 将输入数据(input)和外部数据(data)视为文档(Documents)。理解数据文档的结构与查询方式是编写正确策略的关键。

2.3.1 输入文档(input)

input 是每次策略评估时由调用方传入的临时数据,通常包含请求上下文,如用户信息、操作类型、目标资源等。

# 典型的 input 结构(JSON)
{
    "user": {
        "id": "user-001",
        "role": "viewer",
        "department": "security"
    },
    "operation": "read",
    "resource": {
        "type": "log_stream",
        "id": "stream-prod-01",
        "tags": ["production", "critical"]
    },
    "timestamp": "2025-03-21T10:00:00Z"
}

2.3.2 数据文档(data)

data 是 OPA 加载的外部数据,可以是静态 JSON 文件、从外部服务拉取的策略数据,或其他 Rego 包中定义的规则结果。数据文档是全局的,可在所有包中引用。

# 外部数据示例:角色-权限映射表(roles.json)
{
    "roles": {
        "admin": ["read", "write", "delete", "manage"],
        "viewer": ["read"],
        "auditor": ["read", "export"]
    }
}

# 在 Rego 中引用 data 文档
allowed_operations[op] {
    op := data.roles[input.user.role][_]
}

2.3.3 查询与结果

OPA 的查询分为完整规则查询和部分规则查询。完整规则返回布尔值或具体值;部分规则返回集合或对象。查询结果通过 REST API 或 Go/Java SDK 获取。

查询类型 Rego 规则示例 查询路径 返回结果示例
完整规则 allow { ... } /v1/data/platform/logs/access_control/allow {"result": true}
部分规则 allowed_actions[action] { ... } /v1/data/platform/logs/access_control/allowed_actions {"result": ["read", "write"]}
数据文档 data.roles /v1/data/roles {"result": {"admin": [...], "viewer": [...]}}
注意:在日志平台集成场景中,input 文档通常由 API 网关或日志采集器动态构造,而 data 文档中的角色映射、资源标签等静态数据应定期从配置中心同步,避免策略评估时数据不一致。

2.4 Rego 策略执行流程示意图

下图展示了从输入请求到策略评估再到决策输出的完整流程,帮助理解 Rego 规则在 OPA 中的执行路径。

Rego 策略执行流程 输入文档 (input) 数据文档 (data) 策略包 (package) 规则引擎评估 决策输出 (result) 关键说明 • input 每次评估动态传入 • data 为全局静态/缓存数据 • 包内规则可引用其他包规则 • 结果通过 REST API 返回

2.5 数据文档与查询关系图

为了更清晰地展示 input、data 与 Rego 规则之间的数据流动关系,下图以日志平台权限校验为例,呈现了典型的数据查询路径。

日志平台权限校验数据流 API 网关 input 文档 OPA 策略引擎 角色映射表 (data) 资源标签表 (data) 决策结果 (allow/deny) 查询路径示例 POST /v1/data/platform/logs/rbac/allow Body: { "input": { ... } }
核心要点:Rego 策略的评估结果完全取决于 input 与 data 的组合。在日志平台权限规则测试中,测试用例应覆盖不同的 input 组合(如不同角色、不同操作)以及 data 的边界情况(如空角色映射、缺失标签),以确保策略的健壮性。