3. Rego 语言基础:语法入门、规则定义、数据查询与内置函数
Rego 是 OPA 的策略语言,专为在复杂云原生环境中表达可读、可测试的合规规则而设计。本章将系统讲解 Rego 的核心语法、规则定义模式、数据查询方法以及关键内置函数,为后续编写镜像拉取安全扫描与灾备合规策略奠定基础。
3.1 Rego 语法入门
Rego 是一种声明式查询语言,其语法受 Datalog 启发,但扩展了对 JSON 数据的原生支持。策略由 规则(Rules) 和 查询(Queries) 组成。
3.1.1 基本结构与注释
- 包声明(Package):每个 Rego 文件以
package关键字开头,用于组织策略命名空间。 - 导入(Import):使用
import引入其他包或数据源。 - 注释:使用
#进行单行注释。
package compliance.image_scan
import data.registry.images
# 检查镜像是否包含高危漏洞
allow := true {
images.vulnerabilities[_].severity == "CRITICAL"
}
3.1.2 标量与复合值
| 类型 | 示例 | 说明 |
|---|---|---|
| 字符串 | "alpine:3.18" |
双引号包裹 |
| 数字 | 2024, 3.14 |
整数与浮点数 |
| 布尔值 | true, false |
小写 |
| 数组 | [1, 2, 3] |
有序集合,索引从 0 开始 |
| 对象 | {"name": "nginx", "tag": "latest"} |
键值对,键可为字符串或变量 |
| 集合 | {"critical", "high"} |
无序唯一值,使用大括号 |
3.2 规则定义
规则是 Rego 策略的核心单元,用于定义策略决策。规则可分为 完整规则 和 部分规则。
3.2.1 完整规则
完整规则返回单个布尔值或标量,常用于定义 allow、deny 等最终决策。
package compliance.pull
# 禁止拉取 latest 标签的镜像
deny := "镜像禁止使用 latest 标签" {
input.image.tag == "latest"
}
3.2.2 部分规则
部分规则返回一个集合或对象,常用于生成报告或中间数据。
package compliance.scan
# 收集所有高危漏洞的 CVE 编号
critical_cves[cve] {
vuln := input.scan_results[_]
vuln.severity == "CRITICAL"
cve := vuln.cve_id
}
3.2.3 默认值与否定
- 默认值:使用
default关键字为规则设置初始值,避免未定义错误。 - 否定:使用
not关键字表达条件不成立。
default allow := false
allow := true {
not input.image.vulnerabilities
}
最佳实践:在灾备合规策略中,始终为
allow 或 deny 规则设置 default 值,确保策略在数据缺失时仍能返回明确结果。
3.3 数据查询
Rego 通过 迭代(Iteration) 和 变量绑定 实现强大的数据查询能力。查询通常使用 [_] 遍历数组或集合。
3.3.1 数组与对象遍历
package query.example
# 遍历镜像层,查找包含敏感文件的层
sensitive_layers[digest] {
layer := input.image.layers[_]
layer.files[_] == ".env"
digest := layer.digest
}
3.3.2 多条件组合查询
# 查询所有未通过安全扫描且来自非可信仓库的镜像
blocked_images[image_ref] {
image := input.images[_]
image.scan_status == "FAILED"
image.registry != "harbor.internal.com"
image_ref := image.reference
}
3.3.3 使用 every 关键字
Rego 1.0 引入 every 关键字,用于表达“所有元素必须满足条件”的语义,提升可读性。
# 所有镜像层必须来自可信构建器
allow := true {
every layer in input.image.layers {
layer.builder == "trusted-ci"
}
}
3.4 内置函数
Rego 提供丰富的内置函数,用于处理字符串、时间、JWT、加密等操作。在镜像拉取安全扫描与灾备合规场景中,以下函数尤为关键。
3.4.1 JWT 解码:io.jwt.decode_sign
该函数用于解码并验证 JWT 签名,常用于校验镜像拉取凭证或灾备令牌的有效性。
package jwt.check
# 解码 JWT 并验证签名
_payload := payload {
[header, payload, sig] := io.jwt.decode_sign(input., input.cert)
# 可进一步检查 payload 中的 claims
payload.iss == "dr-backup-system"
}
| 参数 | 类型 | 说明 |
|---|---|---|
|
string | JWT 字符串 |
cert |
string | 用于验证签名的公钥证书(PEM 格式) |
| 返回值 | array | [header, payload, signature] 三元组 |
3.4.2 其他常用内置函数
time.now_ns():获取当前时间(纳秒),用于灾备策略中的时间窗口校验。sprintf:格式化字符串,用于生成合规报告消息。regex.match:正则匹配,用于镜像标签或仓库地址的模式校验。object.get:安全访问对象属性,避免未定义错误。
# 灾备合规示例:检查备份时间是否在 24 小时内
backup_compliant := true {
last_backup := time.now_ns() - input.backup_timestamp
last_backup < 86400000000000 # 24 小时纳秒值
}
3.5 Rego 策略执行流程
下图展示了从输入数据到策略决策的完整执行流程,帮助理解 Rego 规则在 OPA 中的运行机制。
3.6 常见错误与避坑指南
常见错误 1:未定义变量导致规则静默失败
在 Rego 中,如果查询的变量在数据中不存在,规则会静默返回
在 Rego 中,如果查询的变量在数据中不存在,规则会静默返回
undefined,而非报错。务必使用 object.get 或 default 兜底。
常见错误 2:集合与数组混淆
集合
集合
{"a", "b"} 不支持索引访问,而数组 ["a", "b"] 支持。在遍历时注意区分,避免使用 [_] 对集合进行索引。
避坑提示:在编写镜像拉取策略时,JWT 解码函数
io.jwt.decode_sign 要求公钥证书为 PEM 格式。如果证书格式错误,函数会返回 undefined,导致策略无法正确评估。建议在测试阶段使用 trace 函数输出中间结果进行调试。
3.7 本章小结
本章覆盖了 Rego 语言的核心基础:
- 语法入门:包声明、标量与复合值类型。
- 规则定义:完整规则与部分规则的区别及默认值使用。
- 数据查询:遍历、多条件组合与
every关键字。 - 内置函数:重点掌握
io.jwt.decode_sign在凭证校验中的应用。