4. Rego语言入门(二):引用、规则定义、完整规则与部分规则、默认规则
在上一节中,我们掌握了 Rego 的基本语法、标量值与复合值。本节将深入 Rego 的策略核心:引用(References)、规则定义(Rule Definitions),以及两种关键的规则形态——完整规则(Complete Rules)与部分规则(Partial Rules),最后学习默认规则(Default Rules)的声明方式。这些概念是编写 OPA 策略的基石。
4.1 引用(References)
引用是 Rego 中访问嵌套数据的路径表达式,类似于 JSON 或 YAML 中的路径导航。OPA 通过引用从输入的 input 文档或 data 文档中提取值。
4.1.1 点式引用与方括号引用
| 引用类型 | 语法 | 示例 | 说明 |
|---|---|---|---|
| 点式引用 | object.key |
input.user.role |
适用于键名为标识符(字母、数字、下划线,不以数字开头) |
| 方括号引用 | object["key"] |
input["user"]["role"] |
适用于任意字符串键,包括包含特殊字符或空格的键 |
| 数组索引 | array[index] |
input.artifacts[0] |
索引从 0 开始 |
最佳实践:在策略中优先使用点式引用,代码更简洁。当键名包含连字符(
-)、空格或为变量时,必须使用方括号引用。
4.1.2 变量引用与迭代
引用中可以包含变量,实现动态路径访问和集合迭代:
# 输入数据
input = {
"users": [
{"name": "alice", "role": "admin"},
{"name": "bob", "role": "developer"}
]
}
# 使用变量迭代
user_roles[user.role] {
user := input.users[_] # _ 表示通配索引,遍历所有元素
}
# 结果:["admin", "developer"]
4.2 规则定义(Rule Definitions)
规则是 Rego 策略的基本单元,用于定义决策逻辑。每条规则由一个头部(Head)和一个主体(Body)组成。
4.2.1 规则结构
# 规则头部:定义规则名称和输出
rule_name := output_value {
# 规则主体:条件表达式(可包含多个条件)
condition_1
condition_2
# ... 所有条件必须同时为真(逻辑与)
}
- 头部:
rule_name := expression,定义规则名和返回的表达式值。 - 主体:花括号内的条件集合,每个条件占一行,条件之间是逻辑与(AND)关系。
- 赋值操作符:
:=用于局部变量赋值;=用于统一(Unification),在旧版 Rego 中常见,新版推荐使用:=。
4.2.2 规则类型对比
| 特性 | 完整规则(Complete Rule) | 部分规则(Partial Rule) |
|---|---|---|
| 输出形式 | 单个值(标量、对象、数组) | 键值对集合(类似字典) |
| 头部语法 | r := value { body } |
r[key] := value { body } |
| 主体条件 | 所有条件为真时,规则为真 | 每个满足条件的组合生成一个键值对 |
| 典型用途 | 布尔决策、计算单一结果 | 生成允许列表、拒绝列表、属性映射 |
| 默认值 | 未定义(undefined) | 空集合 |
4.3 完整规则(Complete Rules)
完整规则返回一个单一值。当规则主体中的所有条件都满足时,规则被定义为该值;否则规则为未定义(undefined)。
4.3.1 布尔决策规则
# 判断构建产物是否允许部署
allow_deploy := true {
input.artifact.vulnerability_level == "low"
input.artifact.license_compliance == true
}
# 使用:allow_deploy 返回 true 或 undefined
4.3.2 计算规则
# 计算安全评分(0-100)
security_score := score {
base := 100
deductions := input.findings * 10
score := base - deductions
score >= 0
}
# 如果 deductions 超过 100,规则未定义
注意:完整规则在主体条件不满足时返回 undefined,而不是
false。在策略中,undefined 和 false 的行为不同:undefined 表示规则不适用,false 表示明确拒绝。使用 default 关键字可以处理未定义情况。
4.4 部分规则(Partial Rules)
部分规则生成一个键值对集合。规则头部包含一个键变量,主体中的每个成功绑定都会向集合中添加一个条目。
4.4.1 生成允许列表
# 定义允许部署的镜像列表
allowed_images[image] {
image := input.images[_]
image.registry == "trusted-registry.io"
image.scan_status == "passed"
}
# 结果示例:
# {
# "nginx:1.21": true,
# "redis:6.2": true
# }
4.4.2 生成属性映射
# 为每个构建产物生成安全等级映射
artifact_severity[artifact.id] := severity {
artifact := input.artifacts[_]
severity := "critical" {
artifact.cvss_score >= 9.0
}
severity := "high" {
artifact.cvss_score >= 7.0
artifact.cvss_score < 9.0
}
severity := "medium" {
artifact.cvss_score >= 4.0
artifact.cvss_score < 7.0
}
severity := "low" {
artifact.cvss_score < 4.0
}
}
# 结果示例:
# {
# "artifact-001": "critical",
# "artifact-002": "medium"
# }
4.5 默认规则(Default Rules)
默认规则为规则提供回退值,当规则主体条件不满足导致规则未定义时,使用默认值代替。
4.5.1 默认规则语法
# 声明默认值
default allow_deploy = false
# 实际规则定义
allow_deploy := true {
input.artifact.vulnerability_level == "low"
input.artifact.license_compliance == true
}
# 当条件不满足时,allow_deploy 返回 false 而不是 undefined
4.5.2 默认规则使用场景
| 场景 | 无默认规则 | 有默认规则 |
|---|---|---|
| 布尔决策 | 返回 undefined,需额外处理 |
返回 false,明确拒绝 |
| 数值计算 | 返回 undefined,中断策略链 |
返回默认值(如 0),继续评估 |
| 集合生成 | 返回空集合 | 返回默认集合(较少使用) |
关键原则:在 CI/CD 流水线安全策略中,始终为布尔决策规则声明
default = false,遵循默认拒绝(Default Deny)的安全模型。这确保任何未明确允许的操作都被自动阻断。
4.6 规则定义与引用关系图
下图展示了 Rego 规则定义的核心结构以及引用如何连接输入数据与规则逻辑:
4.7 综合示例:构建产物安全验证
将本节知识点整合为一个完整的策略示例,模拟 CI/CD 流水线中的构建产物安全验证:
# 默认拒绝
default allow_deploy = false
# 完整规则:允许部署的条件
allow_deploy := true {
# 引用输入数据
artifact := input.artifact
# 安全扫描通过
artifact.scan_status == "passed"
# 漏洞等级在可接受范围
artifact.max_vulnerability in {"low", "medium"}
# 许可证合规
artifact.license_approved == true
# 签名验证通过
artifact.signature_valid == true
}
# 部分规则:生成阻断原因列表
block_reasons[reason] {
artifact := input.artifact
artifact.scan_status != "passed"
reason := "安全扫描未通过"
}
block_reasons[reason] {
artifact := input.artifact
artifact.max_vulnerability == "critical"
reason := "存在严重漏洞"
}
block_reasons[reason] {
artifact := input.artifact
artifact.license_approved != true
reason := "许可证未批准"
}
block_reasons[reason] {
artifact := input.artifact
artifact.signature_valid != true
reason := "签名验证失败"
}
# 完整规则:汇总阻断信息
deployment_blocked := true {
count(block_reasons) > 0
}
实践建议:在编写策略时,先使用
default 声明安全默认值,然后编写完整规则定义允许条件,最后使用部分规则收集详细的阻断原因。这种模式既保证了安全性,又提供了可操作的反馈信息。
4.8 常见错误与调试
| 错误模式 | 错误示例 | 正确写法 | 说明 |
|---|---|---|---|
| 引用未定义键 | input.nonexistent.key |
先检查存在性:input.nonexistent 或使用 walk |
引用不存在的键会导致规则未定义 |
| 变量未赋值 | result := x + 1(x 未定义) |
x := input.value; result := x + 1 |
所有变量必须先赋值再使用 |
| 规则名冲突 | 同时定义 r := 1 和 r := 2 |
使用不同规则名或部分规则 | 同一规则名只能有一个完整规则定义 |
| 默认规则位置错误 | default 声明在规则之后 |
default 声明在规则之前 |
默认规则必须出现在实际规则定义之前 |