故障隔离设计基于policy as code的升级窗口控制 - 第4节

4.1 OPA 架构:策略决策与执行分离

Open Policy Agent (OPA) 是一个开源的、通用策略引擎,它将策略决策从软件的业务逻辑中解耦出来。OPA 的核心思想是“策略即代码”(Policy as Code),通过统一的声明式语言 Rego 来描述策略,并通过 REST API 对外提供策略查询服务。

核心架构原则: OPA 不负责执行策略(如阻断请求、修改资源),只负责做出策略决策(允许/拒绝/评分)。执行动作由调用方(如 Kubernetes API Server、API 网关)根据 OPA 的决策结果自行完成。

4.1.1 OPA 组件与数据流

OPA 的架构由以下几个核心组件构成:

  • OPA Agent (opa 进程): 核心引擎,加载策略(Rego 文件)和数据(JSON 文档),对外提供 HTTP/gRPC 查询接口。
  • Rego 策略: 使用 Rego 语言编写的规则文件,定义决策逻辑。
  • 数据文档 (Data Documents): 结构化数据(JSON),作为策略决策的输入上下文,例如集群状态、用户信息、资源元数据。
  • 输入文档 (Input Documents): 每次查询时由调用方传入的临时数据,例如准入请求的 AdmissionReview 对象。
  • 查询接口 (Query API): 调用方通过 POST /v1/data/{path} 发送查询请求,OPA 返回决策结果。
OPA 核心架构与数据流 OPA 核心架构与数据流 调用方 (K8s API / 网关 / 应用) OPA Agent (策略引擎) 策略存储 (Rego 文件 / Bundle) 数据源 (K8s 集群 / CMDB) POST /v1/data 加载策略 数据同步 决策结果 (allow/deny) 架构要点: 1. 调用方每次请求都携带 Input 文档,OPA 结合 Data 文档和策略做出决策。 2. OPA 本身不执行任何阻断或变更操作,执行权始终在调用方手中。

4.2 Rego 语言基础:声明式策略编写

Rego 是 OPA 的专用策略语言,受 Datalog 启发,采用声明式范式。编写 Rego 策略的核心是定义“规则”(Rules),规则的结果可以是布尔值(true/false)、对象或数组。

4.2.1 基本语法与规则

概念 语法示例 说明
包声明 package kubernetes.admission 定义策略所属的包路径,对应查询 API 的 URL 路径。
完整规则 allow { ... } 当大括号内所有条件为真时,规则结果为 true。
部分规则 violations[msg] { ... } 生成一个集合,每满足一次条件就向集合中添加一个元素。
默认值 default allow = false 为规则设置默认值,避免未定义导致的意外行为。
迭代 input.request.object.spec.containers[_] 使用下划线 _ 遍历数组或集合中的每个元素。

4.2.2 完整策略示例:禁止特权容器

以下是一个典型的 Kubernetes 准入控制策略,用于禁止创建特权容器:

package kubernetes.admission

import future.keywords.if
import future.keywords.in

# 默认拒绝
default deny := false

# 当容器设置了 securityContext.privileged = true 时,生成拒绝消息
deny if {
    container := input.request.object.spec.containers[_]
    container.securityContext.privileged == true
    reason := sprintf("容器 '%s' 设置了 privileged=true,违反安全策略", [container.name])
}

# 也可以使用部分规则收集所有违规消息
violations[msg] {
    container := input.request.object.spec.containers[_]
    container.securityContext.privileged == true
    msg := sprintf("容器 '%s' 不允许使用特权模式", [container.name])
}
编写建议: 始终为布尔规则(如 allow、deny)设置 default 值。在复杂策略中,优先使用部分规则(如 violations)收集多条违规信息,便于调用方一次性获取所有问题。

4.3 OPA 与 Kubernetes 集成:准入控制

OPA 与 Kubernetes 最主流的集成方式是通过 OPA Gatekeeper(基于 OPA 的 Kubernetes 专用策略控制器)。Gatekeeper 以 Admission Webhook 的形式运行,拦截资源创建/更新请求,交由 OPA 策略引擎决策。

4.3.1 集成架构

Gatekeeper 在 Kubernetes 集群中部署为三个核心组件:

  • Gatekeeper Controller: 管理 ConstraintTemplate 和 Constraint 自定义资源,将策略模板实例化。
  • OPA Agent (sidecar): 内嵌在 Gatekeeper 的 Webhook Pod 中,加载策略并处理准入请求。
  • Admission Webhook: 注册到 Kubernetes API Server,拦截 CREATE 和 UPDATE 操作。
OPA Gatekeeper 集成架构 OPA Gatekeeper 集成架构 K8s API Server (Admission Webhook 调用方) Gatekeeper Webhook (OPA Agent + 控制器) ConstraintTemplate Constraint AdmissionReview 引用模板 实例化策略 AdmissionResponse 集成工作流: 1. 用户执行 kubectl apply,API Server 构造 AdmissionReview 请求。 2. Gatekeeper Webhook 接收请求,OPA 根据 Constraint 和 ConstraintTemplate 执行策略。 3. OPA 返回 allow/deny 决策,Gatekeeper 封装为 AdmissionResponse 返回 API Server。

4.3.2 ConstraintTemplate 与 Constraint

Gatekeeper 通过两个 CRD 实现策略的模板化和参数化:

CRD 作用 示例
ConstraintTemplate 定义 Rego 策略模板,声明参数 schema 和 Rego 代码。 k8srequiredlabels 模板要求资源必须包含指定标签。
Constraint 实例化模板,传入具体参数(如标签键值对)。 require-team-label 实例要求所有 Namespace 必须有 team 标签。

4.3.3 集成最佳实践

生产注意事项: Gatekeeper 的 Webhook 超时时间默认为 3 秒,复杂策略应优化 Rego 查询性能,避免超时导致资源创建失败。建议在策略中使用 index 和 comprehension 优化,并开启 OPA 的 --cache 选项。
  • 策略分层: 将通用策略(如标签校验)与业务策略(如升级窗口控制)分离,分别部署为不同的 ConstraintTemplate。
  • 审计模式: 新策略上线前先使用 enforcementAction: dryrun 运行一段时间,观察违规记录再切换为 deny。
  • 数据同步: 利用 Gatekeeper 的 data.inventory 功能同步集群资源状态,实现跨资源策略(如检查 Service 对应的 Deployment 是否存在)。
  • 监控告警: 暴露 OPA 的决策指标(opa_decision_duration_seconds、opa_http_request_duration_seconds)到 Prometheus,设置策略拒绝率告警。