2. 策略即代码基础:OPA与Rego语言入门、策略编写规范、策略版本管理

2.1 策略即代码(Policy as Code)核心思想

策略即代码(PaC)是将传统运维策略、安全规则、合规要求以代码形式进行声明、测试、版本管理和自动化执行的方法论。其核心价值在于:

  • 可追溯:每次策略变更都有 Git 提交记录,可审计、可回滚。
  • 可测试:策略可以像软件一样编写单元测试和集成测试。
  • 可复用:同一套策略库可跨环境(开发、测试、预发、生产)执行。
  • 自动化:策略评估集成到 CI/CD 流水线,实现“不合规不放行”。
关键认知: 策略即代码不是简单的“把规则写在 YAML 里”,而是将策略决策逻辑从应用代码或人工审核中解耦出来,形成独立的、可编程的决策层。

2.2 OPA 与 Rego 语言入门

2.2.1 OPA 是什么

Open Policy Agent(OPA)是一个开源的、通用的策略引擎,它将策略决策与业务逻辑分离。OPA 接受任意结构化数据(JSON/YAML)作为输入,通过 Rego 语言编写的策略进行推理,输出决策结果(allow/deny 或更复杂的结构化响应)。

特性 说明
通用性 不绑定特定平台,可集成到 Kubernetes、Terraform、CI/CD、API 网关等
声明式 用户描述“想要什么状态”,而非“如何检查”
可组合 策略可以拆分为多个包(package),通过 import 复用
无状态 每次评估独立,输入决定输出,便于缓存和水平扩展

2.2.2 Rego 语言基础语法

Rego 是 OPA 专用的声明式查询语言,受 Datalog 启发。以下是一个最小策略示例:

package example.allow

# 默认拒绝
default allow = false

# 允许条件:用户角色为 admin 且请求方法为 GET
allow {
    input.user.role == "admin"
    input.request.method == "GET"
}

核心语法要素:

  • 包(package):策略命名空间,如 package kubernetes.admission。
  • 规则(rule):形如 head { body },当 body 中所有表达式为真时,head 为真。
  • 默认值(default):为规则提供默认值,避免未定义错误。
  • 迭代(iteration):使用 some 关键字遍历集合。
  • 内置函数:如 count()、split()、regex.match() 等。
Rego 编写规范:
  • 规则体尽量保持扁平,避免深层嵌套。
  • 使用有意义的规则名称,如 allowed_containers 而非 rule1。
  • 将复杂逻辑拆分为辅助规则,提高可读性。
  • 为每个策略文件编写对应的测试文件(_test.rego)。

2.2.3 OPA 策略评估流程

OPA 策略评估流程 输入数据 (JSON) OPA 策略引擎 加载 Rego 策略 执行规则评估 Rego 策略库 决策输出 外部系统 流程:外部系统发送请求 → OPA 加载策略并评估输入 → 返回 allow/deny 或结构化决策

2.3 策略编写规范

2.3.1 文件组织规范

目录/文件 用途 示例
policies/ 存放所有 Rego 策略文件 policies/deployment.rego
tests/ 存放策略对应的测试文件 tests/deployment_test.rego
data/ 存放模拟输入数据(用于本地测试) data/input.json
Makefile 定义策略测试、格式检查、打包命令 make test

2.3.2 命名与注释规范

  • 包名:使用小写字母和点号分隔,如 package kubernetes.network。
  • 规则名:使用蛇形命名法(snake_case),如 allowed_registry。
  • 文件头注释:每个 .rego 文件顶部应包含用途说明、作者、版本。
  • 规则注释:复杂规则体前应添加注释说明逻辑意图。
# ============================================
# 策略:Kubernetes 容器镜像仓库白名单
# 版本:1.2.0
# 作者:SRE Team
# ============================================
package kubernetes.images

# 允许的镜像仓库前缀列表
allowed_registries := [
    "registry.example.com",
    "gcr.io/my-project",
]

# 检查容器镜像是否来自允许的仓库
deny[msg] {
    container := input.containers[_]
    not startswith(container.image, allowed_registries[_])
    msg := sprintf("容器镜像 %v 不在允许的仓库列表中", [container.image])
}

2.3.3 测试规范

每个策略文件应配套测试文件,使用 OPA 内置的 test 框架:

package kubernetes.images

test_allowed_image {
    # 模拟输入:使用允许的镜像
    input := {"containers": [{"image": "registry.example.com/app:v1"}]}
    count(deny) == 0
}

test_denied_image {
    # 模拟输入:使用未授权的镜像
    input := {"containers": [{"image": "docker.io/unknown:latest"}]}
    count(deny) == 1
}
常见陷阱:
  • 忘记写 default allow = false,导致未匹配规则时返回 undefined 而非拒绝。
  • 在规则体中使用 =(赋值)而非 ==(比较),导致逻辑错误。
  • 忽略 some 关键字的迭代语义,导致只检查集合中第一个元素。

2.4 策略版本管理

2.4.1 版本管理策略

策略代码与应用程序代码一样,需要严格的版本管理。推荐采用 语义化版本(SemVer):

版本号示例 变更类型 说明
1.0.0 主版本 策略逻辑发生不兼容变更(如删除规则、修改默认行为)
1.1.0 次版本 新增规则或增强现有规则,向后兼容
1.1.1 补丁版本 修复规则中的逻辑错误或性能问题,不改变策略语义

2.4.2 版本管理最佳实践

  • Git 分支策略:使用 main 分支作为稳定发布分支,develop 分支进行策略开发,特性分支(feature/xxx)用于具体变更。
  • 标签(Tag):每次发布时在 Git 中打标签,如 v1.2.0,确保可追溯。
  • 变更日志(CHANGELOG):维护 CHANGELOG.md,记录每个版本的变更摘要。
  • 策略捆绑包(Bundle):将策略文件打包为 .tar.gz,版本号嵌入文件名,如 policies-v1.2.0.tar.gz。

2.4.3 策略版本与环境的映射

策略版本与环境映射 策略版本仓库 v1.0.0 / v1.1.0 / v1.2.0 开发环境 测试环境 生产环境 v1.2.0 (最新) v1.1.0 (稳定) v1.0.0 (锁定) 原则:开发环境使用最新版本验证,测试环境使用候选版本,生产环境锁定经过验证的稳定版本

2.5 策略即代码的 CI/CD 集成

将策略管理纳入 CI/CD 流水线,确保每次策略变更都经过自动化验证:

  1. 代码提交:开发者提交 Rego 策略变更到特性分支。
  2. 自动格式化检查:使用 opa fmt 检查代码风格。
  3. 单元测试:运行 opa test 执行所有测试用例。
  4. 策略覆盖率报告:生成测试覆盖率,要求不低于 90%。
  5. 构建策略捆绑包:将策略打包为版本化的 .tar.gz 文件。
  6. 部署到 OPA 服务:通过 API 或 Sidecar 热更新策略。
关键指标:
  • 策略测试覆盖率 ≥ 90%
  • 策略评估延迟 ≤ 10ms(P99)
  • 策略变更到生产部署时间 ≤ 30 分钟
  • 策略回滚时间 ≤ 5 分钟

通过以上基础建设,团队可以实现策略的“代码化、版本化、自动化”,为后续跨环境迁移中的策略报告对账奠定坚实的技术基础。