2. 核心概念:策略、规则、数据、输入、输出——OPA的五大核心要素详解

Open Policy Agent (OPA) 的核心是一个通用的策略引擎,它将策略决策与策略执行解耦。要深入理解 OPA 的工作机制,必须掌握其五大核心要素:策略 (Policies)、规则 (Rules)、数据 (Data)、输入 (Input) 和 输出 (Output)。这五个要素构成了 OPA 策略评估的完整闭环。

核心理解:OPA 的本质是一个“策略计算器”。它接收 输入(来自外部的请求)和 数据(预加载的上下文信息),依据 策略(由 规则 构成)进行逻辑运算,最终产生一个 输出(决策结果)。

2.1 五大要素关系总览

下图展示了 OPA 核心要素之间的数据流与依赖关系。策略引擎是中心枢纽,输入和数据是原材料,策略是计算逻辑,输出是最终产品。

OPA 五大核心要素关系架构图 OPA 五大核心要素关系架构图 输入 (Input) 外部请求 / 事件 数据 (Data) 预加载上下文 OPA 策略引擎 Rego 解释器 决策计算核心 策略 (Policies) Rego 规则集 输出 (Output) 决策结果 提供请求上下文 提供基础事实 定义评估逻辑 生成决策 核心流程:输入 + 数据 → 策略引擎(依据策略)→ 输出决策 策略由多条规则组成,规则是 Rego 语言的基本逻辑单元

2.2 要素详解与对比

每个要素在 OPA 生态中扮演着独特的角色。下表从定义、来源、格式和示例四个维度进行对比,帮助快速建立认知。

要素 定义 来源 / 加载方式 数据格式 典型示例
策略 (Policies) 用 Rego 语言编写的规则集合,定义了决策逻辑 通过 OPA API 或文件系统加载,通常存储在 .rego 文件中 Rego 源代码 allow { input.role == "admin" }
规则 (Rules) 策略中的基本逻辑单元,由条件和表达式组成 内嵌在策略文件中,是策略的组成部分 Rego 表达式 deny[msg] { ... }
数据 (Data) 预加载到 OPA 中的结构化信息,作为策略评估的上下文 通过 API 推送、文件加载或服务发现注入 JSON / YAML {"users": {"alice": {"role": "admin"}}}
输入 (Input) 每次策略查询时传入的请求参数,代表待评估的即时事件 由调用方在查询 OPA 时通过 API 请求体传入 JSON {"user": "alice", "action": "delete"}
输出 (Output) 策略引擎根据输入、数据和策略计算得出的决策结果 OPA 引擎自动生成,返回给调用方 JSON (布尔值、对象或数组) {"allow": true, "deny": []}

2.3 要素深度解析

2.3.1 策略 (Policies) 与 规则 (Rules)

策略是 OPA 的“大脑”,而规则是构成大脑的“神经元”。策略文件(.rego)包含多条规则,每条规则定义了一个具体的决策逻辑片段。

  • 策略文件:通常以 package 关键字开头,用于组织和管理规则。例如 package kubernetes.admission。
  • 规则类型:
    • 完整规则 (Complete Rules):返回一个布尔值或单个值。例如 allow := true。
    • 部分规则 (Partial Rules):返回一个集合或对象。例如 deny[msg] { ... } 生成一个拒绝消息列表。
  • 默认值:使用 default 关键字为规则设置默认值,避免未定义导致的意外行为。
# 示例策略文件:example.rego
package system

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

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

# 部分规则:生成拒绝消息
deny[msg] {
    not input.role == "admin"
    msg = sprintf("用户 %v 没有管理员权限", [input.user])
}

2.3.2 数据 (Data) 与 输入 (Input)

数据和输入是策略评估的“燃料”。理解它们的区别至关重要:数据是静态的上下文,输入是动态的请求。

关键区别:
  • 数据 (Data):生命周期长,由运维人员或系统预先加载。例如:集群节点列表、用户角色映射、全局配置参数。在 Rego 中通过 data 变量访问。
  • 输入 (Input):生命周期短,每次策略查询时临时传入。例如:当前请求的 HTTP 方法、请求体内容、用户身份令牌。在 Rego 中通过 input 变量访问。

以下示例展示了如何在策略中同时使用数据和输入:

# 假设数据中已加载了用户角色信息
# data = {"users": {"alice": {"role": "admin"}, "bob": {"role": "viewer"}}}

# 策略规则:检查输入中的用户是否在数据中拥有特定角色
allow {
    # 从数据中查找用户角色
    role := data.users[input.user].role
    # 检查角色是否满足条件
    role == "admin"
}

2.3.3 输出 (Output)

输出是 OPA 策略评估的最终结果。它通常是一个 JSON 对象,包含决策结果和相关信息。在准入控制场景中,输出决定了请求是被允许还是拒绝。

  • 标准输出结构:OPA 默认返回所有规则的值。例如,如果策略中有 allow 和 deny 规则,输出将包含这两个字段。
  • 自定义输出:可以通过 Rego 的 object 或自定义规则来构造更复杂的输出结构,包含详细的拒绝原因、警告信息或审计日志。
# 策略输出示例
{
  "allow": false,
  "deny": [
    "用户 bob 没有管理员权限",
    "请求的命名空间 'production' 不在允许列表中"
  ],
  "warnings": [
    "用户 bob 的令牌将在 5 分钟后过期"
  ]
}

2.4 要素协同工作流程

为了更直观地展示五大要素如何协同工作,下图以 Kubernetes 准入控制为例,展示了从请求发起、策略评估到决策返回的完整流程。

OPA 要素协同工作流程图 - K8s 准入控制 OPA 要素协同工作流程图(Kubernetes 准入控制) 1. K8s API Server 发起准入请求 传入 Input 2. OPA 策略引擎 接收 Input + 加载 Data 加载 Data 3. 数据存储 集群状态 / 用户角色 执行策略 4. 策略文件 Rego 规则集 返回结果 5. 引擎计算决策 聚合规则输出 6. 输出决策 allow / deny + 消息 返回决策 完整闭环:Input + Data → 策略引擎(执行 Policies/Rules)→ Output → 返回调用方

2.5 最佳实践与避坑指南

常见误区:
  • 混淆 Data 与 Input:将频繁变化的请求参数作为 Data 加载,或将长期有效的配置作为 Input 传入。正确做法:静态配置用 Data,动态请求用 Input。
  • 规则未定义默认值:当规则不满足任何条件时,OPA 返回 undefined,可能导致意外行为。始终使用 default 关键字设置安全默认值。
  • 忽略输出结构:在准入控制场景中,Kubernetes API Server 期望特定的输出格式。确保策略输出包含 allow 和 deny 字段。
设计建议:
  • 分层组织策略:将通用规则(如认证)与业务规则(如资源配额)放在不同的 package 中,便于维护和复用。
  • 利用 Data 缓存:对于频繁查询的配置(如黑名单),通过 OPA 的 Data API 预加载,避免每次请求都查询外部数据源。
  • 输出结构化:设计包含 allowed、denied、warnings 和 audit 字段的输出,方便调用方进行后续处理。