4. Policy Check 核心原则:策略即代码(Policy as Code)
在传统合规审计中,策略通常以 PDF 文档、Word 表格或邮件形式存在,依赖人工解读与执行。Policy Check 将这一过程彻底重构为 策略即代码(Policy as Code, PaC) 模式,使合规规则成为可版本管理、可自动验证、可集成到 CI/CD 管线的代码资产。
4.1 策略即代码的核心价值
- 可版本化:策略文件纳入 Git 等版本控制系统,每次变更都有审计轨迹。
- 可自动化:无需人工逐条核对,由引擎自动评估基础设施或应用配置。
- 可测试:为策略编写单元测试,确保规则逻辑正确。
- 可复用:同一套策略可在开发、预发、生产环境一致执行。
- 可追溯:策略变更与合规报告一一对应,满足监管取证要求。
关键认知:策略即代码不是简单的“把规则写成 YAML”,而是将合规知识转化为可执行、可断言、可组合的代码逻辑,使审计从“事后检查”变为“事前预防”和“事中控制”。
4.2 声明式 vs 命令式策略:两种范式对比
Policy Check 支持两种策略定义范式,理解其差异是正确编写策略的前提。
| 维度 | 声明式(Declarative) | 命令式(Imperative) |
|---|---|---|
| 核心思想 | 描述“目标状态是什么” | 描述“如何检查或修复” |
| 表达方式 | 数据驱动,规则 = 条件 + 预期值 | 逻辑驱动,规则 = 步骤 + 断言 |
| 可读性 | 高,接近自然语言或配置规范 | 中,需要理解控制流 |
| 幂等性 | 天然幂等,只描述结果 | 需自行保证幂等 |
| 适用场景 | 资源合规、配置基线、安全策略 | 复杂逻辑校验、多步骤编排、自定义修复 |
| Policy Check 示例 | Rego / CUE / HCL | Python / JavaScript / Shell |
实践建议:优先使用声明式策略定义基线规则,仅在需要复杂条件分支或动态修复时引入命令式策略。Policy Check 引擎支持两种范式混合编排。
4.3 声明式策略示例:Rego 语言
以下是一个典型的声明式策略,检查所有 Kubernetes 容器是否设置了 CPU 和内存限制:
package kubernetes.admission
# 默认允许
default allow = true
# 拒绝未设置资源限制的容器
allow {
input.request.operation == "CREATE"
container := input.request.object.spec.containers[_]
container.resources.limits.cpu != null
container.resources.limits.memory != null
}
# 违反策略时返回详细消息
deny[msg] {
input.request.operation == "CREATE"
container := input.request.object.spec.containers[_]
not container.resources.limits
msg := sprintf("容器 %v 未设置资源限制", [container.name])
}
4.4 命令式策略示例:Python 脚本
当需要执行外部 API 调用或复杂数据聚合时,命令式策略更为灵活:
import requests
def check_cert_expiry(endpoint, warning_days=30):
"""检查 TLS 证书是否即将过期"""
response = requests.get(f"https://{endpoint}", verify=True)
cert = response.connection.sock.getpeercert()
expiry = datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y %Z')
remaining = (expiry - datetime.utcnow()).days
if remaining <= 0:
return {"status": "FAIL", "message": f"证书已过期"}
elif remaining <= warning_days:
return {"status": "WARN", "message": f"证书将在 {remaining} 天后过期"}
else:
return {"status": "PASS", "message": f"证书有效期剩余 {remaining} 天"}
4.5 策略范式选择决策流程
4.6 策略即代码的工程化实践
常见陷阱:不要将所有策略都写成命令式脚本。命令式策略虽然灵活,但可读性差、测试成本高、难以审计。建议 80% 的基线策略使用声明式,仅 20% 的复杂场景使用命令式。
在 Policy Check 中实施策略即代码时,应遵循以下工程化步骤:
- 策略建模:将合规需求转化为可量化的规则条件。
- 代码编写:选择声明式或命令式范式实现规则。
- 单元测试:为每条策略编写正向和反向测试用例。
- 版本管理:将策略代码与基础设施代码一同纳入 Git 仓库。
- CI/CD 集成:在流水线中自动执行策略检查,阻断不合规变更。
- 审计报告:每次策略执行生成结构化报告,包含通过/失败详情。
4.7 声明式与命令式策略对比总结
| 对比项 | 声明式策略 | 命令式策略 |
|---|---|---|
| 学习曲线 | 低,领域特定语言(DSL) | 中高,通用编程语言 |
| 执行效率 | 高,可并行评估 | 中,依赖运行时 |
| 调试难度 | 中,需理解 DSL 语义 | 低,标准 IDE 支持 |
| 策略组合 | 内置 AND/OR/NOT 逻辑 | 需手动编排 |
| 修复能力 | 仅检测,不自动修复 | 可包含修复逻辑 |
| 审计友好度 | 高,规则即文档 | 中,需额外注释 |
最佳实践:在 Policy Check 项目中,建议将声明式策略作为默认选择,仅在需要调用外部系统、执行复杂数学计算或实现动态修复时,才使用命令式策略。两种范式可以通过统一的策略引擎编排层无缝协作。