2. OPA基础回顾:Rego语言核心概念、策略结构、数据输入与查询
在深入 Helm 集成之前,必须牢固掌握 OPA(Open Policy Agent)的策略语言——Rego。Rego 并非通用编程语言,而是一种专为云原生环境设计的声明式查询语言(Datalog 变体)。本章将系统梳理 Rego 的核心概念、策略结构、数据输入机制与查询方式,为后续编写合规校验策略奠定基础。
2.1 Rego 语言核心概念
Rego 的核心思想是:将策略视为对数据的查询。策略不是“如果-那么”的命令式逻辑,而是声明一组规则,由 OPA 引擎根据输入数据自动推导出结果。
| 概念 | 说明 | 示例 |
|---|---|---|
| 规则(Rule) | 策略的基本单元,定义一组条件与结果 | allow { input.role == "admin" } |
| 谓词(Predicate) | 规则中的条件表达式,返回 true/false | input.namespace == "production" |
| 变量(Variable) | 不可变绑定,使用 := 赋值 |
user := input.user |
| 引用(Reference) | 通过点号或方括号访问嵌套数据 | input.spec.containers[0].image |
| 集合推导(Comprehension) | 从集合中筛选、转换数据 | [c.image | c := input.containers[_]] |
| 内置函数(Built-in) | 预置的字符串、正则、时间等函数 | regex.match("^nginx:", image) |
关键理解: Rego 中所有变量都是不可变的。一旦绑定,不能重新赋值。这与 Kubernetes 声明式 API 的理念高度一致——策略只描述“应该是什么”,而非“如何做”。
2.2 策略结构:包、规则与默认值
一个完整的 Rego 策略文件通常包含以下结构层次:
package kubernetes.admission # 包声明,用于命名空间隔离
import future.keywords.if # 可选:启用 if 关键字(Rego v0.10+)
import future.keywords.in # 可选:启用 in 关键字
default allow := false # 默认拒绝(白名单模式)
# 规则:允许所有非 production 命名空间的部署
allow if {
input.kind == "Deployment"
input.metadata.namespace != "production"
}
# 规则:允许 production 命名空间中带有 approved 标签的部署
allow if {
input.kind == "Deployment"
input.metadata.namespace == "production"
input.metadata.labels.approved == "true"
}
# 规则:拒绝使用 latest 标签的容器镜像
deny[msg] {
input.kind == "Deployment"
some container in input.spec.template.spec.containers
endswith(container.image, ":latest")
msg := sprintf("容器 %v 使用了 latest 标签,禁止部署", [container.name])
}
| 结构元素 | 作用 | 最佳实践 |
|---|---|---|
package |
定义策略所属的命名空间,避免冲突 | 使用 kubernetes.admission 或 helm.release 等语义化名称 |
default |
为规则设置默认值,防止未定义 | 始终为 allow 设置 default allow := false(白名单安全模型) |
allow |
布尔规则,返回 true 表示允许 | 多个 allow 规则之间是 OR 关系,任一为 true 即允许 |
deny |
生成拒绝消息的规则,返回数组 | 使用 deny[msg] 结构,每条违规生成一条具体消息 |
violation |
Kubernetes 动态准入控制专用规则 | 返回 {"allowed": false, "message": msg} 格式 |
常见陷阱: 多个同名规则(如多个
allow)在 Rego 中是逻辑 OR 关系。如果希望所有条件同时满足才允许,必须将条件写在同一规则体内,或使用 and 组合。
2.3 数据输入:input 与 data
OPA 策略引擎在评估时接收两类数据源:
input:请求时的动态数据,如 Kubernetes AdmissionReview 请求体、Helm values 文件内容。data:预加载的静态数据,如集群资源清单、外部配置、黑名单列表。
数据输入对比:
| 特性 | input |
data |
|---|---|---|
| 来源 | 每次请求时由调用方传入 | OPA 启动时或通过 API 预加载 |
| 生命周期 | 单次请求有效 | 持久化,可被多个请求共享 |
| 典型用途 | Helm values、K8s 资源对象、用户请求 | 合规基线、允许的镜像仓库列表、命名空间白名单 |
| 访问方式 | input.deployment.replicas |
data.allowed_registries |
| 更新方式 | 每次请求自动更新 | 通过 OPA REST API 或 Bundle 更新 |
在 Helm 集成场景中,input 通常包含渲染后的 Helm values 和模板生成的 Kubernetes 资源清单;data 则包含企业合规基线、安全策略规则等静态配置。
2.4 查询与结果:Rego 的评估模型
OPA 对 Rego 策略的评估本质上是查询执行。用户通过 OPA 的 REST API 或 Go 库发起查询,OPA 引擎根据规则和数据返回结果。
查询结果通常有三种形式:
- 布尔值:
true或false,用于allow规则。 - 字符串数组:
deny[msg]返回的违规消息列表。 - 对象:Kubernetes 动态准入控制要求的
{"allowed": bool, "message": string}格式。
2.5 常用内置函数与模式
在 Helm 策略校验中,以下内置函数和模式最为常用:
| 函数/模式 | 用途 | 示例 |
|---|---|---|
regex.match(pattern, value) |
正则匹配字符串 | regex.match("^registry\\.company\\.com/", image) |
endswith(str, suffix) |
检查字符串后缀 | endswith(image, ":latest") |
count(collection) |
计算集合元素数量 | count(input.spec.containers) > 1 |
some ... in ... |
遍历集合 | some c in input.spec.containers |
every ... in ... |
全称量化(所有元素满足条件) | every c in input.containers { c.resources.limits != null } |
object.get(obj, key, default) |
安全访问嵌套字段,避免未定义错误 | object.get(input.metadata, "labels", {}) |
实战建议: 在 Helm 策略中,优先使用
object.get 访问可能缺失的字段,避免因字段不存在导致规则 panic。同时,使用 every 关键字可以简洁地表达“所有容器都必须满足资源限制”这类全称约束。
2.6 策略测试与调试
Rego 提供内置的测试框架,支持通过 opa test 命令进行单元测试:
# policy_test.rego
package kubernetes.admission
test_allow_production_with_approved_label {
result := allow with input as {
"kind": "Deployment",
"metadata": {
"namespace": "production",
"labels": {"approved": "true"}
}
}
result == true
}
test_deny_latest_tag {
result := deny with input as {
"kind": "Deployment",
"spec": {
"template": {
"spec": {
"containers": [{"name": "web", "image": "nginx:latest"}]
}
}
}
}
count(result) == 1
}
执行测试:
opa test ./policy/ -v
测试输出示例:
data.kubernetes.admission.test_allow_production_with_approved_label: PASS (1.2ms)
data.kubernetes.admission.test_deny_latest_tag: PASS (0.8ms)
--------------------------------------------------------------------------------
PASS: 2/2
调试技巧: 使用
opa eval --data policy.rego --input input.json "data.kubernetes.admission.allow" 可以快速验证策略在特定输入下的行为,无需启动 OPA 服务器。