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 作为独立服务或库嵌入时的核心组件与数据流。
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 策略。这种分离使得安全团队可以控制策略逻辑,而平台团队可以灵活调整数据配置。