2. OPA 与 Rego 基础:OPA 架构、Rego 语言核心概念

在深入 Gatekeeper 约束规则之前,必须理解其底层引擎——开放策略代理(OPA) 以及它的策略语言 Rego。OPA 是一个通用的、开源的策略引擎,它将策略从软件中解耦;而 Rego 则是专为 OPA 设计的声明式查询语言。本章将拆解 OPA 的核心架构,并建立 Rego 语言的基本认知,为后续编写 Gatekeeper 约束奠定基础。

2.1 OPA 架构:策略决策的“大脑”

OPA 并非一个代理或 sidecar,而是一个独立的服务或库。其核心职责是:接收查询(输入),结合策略(Policy)和数据(Data),输出决策(Decision)。下图展示了 OPA 的高层架构与请求流。

OPA 架构与策略决策流程 外部系统 (K8s API / 服务) input OPA 引擎 策略 (Rego 规则) 数据 (JSON 文档) 查询 / 决策请求 decision 策略执行点 (准入控制器 / 网关) 加载 核心工作流: 1. 外部系统发送 JSON 格式的 input 查询到 OPA。 2. OPA 引擎将 input 与已加载的 Rego 策略和外部数据(data)进行匹配。 3. OPA 返回决策结果(allow/deny 或结构化数据),由外部系统执行。
关键理解: OPA 将“策略决策”与“策略执行”分离。OPA 只负责“决策”,不负责“执行”。例如,Kubernetes 准入控制器(Gatekeeper)负责拦截请求并调用 OPA,OPA 返回“允许”或“拒绝”,准入控制器再执行该决定。

2.2 Rego 语言核心概念

Rego 是一种受 Datalog 启发的声明式查询语言。与命令式编程(如 Python、Go)不同,Rego 不描述“如何做”,而是描述“数据应该是什么样子”。策略编写者定义一组规则,OPA 引擎自动评估这些规则并返回结果。

2.2.1 规则(Rules)

规则是 Rego 策略的基本构建块。一个规则定义了一个决策或一个派生值。规则有两种主要形式:

规则类型 语法特征 示例 说明
完整规则 单个条件,结果为单个值 allow := true { input.role == "admin" } 当条件满足时,allow 被赋值为 true;否则为 undefined。
部分规则 多个条件,结果为集合或对象 allowed_users[user] { user := input.users[_]; user.role == "viewer" } 生成一个包含所有满足条件用户的集合。
默认规则 提供回退值 default allow = false 当其他规则未定义时,使用默认值,避免未定义错误。
避坑指南: 在 Gatekeeper 约束中,最常用的是 完整规则。约束模板通常定义一个 violation 规则,当检测到违规时返回 {"msg": "..."},否则不返回任何值(即未定义)。不要混淆 true/false 与 undefined 的区别。

2.2.2 查询(Queries)

查询是向 OPA 引擎提问的方式。在 Rego 中,查询可以简单到只引用一个规则,也可以复杂到包含多个条件和迭代。查询的结果是 绑定 或 布尔值。

  • 布尔查询: 判断某个条件是否成立。例如:allow 返回 true 或 false(或 undefined)。
  • 数据查询: 获取满足条件的数据集合。例如:data.allowed_users 返回用户列表。
  • 迭代查询: 使用 some 关键字遍历集合。例如:some i; input.namespaces[i] == "production"。

2.2.3 数据(Data)

OPA 中的“数据”分为两类:

数据来源 访问路径 典型内容
基础文档 data 通过 OPA API 加载的静态 JSON 数据(如集群资源清单、外部配置)。
输入文档 input 每次查询时由外部系统传入的动态数据(如 Kubernetes 准入请求的 AdmissionReview)。
虚拟文档 data.package.rule 由 Rego 规则计算得出的派生数据,是策略评估的结果。
Rego 数据模型与查询路径 data 基础文档 (静态 JSON / 外部数据) 输入文档 (input / 动态请求) 虚拟文档 (规则计算结果) 查询示例: data.cluster_namespaces → 访问基础文档中的命名空间列表 input.request.object.spec.replicas → 访问输入请求中的副本数

2.3 第一个 Rego 规则示例

以下是一个完整的 Rego 规则示例,展示了规则、查询和数据的协作。该规则检查输入的用户是否具有“admin”角色。

package example.auth

# 默认规则:拒绝所有请求
default allow = false

# 完整规则:如果用户角色是 admin,则允许
allow {
    input.role == "admin"
}

# 部分规则:列出所有具有 viewer 角色的用户
viewers[user] {
    user := input.users[_]
    user.role == "viewer"
}
执行逻辑: 当 OPA 收到查询 data.example.auth.allow 时,它会检查 input.role 是否等于 "admin"。如果匹配,allow 返回 true;否则返回 false(因为默认规则)。查询 data.example.auth.viewers 则会返回所有 viewer 角色的用户集合。

2.4 本章小结

  • OPA 架构 遵循“输入 → 策略 + 数据 → 决策”的简洁模型,实现了策略与执行的解耦。
  • Rego 规则 是声明式的,分为完整规则、部分规则和默认规则,用于定义策略逻辑。
  • 查询 是向 OPA 提问的方式,结果可以是布尔值或数据集合。
  • 数据 分为基础文档(静态)、输入文档(动态)和虚拟文档(派生),通过 data 和 input 路径访问。
  • 理解这些基础概念是编写 Gatekeeper 约束模板的前提,下一章将直接应用这些知识来构建第一个安全基线约束。