策略语法基础:策略语言的基本结构、关键字与语法规则

在云原生安全基线核验中,策略即代码(Policy as Code)是核心实践。不同的策略引擎(如 OPA、Kyverno)使用不同的策略语言,但都遵循声明式、可组合的语法范式。本章将系统梳理 Rego(OPA 语言)、Kyverno 策略(基于 YAML 的 DSL)以及通用策略语言的基本结构、关键字与语法规则,帮助你在编写和调试策略时快速定位语法错误。

3.1 策略语言核心概念对比

下表从语言类型、策略结构、规则定义方式、变量作用域四个维度对比三种主流策略语言,便于建立整体认知。

维度 Rego (OPA) Kyverno (YAML DSL) 通用策略语言参考
语言类型 声明式逻辑编程语言(类 Datalog) 声明式 YAML 配置(基于 Kubernetes 资源) 声明式规则引擎(如 JSON/YAML + 条件表达式)
策略结构 package + import + rules apiVersion + kind + metadata + spec 规则集 + 条件 + 动作
规则定义 规则名 := 表达式 { 条件 } match + validate / mutate / generate if-then 或 when-then 结构
变量作用域 局部变量(:= 赋值)、全局变量(data) 模板变量({{ request.object.spec }}) 上下文变量(context.xxx)

3.2 Rego 语言基本结构与关键字

Rego 是 OPA 的原生策略语言,其核心结构由 包(package)、导入(import)、规则(rule) 三部分组成。规则是 Rego 的基本计算单元,每条规则返回一个布尔值、集合或对象。

3.2.1 基本结构示例

package kubernetes.admission

import data.kubernetes.resources as k8s

# 规则:禁止使用 latest 标签
deny[msg] {
    input.request.kind.kind == "Pod"
    container := input.request.object.spec.containers[_]
    container.image == "nginx:latest"
    msg := sprintf("容器 %v 使用了 latest 标签,请指定固定版本", [container.name])
}

3.2.2 核心关键字与语法规则

  • package:声明策略所属的命名空间,用于组织策略和避免命名冲突。
  • import:导入外部数据或规则,支持别名(as)和通配符(*)。
  • 规则头:规则名 := 表达式(完整规则)或 规则名[变量] { 条件 }(部分规则)。
  • 迭代器:some i 或 _ 用于遍历数组/集合,如 input.spec.containers[_]。
  • 赋值::= 用于局部变量赋值,== 用于相等比较,= 用于统一(unification)。
  • 内置函数:sprintf、count、regex.match 等,用于字符串处理、集合运算和正则匹配。
常见语法陷阱:Rego 中 = 和 := 容易混淆。:= 只能用于首次赋值,后续引用必须使用 == 或 =。例如 x := 1; x == 2 是合法比较,但 x := 1; x := 2 会引发编译错误。

3.3 Kyverno 策略结构与语法规则

Kyverno 策略使用 Kubernetes 原生 YAML 格式,通过 match 和 validate/mutate/generate 块定义规则。其语法更贴近 Kubernetes 用户习惯,但同样需要严格遵循 YAML 缩进和字段约束。

3.3.1 基本结构示例

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-latest-tag
spec:
  validationFailureAction: Audit
  rules:
  - name: require-image-tag
    match:
      resources:
        kinds:
        - Pod
    validate:
      message: "镜像标签不能为 latest"
      pattern:
        spec:
          containers:
          - image: "!*:latest"

3.3.2 核心关键字与语法规则

  • apiVersion / kind:固定为 kyverno.io/v1 和 ClusterPolicy(集群范围)或 Policy(命名空间范围)。
  • spec.rules:规则列表,每个规则包含 name、match、validate/mutate/generate。
  • match:定义策略适用的资源类型、标签选择器、命名空间等。
  • validate.pattern:使用 Kubernetes 风格的 pattern 或 anyPattern 进行字段匹配,支持通配符 * 和否定 !。
  • validate.deny:使用 conditions 块编写更复杂的条件表达式,支持 key、operator、value。
  • 模板变量:{{ request.object.spec.containers[].image }} 用于引用请求中的字段。
YAML 缩进错误:Kyverno 策略中 match、validate 等字段的缩进层级必须严格对齐。常见错误是将 validate 与 match 放在同一层级,导致策略解析失败。建议使用 YAML 校验工具(如 yamllint)预先检查。

3.4 策略语法结构总览图

下图展示了 Rego 和 Kyverno 两种策略语言的语法结构对比,帮助理解声明式策略的通用组织模式。

策略语法结构对比:Rego vs Kyverno Rego 策略结构 package kubernetes.admission import data.kubernetes.resources as k8s deny[msg] { ... } allow { ... } violation[msg] { ... } 规则头 := 表达式 { 条件 } Kyverno 策略结构 apiVersion: kyverno.io/v1 kind: ClusterPolicy spec.rules[].match spec.rules[].validate spec.rules[].mutate/generate YAML 声明式 + 模板变量

3.5 通用语法规则与调试要点

无论使用哪种策略语言,以下语法规则是编写可调试策略的基础:

  1. 声明式优先:策略只描述“应该是什么”,不描述“如何执行”。避免在策略中编写循环或复杂控制流。
  2. 数据不可变:策略引擎通常不允许修改输入数据,所有转换通过 mutate 或 copy 语义实现。
  3. 规则组合:多个规则通过逻辑与(AND)或逻辑或(OR)组合,Rego 使用 ; 和 |,Kyverno 使用 conditions 块。
  4. 错误处理:策略引擎遇到语法错误时,通常返回明确的错误行号和原因。常见错误包括:未闭合的括号、缩进不一致、未定义的变量、类型不匹配。
调试建议:在编写策略时,先使用最小化输入(如单个 Pod 的 JSON 表示)进行单元测试。Rego 可使用 opa eval 命令配合 --input 参数;Kyverno 可使用 kyverno apply 命令进行本地验证。将策略拆分为多个小规则,逐条验证,能显著降低语法错误的排查难度。

3.6 策略语法错误分类与排查流程

下图总结了策略语法错误的常见类型及排查步骤,帮助你在实际调试中快速定位问题。

策略语法错误分类与排查流程 语法错误分类 1. 缩进/格式错误 2. 关键字拼写错误 3. 变量未定义/作用域错误 4. 类型不匹配 5. 规则头格式错误 排查流程(自底向上) 步骤1: 使用 linter 检查格式(opa fmt / yamllint) 步骤2: 逐条规则注释测试,定位错误规则 步骤3: 检查变量作用域和赋值操作符(:= vs ==) 步骤4: 使用最小输入测试,验证规则输出 步骤5: 查看引擎错误日志,定位行号 提示:大多数语法错误可通过格式化工具和单元测试在 5 分钟内定位

3.7 本章小结