2. OPA 基础概念:Rego 语言简介、策略与数据的分离、OPA 的架构组件

在构建多集群合规校验流水线之前,必须理解 OPA(Open Policy Agent)的核心设计哲学。OPA 并非传统的策略执行引擎(如 iptables 或 RBAC),而是一个 策略决策点(PDP),它将策略逻辑从具体软件中解耦,实现统一的策略即代码(Policy-as-Code)。本章将围绕三个核心支柱展开:Rego 语言、策略与数据分离、以及 OPA 的运行时架构。

2.1 Rego 语言简介:声明式策略查询

Rego 是 OPA 专用的声明式查询语言,灵感来源于 Datalog。它不描述“如何做”(命令式),而是描述“数据应该是什么样子”(声明式)。Rego 的核心是 规则(Rules) 和 查询(Queries)。

2.1.1 基本语法与规则

Rego 中的每条规则都是一个逻辑断言。当规则为真时,它产生一个值(布尔、集合或对象)。

# 允许所有命名空间包含标签 'team: platform'
allow {
    input.request.kind == "Namespace"
    input.request.object.metadata.labels.team == "platform"
}

# 拒绝没有 owner 标签的 Deployment
deny[msg] {
    input.request.kind == "Deployment"
    not input.request.object.metadata.labels.owner
    msg := sprintf("Deployment %v 缺少 owner 标签", [input.request.object.metadata.name])
}
关键区别: allow 规则返回布尔值(true/false);deny 规则在条件满足时生成一条拒绝消息。OPA 默认使用“默认拒绝”模型,即没有明确允许即拒绝。

2.1.2 迭代与聚合

Rego 使用 some 关键字进行迭代,使用 every 关键字进行全称量化,非常适合校验容器镜像的合规性。

# 校验所有容器镜像必须来自内部仓库
violation[msg] {
    some container in input.containers
    not startswith(container.image, "registry.internal.company.com/")
    msg := sprintf("容器 %v 的镜像来源不合法: %v", [container.name, container.image])
}

# 使用 every 确保所有端口都小于 1024
valid_ports {
    every port in input.ports {
        port < 1024
    }
}

2.2 策略与数据的分离:OPA 的核心设计模式

OPA 最强大的特性是 策略(Policy) 与 数据(Data) 的完全解耦。策略是 Rego 代码,数据是 JSON 文档。OPA 在运行时将两者结合,做出决策。

维度 策略(Policy) 数据(Data)
内容 Rego 规则文件(.rego) JSON / YAML 文档
来源 Git 仓库、ConfigMap、Bundle API 外部 API、Kubernetes 资源、LDAP、静态文件
变更频率 低(随合规需求变更) 高(随基础设施状态变化)
示例 “所有镜像必须签名” 当前集群中的镜像列表、允许的仓库白名单
查询方式 data.package_name.rule_name data.whitelist.allowed_repos
实践意义: 在 Helm 发布流水线中,策略(Rego 文件)通常作为 Chart 的一部分或通过 OPA Bundle 分发;而数据(如环境白名单、集群标签)则通过 OPA 的 data API 动态注入,无需修改策略代码即可调整合规规则。

2.3 OPA 的架构组件

OPA 的架构围绕 决策请求 和 策略评估 设计。下图展示了 OPA 作为独立服务或库嵌入时的核心组件与数据流。

OPA 架构组件与决策流程 OPA 核心架构组件 外部客户端 查询请求 OPA 服务 (PDP) REST API / gRPC / 库嵌入 决策响应 策略执行点 Rego 评估引擎 数据缓存 (Data Store) Bundle 管理 / 发现 读取 同步 外部数据源 策略 Bundle 仓库 数据注入 策略拉取 组件说明 • Rego 引擎:执行策略 • 数据缓存:存储上下文 • Bundle:分发策略包 • 外部数据:动态注入 • 决策:返回 allow/deny

2.3.1 组件详解

  • Rego 评估引擎: 核心计算单元,负责解析 Rego 规则、构建逻辑查询树并执行模式匹配。它接收输入(input)和上下文数据(data),输出决策结果。
  • 数据缓存(Data Store): 内存中的 JSON 文档存储。OPA 将外部数据(如集群资源列表、白名单)加载到此处,使策略评估无需频繁调用外部 API,提升性能。
  • Bundle 管理: 负责从远程 Bundle 服务器(如 HTTP 端点或对象存储)拉取、验证和热加载策略包。Bundle 是 .tar.gz 格式,包含 .rego 文件和 .json 数据文件,支持版本控制和签名校验。
  • 决策 API: 对外暴露 REST 或 gRPC 接口。客户端(如 Kubernetes API Server 的 Webhook、Helm 发布流水线)发送 input 对象,OPA 返回 allow、deny 或结构化决策。

2.3.2 部署模式

模式 描述 适用场景
Sidecar / DaemonSet OPA 作为独立进程运行在 Kubernetes 集群内,通过 Admission Webhook 拦截资源请求。 Kubernetes 原生策略执行,如 Gatekeeper。
外部服务 OPA 部署为集群外部的独立服务,通过 REST API 调用。 CI/CD 流水线(如 Helm 发布前校验)、跨集群策略中心。
库嵌入 将 OPA 作为 Go 库(github.com/open-policy-agent/opa)嵌入到自定义工具中。 需要低延迟、无网络开销的定制化策略引擎。
注意: 在 Helm 发布流水线中,推荐使用 外部服务模式。将 OPA 部署为一个独立的策略决策中心,所有集群的 Helm 发布请求都通过该中心进行预校验,确保策略一致性,避免每个集群维护独立的 OPA 实例导致策略漂移。

2.4 策略与数据分离的实践示例

假设我们需要校验 Helm 发布的 Deployment 必须使用内部镜像仓库。策略与数据分离如下:

策略文件(policy.rego):

package helm.verify

# 从 data 中读取允许的仓库前缀
allowed_repos := data.whitelist.repositories

# 校验规则
deny[msg] {
    some container in input.containers
    not startswith(container.image, allowed_repos[_])
    msg := sprintf("容器 %v 的镜像 %v 不在允许仓库列表中", [container.name, container.image])
}

数据文件(data.json):

{
  "whitelist": {
    "repositories": [
      "registry.internal.company.com/",
      "docker.internal.mirror/"
    ]
  }
}

当需要添加新的允许仓库时,只需更新 data.json,无需修改 Rego 策略。这种分离使得安全团队可以控制策略逻辑,而平台团队可以灵活调整数据配置。