3. Policy as Code (PaC) 基础:定义、区别与云原生价值
Policy as Code(PaC)是将策略声明、合规规则与治理逻辑以机器可读的代码形式进行管理、版本化、测试与自动执行的工程实践。它并非简单的“把策略写成YAML”,而是将策略从人工审批的静态文档,转变为可集成到CI/CD流水线中的动态执行单元。
3.1 PaC 的核心定义
PaC 通过声明式语言(如 Rego、CUE、CEL)或通用编程语言(如 Go、Python)的 DSL,将策略抽象为可重复评估的规则集合。其核心特征包括:
- 声明式表达:策略描述“期望状态”,而非“如何执行”。
- 版本化与审计:策略存储在 Git 仓库中,每次变更都有完整历史记录。
- 自动化执行:策略在部署前、部署中或运行时自动触发评估。
- 可测试性:策略可以像软件代码一样编写单元测试与集成测试。
关键概念:PaC 将策略从“人治”转向“代码治”,使合规性成为软件交付流水线中的一等公民。
3.2 与传统策略管理的区别
传统策略管理依赖静态文档、人工审核与事后检查,而 PaC 实现了策略的自动化、可编程与持续验证。下表从多个维度对比两者的差异:
| 对比维度 | 传统策略管理 | Policy as Code |
|---|---|---|
| 表达形式 | Word/PDF 文档、邮件通知 | 代码文件(.rego, .cue, .yaml) |
| 存储方式 | 共享文件夹、Wiki 页面 | Git 仓库(版本控制、分支管理) |
| 执行时机 | 事后审计、定期检查 | 实时拦截(CI/CD 门禁、准入控制) |
| 变更流程 | 邮件审批、会议讨论 | Pull Request + Code Review + 自动化测试 |
| 可测试性 | 无测试机制 | 单元测试、集成测试、模拟评估 |
| 回滚能力 | 困难,依赖人工记忆 | git revert 即可回滚到任意历史版本 |
| 扩展性 | 随组织规模线性增长,人力成本高 | 策略即代码,可复用、可组合、可共享 |
常见误区:PaC 不是简单的“把策略写成 YAML 文件”。如果 YAML 文件仍然需要人工逐行检查、没有自动化评估引擎,那它本质上还是传统策略管理,只是换了一种文件格式。
3.3 PaC 在云原生中的价值
云原生环境具有动态性、多租户、微服务化与基础设施即代码(IaC)等特征,传统策略管理方式难以应对其快速变化与复杂依赖。PaC 在云原生中的核心价值体现在以下四个层面:
- 安全左移与合规内建:策略在代码提交、镜像构建、部署编排阶段即执行检查,避免不合规配置进入生产环境。例如,禁止容器以 root 用户运行、限制镜像来源为私有仓库。
- 故障隔离的自动化保障:通过 PaC 定义“升级窗口”、“最大并发数”、“跨 AZ 分布”等策略,自动拒绝违反隔离规则的变更请求,从源头防止故障扩散。
- 多集群统一治理:在混合云或多集群场景下,PaC 作为统一的策略控制面,确保所有集群遵循相同的安全基线、资源配额与网络策略。
- 审计与可观测性增强:每次策略评估都会产生结构化日志,包含决策结果、输入上下文与触发规则,为事后审计和故障根因分析提供精确数据。
3.4 典型 PaC 工具生态
云原生领域已形成丰富的 PaC 工具链,覆盖策略定义、评估引擎与集成平台。下表列出主流工具及其适用场景:
| 工具 | 策略语言 | 主要场景 | 集成方式 |
|---|---|---|---|
| Open Policy Agent (OPA) | Rego | Kubernetes 准入控制、API 授权、IaC 扫描 | Sidecar / DaemonSet / Go SDK |
| Kyverno | YAML (DSL) | Kubernetes 原生策略管理 | Admission Webhook / CLI |
| Sentinel | Sentinel DSL | HashiCorp 生态(Terraform, Vault, Consul) | Enterprise 集成 |
| Checkov / tfsec | Python / HCL | IaC 静态扫描(Terraform, CloudFormation) | CLI / CI/CD 插件 |
| Conftest | Rego | 配置文件与 IaC 策略测试 | CLI / CI/CD 流水线 |
选型建议:如果团队已深度使用 Kubernetes,优先考虑 Kyverno(学习成本低)或 OPA Gatekeeper(生态成熟);如果策略需要跨平台(K8s + 云 API + 微服务),OPA 的通用性更强。
3.5 一个简单的 PaC 策略示例
以下使用 OPA/Rego 语言定义一个“升级窗口控制”策略,限制只能在非高峰时段(UTC 时间 02:00–06:00)执行 Deployment 更新:
package kubernetes.admission
import future.keywords.if
import future.keywords.in
# 定义允许的升级窗口(UTC 时间)
allowed_hours := {h | h >= 2; h < 6}
# 拒绝在升级窗口外变更 Deployment
deny[msg] if {
input.request.operation == "UPDATE"
input.request.kind.kind == "Deployment"
time_hour := time.now_ns() / 3600000000000 % 24
not allowed_hours[time_hour]
msg := sprintf("Deployment 更新被拒绝:当前 UTC 时间 %d:00 不在允许的升级窗口 (02:00-06:00) 内", [time_hour])
}
策略解读:该策略在 Kubernetes 准入控制器中实时拦截 Deployment 更新请求。如果当前时间不在 02:00–06:00(UTC),则返回拒绝消息。通过 PaC,升级窗口控制从“运维人员手动检查”变为“系统自动强制”,从根本上消除了人为疏忽导致的故障风险。