4. OPA Gatekeeper 入门:Rego 策略语言基础、ConstraintTemplate 与 Constraint 概念

OPA Gatekeeper 是 Kubernetes 生态中最成熟的通用准入控制器之一。它将开放策略代理(OPA)的策略引擎与 Kubernetes 的 Admission Webhook 深度集成,允许集群管理员使用声明式 Rego 语言编写策略,并通过 CRD(Custom Resource Definition)进行管理。理解 Rego 语言基础、ConstraintTemplate 与 Constraint 的概念,是掌握 Gatekeeper 的核心前提。

4.1 Rego 策略语言基础

Rego 是一种为 OPA 量身定制的声明式查询语言。它并非传统的命令式编程语言,而是基于逻辑推理的规则引擎。在 Gatekeeper 中,Rego 用于定义“允许”或“拒绝”资源变更的条件。

4.1.1 Rego 核心概念

  • 规则(Rules):Rego 的基本单元,形式为 rule_name = value { condition }。当条件满足时,规则被赋值为 true 或具体值。
  • 文档(Documents):OPA 将输入数据(如 Kubernetes 资源对象)视为嵌套的 JSON 文档。Rego 通过点号(.)访问文档中的字段,例如 input.request.object.spec.replicas。
  • 迭代(Iteration):使用 some 关键字遍历数组或集合,例如 some container in input.request.object.spec.containers。
  • 内置函数(Built-in Functions):Rego 提供丰富的内置函数,如 count()、regex.match()、sprintf() 等,用于数据处理和验证。

4.1.2 典型 Rego 策略结构

在 Gatekeeper 的 ConstraintTemplate 中,Rego 代码通常包含两个关键部分:violation 规则和 deny 规则。

package mylibrary

# violation 规则:当条件满足时,生成一条违规消息
violation[{"msg": msg}] {
    # 条件逻辑
    input.request.operation == "CREATE"
    container := input.request.object.spec.containers[_]
    not container.securityContext.runAsNonRoot
    msg := sprintf("容器 %v 未设置 runAsNonRoot: true", [container.name])
}

# deny 规则(可选):直接返回 true/false 决定是否拒绝
deny[msg] {
    # 条件逻辑
    input.request.object.metadata.name == "forbidden-pod"
    msg := "不允许创建名为 forbidden-pod 的 Pod"
}
关键点:Rego 的 violation 规则返回一个包含消息的数组。如果数组非空,Gatekeeper 会拒绝该请求并返回消息。如果数组为空,则请求被允许。

4.2 ConstraintTemplate 与 Constraint 概念

Gatekeeper 通过两个 CRD 将 Rego 策略与 Kubernetes 资源绑定:ConstraintTemplate 和 Constraint。这种分离设计实现了策略逻辑与策略实例的解耦。

4.2.1 ConstraintTemplate

ConstraintTemplate 是策略的“模板”,它定义了 Rego 逻辑、参数模式(parameters schema)以及如何将参数注入到 Rego 代码中。一个 ConstraintTemplate 可以被多个 Constraint 实例化。

字段 说明 示例
apiVersion 固定为 templates.gatekeeper.sh/v1 templates.gatekeeper.sh/v1
kind 固定为 ConstraintTemplate ConstraintTemplate
spec.crd.spec.names.kind 定义该模板生成的 CRD 名称(即 Constraint 的 kind) K8sRequiredLabels
spec.targets[0].rego 包含 Rego 策略代码的字符串 见下方代码块
spec.targets[0].libs 可选的 Rego 库代码,用于复用 []
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.request.operation == "CREATE"
            required_label := input.parameters.labels[_]
            not input.request.object.metadata.labels[required_label]
            msg := sprintf("缺少必需的标签: %v", [required_label])
        }

4.2.2 Constraint

Constraint 是 ConstraintTemplate 的实例化对象。它通过 spec.match 字段指定策略的生效范围(如命名空间、资源类型),并通过 spec.parameters 字段传入具体参数。

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: require-team-label
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaces:
      - "production"
  parameters:
    labels:
      - "team"
      - "owner"
实践建议:在 Kustomize 中管理 Constraint 时,可以将 spec.match 和 spec.parameters 作为可配置字段,通过 Kustomize 的 patches 或 vars 实现环境差异化。

4.3 ConstraintTemplate 与 Constraint 的关系

下图展示了 ConstraintTemplate 与 Constraint 之间的逻辑关系,以及它们如何协同工作以实现准入控制。

ConstraintTemplate 与 Constraint 关系图 ConstraintTemplate 与 Constraint 关系 ConstraintTemplate 定义 Rego 策略逻辑 定义参数模式(Schema) 生成 CRD Constraint 实例化 ConstraintTemplate 指定 match 范围 传入 parameters 参数 实例化(1:N) 工作流程 1. 创建 ConstraintTemplate → 自动生成 CRD 2. 创建 Constraint(CRD 实例)→ 策略生效

4.4 策略执行流程

当 Kubernetes API Server 收到资源变更请求时,Gatekeeper 的 Webhook 会拦截该请求,并按照以下流程执行策略评估:

  1. 请求拦截:API Server 将 AdmissionReview 请求发送到 Gatekeeper Webhook。
  2. 匹配 Constraint:Gatekeeper 根据请求的资源类型、命名空间、操作等字段,匹配所有已安装的 Constraint。
  3. 加载 Rego:对于每个匹配的 Constraint,Gatekeeper 加载对应的 ConstraintTemplate 中的 Rego 代码,并将 Constraint 的 spec.parameters 注入为 input.parameters。
  4. 执行评估:OPA 引擎执行 Rego 规则,检查 violation 或 deny 规则是否返回非空结果。
  5. 返回结果:如果存在违规,Gatekeeper 返回拒绝响应并附带消息;否则允许请求继续。
注意:Gatekeeper 默认只拦截 CREATE 和 UPDATE 操作。如果需要拦截 DELETE 或其他操作,必须在 ConstraintTemplate 的 Rego 代码中显式检查 input.request.operation。

4.5 常见 Rego 模式与最佳实践

模式 Rego 示例 说明
检查标签存在 not input.request.object.metadata.labels["app"] 验证资源是否包含指定标签
遍历容器 some container in input.request.object.spec.containers 对 Pod 中的每个容器执行检查
正则匹配 regex.match("^[a-z]+$", name) 验证名称是否符合命名规范
参数化检查 required_label := input.parameters.labels[_] 从 Constraint 的 parameters 中读取动态值
排除特定命名空间 input.request.object.metadata.namespace != "kube-system" 跳过系统命名空间的检查

4.6 本章小结

OPA Gatekeeper 通过 Rego 语言提供了强大的策略定义能力,而 ConstraintTemplate 与 Constraint 的分离设计使得策略可以像 Kubernetes 原生资源一样被管理、版本化和复用。掌握 Rego 的基础语法和 Gatekeeper 的 CRD 模型,是后续在 Kustomize 中适配和组合准入策略的基石。