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 引擎根据规则和数据返回结果。

Rego 策略评估流程 输入 (input) Helm Values / K8s 资源 数据 (data) 合规基线 / 黑名单 OPA 引擎 Rego 规则评估 查询执行器 策略规则 (allow / deny / violation) 声明式条件匹配 查询结果 (true / false / 消息) 查询示例 data.kubernetes.admission.allow

查询结果通常有三种形式:

  • 布尔值: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 服务器。