2. OPA 与 Rego 基础:OPA 架构概览、Rego 语言核心概念、安装与命令行交互

2.1 OPA 架构概览

OPA(Open Policy Agent)是一个开源的、通用策略引擎,它将策略决策与业务逻辑解耦。在 Kubernetes 生态中,OPA 通常以 Gatekeeper 的形式作为准入控制器运行,但其架构本身是通用的。

核心思想:OPA 不负责执行策略(如拒绝 Pod 创建),而是负责做出决策。它将策略决策过程抽象为:输入(Input)+ 策略(Policy)+ 数据(Data)→ 决策(Decision)。

OPA 的架构由以下几个关键组件构成:

  • OPA 服务(opa 进程):核心引擎,负责加载策略、接收查询并返回决策结果。
  • Rego 策略文件(.rego):使用 Rego 语言编写的策略规则集合。
  • 数据文档(Data Documents):外部加载的 JSON/YAML 数据,例如集群节点列表、命名空间标签等,可作为策略决策的上下文。
  • 输入文档(Input Documents):每次策略查询时传入的请求内容,例如 Kubernetes 准入请求的 AdmissionReview 对象。
  • REST API / gRPC:外部系统通过 API 向 OPA 发送查询请求。
OPA 架构概览 OPA 架构概览 外部系统 (K8s / 微服务) 输入文档 (Input) OPA 策略引擎 (Rego 评估) 决策输出 (allow/deny) 数据文档 (Data) Rego 策略文件 (.rego) 说明 OPA 将策略决策与业务逻辑分离:外部系统发送输入,OPA 结合策略和数据返回决策结果。
关键理解:OPA 本身是一个通用决策引擎,不绑定 Kubernetes。Gatekeeper 是 OPA 在 Kubernetes 环境中的具体集成实现,负责将集群资源变更事件转换为 OPA 可处理的输入文档。

2.2 Rego 语言核心概念

Rego 是 OPA 的专用策略语言,受 Datalog 启发,专为在复杂嵌套结构上进行策略定义而设计。理解 Rego 的核心概念是编写有效约束规则的前提。

2.2.1 规则(Rules)

Rego 中的规则是策略的基本构建块。规则定义了一个决策条件,当条件满足时,规则为真(true)。规则分为两种主要类型:

规则类型 描述 示例
完整规则 返回一个布尔值或一个完整的结果集。通常用于定义“允许”或“拒绝”的最终决策。 allow { input.request.operation == "CREATE" }
部分规则 生成一组值,类似于数据库查询结果。常用于收集违反策略的资源列表。 violation[msg] { ... }
# 完整规则示例:检查命名空间是否具有 required-label 标签
package example

# 完整规则:如果命名空间没有 required-label,则 deny 为 true
deny {
    input.kind == "Namespace"
    not input.metadata.labels["required-label"]
}

# 部分规则示例:收集所有缺少 required-label 的命名空间名称
violation[ns_name] {
    input.kind == "Namespace"
    ns_name := input.metadata.name
    not input.metadata.labels["required-label"]
}

2.2.2 表达式(Expressions)

表达式是构成规则主体的条件语句。Rego 支持多种表达式类型:

  • 相等性检查:== 和 !=,用于比较值。
  • 赋值::= 用于局部变量赋值;= 用于统一(unification),既可用于赋值也可用于匹配。
  • 成员关系:some 关键字用于迭代集合或数组。
  • 内置函数:如 count()、regex.match()、sprintf() 等。
  • 否定:not 关键字用于检查条件不成立。
# 表达式示例
package example

# 使用 some 迭代数组
violation[msg] {
    some container in input.spec.containers
    container.image == "latest"
    msg := sprintf("容器 %v 使用了 latest 标签", [container.name])
}

# 使用内置函数和否定
deny {
    input.kind == "Pod"
    not regex.match("^[a-z0-9-]+$", input.metadata.name)
}

2.2.3 查询(Queries)

查询是向 OPA 引擎请求决策结果的方式。在命令行中,可以使用 opa eval 命令执行查询。查询可以针对规则、数据文档或输入文档进行。

# 命令行查询示例
# 查询 data.example.deny 规则的结果
opa eval --data policy.rego --input input.json "data.example.deny"

# 查询所有 violation 消息
opa eval --data policy.rego --input input.json "data.example.violation"
常见误区:Rego 中的变量一旦赋值,在同一个规则体内不可重新赋值。这与大多数编程语言不同。例如,x := 1; x := 2 会导致编译错误。如果需要条件分支,应使用 else 关键字或定义多个规则。

2.3 OPA 的安装与命令行交互

在开始编写策略之前,需要在本地环境中安装 OPA 并熟悉其命令行工具。以下是在 Linux/macOS 环境下的安装步骤。

2.3.1 安装 OPA

OPA 以单一二进制文件形式分发,安装过程非常简单:

操作系统 安装命令
Linux (amd64) curl -L -o opa https://openpolicyagent.org/downloads/v0.60.0/opa_linux_amd64_static
chmod 755 ./opa
macOS (amd64) curl -L -o opa https://openpolicyagent.org/downloads/v0.60.0/opa_darwin_amd64
chmod 755 ./opa
macOS (arm64) curl -L -o opa https://openpolicyagent.org/downloads/v0.60.0/opa_darwin_arm64
chmod 755 ./opa

安装完成后,将 opa 二进制文件移动到 /usr/local/bin 或添加到 PATH 中,然后验证安装:

# 验证版本
opa version

# 预期输出示例
Version: 0.60.0
Build Commit: abc123
Build Timestamp: 2024-01-15T12:00:00Z

2.3.2 命令行交互基础

OPA 提供了几个核心子命令用于策略开发和测试:

  • opa eval:评估 Rego 表达式或查询,是日常开发中最常用的命令。
  • opa test:运行 Rego 测试用例,用于验证策略的正确性。
  • opa run:启动 OPA 交互式 REPL(Read-Eval-Print Loop)环境,适合快速实验。
  • opa fmt:格式化 Rego 代码,保持代码风格一致。
  • opa check:检查 Rego 文件的语法和语义错误。
# 1. 使用 opa eval 进行简单查询
# 直接计算一个表达式
opa eval "1 + 2"

# 输出: 3

# 2. 使用 --data 加载策略文件
# 假设有一个 policy.rego 文件
opa eval --data policy.rego "data.example.deny"

# 3. 使用 --input 加载输入数据
# 假设有一个 input.json 文件
opa eval --data policy.rego --input input.json "data.example.violation"

# 4. 使用 opa run 启动 REPL
opa run

# 在 REPL 中可以直接输入 Rego 表达式
> 1 + 2
3
> x := 5; y := 10; x + y
15
> exit
OPA 命令行交互流程 OPA 命令行交互流程 1. 编写策略 policy.rego 2. 准备输入 input.json 3. 执行查询 opa eval 4. 获取结果 决策输出 典型工作流 编写 Rego 策略 → 准备模拟输入 → 使用 opa eval 执行查询 → 分析决策结果 迭代修改策略直到满足预期行为

2.3.3 完整示例:从策略到决策

以下是一个完整的端到端示例,演示如何编写策略、准备输入并获取决策结果。

步骤 1:创建策略文件 check_label.rego

package k8s.namespace

# 拒绝没有 "owner" 标签的命名空间
deny[msg] {
    input.kind == "Namespace"
    not input.metadata.labels["owner"]
    msg := sprintf("命名空间 %v 缺少 owner 标签", [input.metadata.name])
}

步骤 2:创建输入文件 input.json

{
  "kind": "Namespace",
  "metadata": {
    "name": "test-ns",
    "labels": {
      "env": "production"
    }
  }
}

步骤 3:执行查询

opa eval --data check_label.rego --input input.json "data.k8s.namespace.deny"

步骤 4:查看输出

{
  "result": [
    {
      "expressions": [
        {
          "value": [
            "命名空间 test-ns 缺少 owner 标签"
          ],
          "text": "data.k8s.namespace.deny",
          "location": {
            "row": 1,
            "col": 1
          }
        }
      ]
    }
  ]
}
实践建议:在开发 Gatekeeper 约束规则时,建议先在本地使用 opa eval 和模拟输入进行验证,确认策略逻辑正确后再部署到集群中。这可以显著减少调试时间。

2.4 本章小结

本章介绍了 OPA 的核心架构、Rego 语言的基础概念以及 OPA 的安装与命令行交互方式。掌握这些基础知识后,您将能够:

  • 理解 OPA 如何将策略决策与业务逻辑解耦。
  • 使用 Rego 编写基本的完整规则和部分规则。
  • 通过命令行工具 opa eval 执行查询并获取决策结果。
  • 为后续章节中 Gatekeeper 约束规则的编写和调试打下坚实基础。