2. OPA 基础:OPA 简介、Rego 语言核心概念与策略即代码

在云原生安全准入控制体系中,OPA(Open Policy Agent)已成为事实上的策略引擎标准。本章将深入剖析 OPA 的设计哲学、Rego 语言的核心语法,以及“策略即代码”这一核心理念如何重塑安全治理模式。

2.1 OPA 简介:通用策略引擎

OPA 是一个开源的、与平台无关的策略引擎,它将策略决策从具体业务逻辑中解耦。OPA 不负责执行策略(如拒绝请求),而是回答“这个请求是否被允许?”的问题。

核心设计原则: OPA 采用“决策请求-策略评估”的分离架构。任何系统(Kubernetes、API 网关、CI/CD 流水线)都可以向 OPA 发送结构化查询(Input),OPA 结合策略(Policy)和数据(Data)返回决策结果(Decision)。

OPA 的工作流程可概括为以下步骤:

  1. 输入(Input): 外部系统(如 Kubernetes API Server)将准入请求(如 Pod 创建请求)转换为 JSON 格式发送给 OPA。
  2. 策略评估: OPA 使用 Rego 语言编写的策略规则,对输入进行逻辑判断。
  3. 数据查询: 策略执行过程中,OPA 可查询外部数据源(如允许的镜像仓库列表、用户角色信息)。
  4. 决策输出: OPA 返回 allow(允许)、deny(拒绝)或带有详细原因的 violation 信息。
OPA 决策流程架构图 OPA 决策流程架构 外部系统 (K8s / API / CI) Input (JSON) OPA 策略引擎 Rego 策略评估 查询数据 数据源 (Data) Decision 决策结果 allow / deny 说明:OPA 不执行策略,只做决策。外部系统根据决策结果自行决定是否执行或拒绝。

2.2 Rego 语言核心概念

Rego 是 OPA 的原生查询语言,专为在复杂嵌套结构(如 JSON/YAML)上定义策略而设计。Rego 并非通用编程语言,而是一种声明式逻辑语言,其核心是“规则”和“查询”。

2.2.1 基本语法与规则

Rego 中的基本单元是 规则(Rule)。一个规则定义了一个决策或一个中间值。

# 定义一个简单的 allow 规则
package kubernetes.admission

# 如果 input 中的 role 是 "admin",则允许
allow {
    input.role == "admin"
}

# 如果用户属于 "ops" 团队,也允许
allow {
    input.team == "ops"
}

上述代码中:

  • package 用于组织策略,避免命名冲突。
  • allow 是规则名,OPA 默认将规则名作为决策结果。
  • { ... } 内的表达式必须全部为 true,该规则才成立。
  • 多个同名规则(如两个 allow)之间是 逻辑或(OR) 关系。

2.2.2 迭代与推导

Rego 的强大之处在于对集合的迭代和推导能力,无需显式编写循环。

# 检查容器镜像是否来自允许的仓库
deny[msg] {
    container := input.containers[_]
    not startswith(container.image, "registry.example.com/")
    msg := sprintf("容器 %v 使用了未授权的镜像仓库: %v", [container.name, container.image])
}

关键点解析:

  • input.containers[_]:[_] 是迭代语法,遍历 containers 数组中的每个元素。
  • deny[msg]:生成一个包含违规信息的集合。如果集合非空,表示存在违规。
  • sprintf:Rego 内置的字符串格式化函数。

2.2.3 内置函数与数据查询

Rego 提供了丰富的内置函数,用于字符串处理、时间比较、加密计算等。同时,OPA 支持通过 data 关键字查询外部数据。

类别 函数/语法 说明
字符串 startswith(str, prefix) 检查字符串是否以指定前缀开头
集合 array.concat(a, b) 合并两个数组
时间 time.now_ns() 获取当前时间(纳秒)
数据查询 data.allowed_registries[_] 从 OPA 的数据文档中查询允许的仓库列表
最佳实践: 将动态配置(如允许的镜像列表、用户角色)作为 Data 注入 OPA,而非硬编码在 Rego 策略中。这样策略与配置分离,更新配置无需修改策略代码。

2.3 策略即代码(Policy as Code)

“策略即代码”是将安全策略、合规规则和治理要求以代码形式进行版本管理、测试、部署和审计的实践。OPA 和 Rego 是实现这一理念的理想工具。

2.3.1 与传统策略管理的对比

维度 传统策略管理 策略即代码(OPA)
存储形式 文档、Wiki、PDF Git 仓库中的 Rego 文件
变更流程 邮件审批、手动配置 Pull Request + CI 测试 + 自动部署
可测试性 难以自动化测试 支持单元测试和集成测试
审计追溯 依赖操作日志 Git 历史 + 策略版本标签
执行一致性 依赖人工理解 机器自动执行,结果一致

2.3.2 策略即代码的流水线集成

在 DevSecOps 流水线中,策略即代码的典型工作流如下:

  1. 开发: 安全工程师在 Git 仓库中编写 Rego 策略。
  2. 测试: CI 阶段运行 opa test 命令,验证策略逻辑正确性。
  3. 打包: 将策略编译为 OPA Bundle(.tar.gz 文件)。
  4. 部署: 将 Bundle 分发到 OPA 实例或作为 Sidecar 注入。
  5. 执行: 运行时,OPA 加载最新策略,对每个准入请求进行实时评估。
策略即代码生命周期 策略即代码生命周期 1. 编写 Rego 策略 2. 测试 opa test 3. 打包 Bundle 4. 部署 OPA 实例 持续反馈与迭代 说明:策略即代码将安全治理左移到开发阶段,通过 GitOps 实现策略的版本化、可审计和自动化部署。
常见陷阱: 不要将 OPA 策略写成“万能规则”。策略应保持原子性,每个规则只关注一个安全维度(如镜像来源、特权容器、网络策略)。过度复杂的规则难以测试和维护。

2.4 本章小结