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 策略评估流程
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 策略版本与环境的映射
2.5 策略即代码的 CI/CD 集成
将策略管理纳入 CI/CD 流水线,确保每次策略变更都经过自动化验证:
- 代码提交:开发者提交 Rego 策略变更到特性分支。
- 自动格式化检查:使用
opa fmt检查代码风格。 - 单元测试:运行
opa test执行所有测试用例。 - 策略覆盖率报告:生成测试覆盖率,要求不低于 90%。
- 构建策略捆绑包:将策略打包为版本化的
.tar.gz文件。 - 部署到 OPA 服务:通过 API 或 Sidecar 热更新策略。
关键指标:
- 策略测试覆盖率 ≥ 90%
- 策略评估延迟 ≤ 10ms(P99)
- 策略变更到生产部署时间 ≤ 30 分钟
- 策略回滚时间 ≤ 5 分钟
通过以上基础建设,团队可以实现策略的“代码化、版本化、自动化”,为后续跨环境迁移中的策略报告对账奠定坚实的技术基础。