4. ConstraintTemplate 入门:CRD 结构、Rego 模板编写基础、模板参数化

ConstraintTemplate(约束模板)是 Gatekeeper 的核心扩展点,它定义了策略的“形状”和“逻辑”。本章将深入剖析 ConstraintTemplate 的 CRD 结构、Rego 模板编写基础以及如何通过参数化实现模板复用。

4.1 ConstraintTemplate CRD 结构解析

ConstraintTemplate 本身是一个 Kubernetes 自定义资源(CRD),其 API 版本为 templates.gatekeeper.sh/v1。一个完整的 ConstraintTemplate 由三个主要部分组成:metadata、spec.crd.spec 和 spec.targets。

字段路径 类型 说明
metadata.name string 模板名称,必须与后续创建的 Constraint 的 constraintType 一致。
spec.crd.spec.names.kind string 定义由此模板生成的 Constraint 的 Kind 名称。
spec.crd.spec.validation.openAPIV3Schema object 定义 Constraint 实例的 spec.parameters 字段的 JSON Schema 结构,用于参数校验。
spec.targets[].target string 目标系统,通常为 admission.k8s.gatekeeper.sh。
spec.targets[].rego string Rego 策略代码,包含 violation 规则。
spec.targets[].libs []string 可选的 Rego 库代码,用于在多个模板间共享函数。
关键理解: ConstraintTemplate 是“模板工厂”,它通过 spec.crd.spec 定义了 Constraint 实例的“参数接口”,并通过 spec.targets[].rego 提供了策略执行逻辑。

4.2 Rego 模板编写基础

Rego 是 Gatekeeper 的策略语言,其核心是 violation 规则。当 violation 规则返回 true 时,表示请求违反策略。

4.2.1 基本 Rego 模板结构

package mypackage

violation[{"msg": msg}] {
  # 条件判断
  input.review.object.metadata.name == "forbidden-name"
  msg := "资源名称不允许为 forbidden-name"
}
  • package:定义 Rego 包名,建议与模板名称对应。
  • violation:一个集合规则,每个满足条件的条目生成一个包含 msg 字段的对象。
  • input:Gatekeeper 注入的全局变量,包含 review(AdmissionReview 对象)和 parameters(用户传入的参数)。

4.2.2 访问请求数据

Rego 通过 input 对象访问 Kubernetes 资源请求的详细信息:

表达式 说明
input.review.object 被审查的 Kubernetes 资源对象。
input.review.oldObject 更新操作中的旧对象。
input.review.operation 操作类型,如 CREATE、UPDATE。
input.parameters 用户在 Constraint 实例中定义的参数。

4.3 模板参数化

参数化允许同一个 ConstraintTemplate 通过不同的参数配置实现不同的策略行为,避免为每个细微差异创建新模板。

4.3.1 定义参数 Schema

在 spec.crd.spec.validation.openAPIV3Schema 中定义参数结构:

spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        openAPIV3Schema:
          type: object
          properties:
            labels:
              type: array
              items:
                type: string

4.3.2 在 Rego 中使用参数

通过 input.parameters 访问用户传入的参数:

package k8srequiredlabels

violation[{"msg": msg}] {
  input.review.operation == "CREATE"
  label := input.parameters.labels[_]
  not input.review.object.metadata.labels[label]
  msg := sprintf("必须包含标签: %v", [label])
}

4.4 ConstraintTemplate 与 Constraint 的关系

下图展示了 ConstraintTemplate 如何通过参数化生成不同的 Constraint 实例:

ConstraintTemplate 与 Constraint 参数化关系 ConstraintTemplate K8sRequiredLabels Rego: 检查标签是否存在 参数: labels (array) 实例化 Constraint 实例 1 kind: K8sRequiredLabels parameters.labels: ["app", "env"] Constraint 实例 2 kind: K8sRequiredLabels parameters.labels: ["team", "cost-center"] 实例化 参数化优势 • 一个模板 • 多种策略 • 减少重复代码 • 统一维护 • 灵活配置

4.5 完整示例:带参数的标签检查模板

以下是一个完整的 ConstraintTemplate 示例,它检查资源是否包含指定的标签:

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        openAPIV3Schema:
          type: object
          properties:
            labels:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels

        violation[{"msg": msg}] {
          input.review.operation == "CREATE"
          label := input.parameters.labels[_]
          not input.review.object.metadata.labels[label]
          msg := sprintf("必须包含标签: %v", [label])
        }
最佳实践: 在 openAPIV3Schema 中明确定义参数类型和约束,Gatekeeper 会自动校验用户传入的参数是否符合 Schema 定义,避免运行时错误。

4.6 参数化与 Rego 数据查询

参数化不仅限于简单的列表或字符串,还可以结合 Rego 的数据查询功能实现更复杂的策略。例如,从 ConfigMap 中读取允许的镜像列表:

package allowedimages

violation[{"msg": msg}] {
  image := input.review.object.spec.containers[_].image
  not data.allowedimages.images[image]
  msg := sprintf("镜像 %v 不在允许列表中", [image])
}

这种方式将策略逻辑与配置数据分离,通过更新 ConfigMap 即可动态调整策略行为,无需修改 ConstraintTemplate 或重新部署。

4.7 本章小结

  • CRD 结构:ConstraintTemplate 包含 spec.crd.spec(定义参数接口)和 spec.targets(定义 Rego 逻辑)。
  • Rego 基础:violation 规则是策略的核心,通过 input 访问请求数据和参数。
  • 参数化:通过 openAPIV3Schema 定义参数结构,在 Rego 中使用 input.parameters 引用参数,实现模板复用。
  • 数据查询:Rego 支持通过 data 关键字查询集群中的其他资源,实现动态策略。