doctena-org/octorules

GitHub: doctena-org/octorules

octorules 是一个受 octodns 启发的 WAF 规则即代码管理工具,支持通过 YAML 声明式配置在多云环境下统一管理并部署 WAF 规则。

Stars: 3 | Forks: 0

# octorules ## WAF 规则即代码 — 以声明式方式跨提供商管理规则 秉承[基础设施即代码](https://en.wikipedia.org/wiki/Infrastructure_as_Code) 的理念,octorules 提供了工具和模式来将 WAF 和安全规则作为 YAML 文件进行管理。生成的配置可以存放在代码仓库中,并像您的其他代码一样进行部署,从而保持清晰的历史记录并使用现有的审查和工作流。 [octodns](https://github.com/octodns/octodns) 管理 DNS 记录,但无法触及 WAF 规则。**octorules** 填补了这一空白 — 每个域/策略一个 YAML 文件,应用前先规划,遇错即止 (fail-fast)。 ### 提供商生态 octorules 是与提供商无关的。每个提供商都是一个独立的包: | 包 | 提供商 | 状态 | |---|---|---| | [octorules-cloudflare](https://github.com/doctena-org/octorules-cloudflare) | Cloudflare Rules (23 个阶段) | 稳定版 | | [octorules-aws](https://github.com/doctena-org/octorules-aws) | AWS WAF v2 (4 个阶段) | 测试版 | | [octorules-google](https://github.com/doctena-org/octorules-google) | Google Cloud Armor (4 个阶段) | 测试版 | | [octorules-azure](https://github.com/doctena-org/octorules-azure) | Azure WAF — Front Door & App Gateway (3 个阶段) | 阿尔法版 | | [octorules-bunny](https://github.com/doctena-org/octorules-bunny) | Bunny.net Shield WAF (4 个阶段) | 阿尔法版 | ## 快速开始 ### 安装 为您的 WAF 安装对应的提供商包。这会自动拉取 octorules 核心: ``` pip install octorules-cloudflare # Cloudflare (includes wirefilter expression engine) pip install octorules-aws # AWS WAF v2 pip install octorules-google # Google Cloud Armor (includes cel-python) pip install octorules-azure # Azure WAF (Front Door / Application Gateway) pip install octorules-bunny # Bunny.net Shield WAF ``` 仅核心(离线 lint,无提供商): ``` pip install octorules ``` ### 配置 创建一个指向您的 zones 的配置文件: ``` # config.yaml providers: cloudflare: token: env/CLOUDFLARE_API_TOKEN rules: directory: ./rules zones: example.com: sources: - rules ``` `env/` 前缀在运行时从环境变量解析值 — 将密钥排除在 YAML 之外。这是内置的密钥处理器;有关可插拔后端(Vault、AWS Secrets Manager 等)的详细信息,请参阅 [Secret handlers](#secret-handlers)。 提供商部分下的所有键(除 `class` 和 `safety` 外)都作为关键字参数转发给提供商构造函数 — 类似于 octodns 的透传方式。有关可用设置,请参阅每个提供商的文档。 #### 多提供商设置 要跨多个提供商管理规则,请在 `providers:` 下将每个提供商添加为一个命名部分,并通过 `targets:` 将 zones 分配给提供商。当仅配置一个提供商时,`targets` 会自动分配,可以省略。有关包含所有五个提供商的完整多提供商配置,请参阅 [`examples/config.yaml`](examples/config.yaml)。 #### 多目标 zone 一个 zone 可以针对同一 **类** 的多个提供商(例如,两个 Cloudflare 账户,或生产环境 + 预发布环境)。在 `targets:` 下列出多个名称 — octorules 会针对每个目标独立规划和应用。由于自动发现无法区分同一提供商的两个实例,因此需要显式指定 `class:`。有关带注释的示例,请参阅 [`examples/config.yaml`](examples/config.yaml)。 #### 提供商自动发现 提供商类通过 `octorules.providers` 入口点组进行自动发现(已安装的提供商包会自行注册)。要覆盖自动发现,请显式设置 `class:`: ``` providers: custom: class: my_package.MyProvider api_key: env/MY_API_KEY ``` #### YAML 包含 YAML 文件支持 `!include` 指令来拆分大型配置: ``` zones: example.com: !include zones/example.yaml ``` ``` # rules/example.com.yaml redirect_rules: !include shared/redirects.yaml ``` 包含文件的解析是相对于包含该指令的文件进行的。支持嵌套包含和循环包含检测。包含操作限制在父文件的目录树内。 ### 定义规则 为每个 zone 创建一个规则文件。文件名必须与 `config.yaml` 中 `zones:` 下用作键的 zone 名称相匹配,该名称映射到提供商自己“zone”的概念: | 提供商 | Zone 概念 | Zone 名称示例 | 规则文件 | |---|---|---|---| | Cloudflare | DNS 域 | `example.com` | `rules/example.com.yaml` | | AWS WAF | Web ACL 名称 | `my-web-acl` | `rules/my-web-acl.yaml` | | Google Cloud Armor | 安全策略名称 | `my-security-policy` | `rules/my-security-policy.yaml` | | Azure WAF | WAF 策略名称 | `my-waf-policy` | `rules/my-waf-policy.yaml` | | Bunny Shield | Pull zone 名称 | `my-pull-zone` | `rules/my-pull-zone.yaml` | 映射关系为:`config.yaml` 中的 `zones.` → 磁盘上的 `rules/.yaml` → 运行时的 `resolve_zone_id("")`,后者将名称解析为提供商的内部 ID。 每条规则都需要一个 **`ref`**(稳定标识符,在阶段内唯一)和一个 **`expression`**(特定于提供商的过滤表达式)。可选字段包括 `description`、`enabled`(默认为 `true`)、`action` 和 `action_parameters`。阶段名称、可用操作和表达式语法因提供商而异 — 请参阅提供商的文档和 [`examples/rules/`](examples/rules/) 目录以获取完整的按提供商分类的示例。 #### 规则级元数据 规则支持 `octorules:` 键,用于存储控制 octorules 行为的每条规则元数据,而不会影响提供商 API。 **忽略规则** — 将规则保留在 YAML 中(用于文档记录、版本控制、审查),但在规划/同步期间跳过它: ``` waf_custom_rules: - ref: experimental-geo-block description: "Testing geo-block — not ready for production" expression: 'ip.geoip.country in {"RU" "CN"}' action: block octorules: ignored: true ``` 被忽略的规则仍会经过验证和 lint(以便在取消忽略前捕获错误),但在规划器的两侧都是不可见的 — 它们不会产生 ADD/MODIFY/REMOVE 变更,如果规则存在于上游,也不会被删除或覆盖。这与 octodns 约定一致:可以在提供商上手动编辑该规则,而不会受到 octorules 的干扰。 **针对特定提供商** — 在多提供商或多目标设置中,将规则限制为特定目标: ``` waf_custom_rules: # Only deploy to Cloudflare - ref: cf-specific-rule expression: 'http.request.uri.path matches "^/api/.*"' action: block octorules: included: - cloudflare # Deploy everywhere EXCEPT staging - ref: prod-only-rule expression: 'ip.src in $blocklist' action: block octorules: excluded: - cf-staging ``` `included` 和 `excluded` 是互斥的(符合 octodns 约定)。名称与提供商配置键相匹配(例如 `cloudflare`、`aws`、`cf-prod`)。没有 `included`/`excluded` 的规则适用于所有目标。 `octorules:` 键总是在向提供商 API 发送规则之前被剥离。 #### 多行表达式 复杂的表达式可以使用 YAML 块标量 (`|-`) 来提高可读性。octorules 会在发送给提供商之前以及在 lint 之前标准化空白字符(将换行符和缩进折叠为引号字符串外的单个空格),因此格式化纯粹是为了美观: ``` waf_custom_rules: - ref: geo-block description: Block by country outside active regions action: block expression: |- (ip.geoip.asnum in { 9009 64080 } and not ip.geoip.country in { "AT" "BE" "DE" "FR" }) ``` 使用 `|-`(去除尾随换行符)而不是 `|`(保留尾随换行符)。 ### 使用 octorules 使用单独的命令进行规划和应用 — 类似于 Terraform 的 `plan`/`apply` 拆分。WAF 规则具有很大的破坏范围(错误的规则可能会阻止所有流量),因此两步工作流强制在变更到达提供商之前进行明确的审查。这也启用了 CI 模式,即在 PR 打开时运行 `plan`(将结果作为 PR 评论发布),并在合并时运行 `sync` 并进行校验和验证以捕获偏差。 ``` # 预览变更 (dry-run) octorules plan --config config.yaml # 应用更改 octorules sync --doit --config config.yaml # 仅验证配置 (无 API 调用,适用于 CI) octorules lint --config-only --config config.yaml # 将现有规则导出为 YAML octorules dump --config config.yaml # 离线 Lint 规则文件 octorules lint --config config.yaml # 审计 IP 重叠、CDN 冲突和区域漂移 octorules audit --config config.yaml ``` ## Secret 处理程序 配置字符串值使用 `handler/reference` 语法在加载时解析密钥。内置的 `env` 处理器解析环境变量(`env/MY_TOKEN` → `$MY_TOKEN`)。您可以添加自定义处理器用于 Vault、AWS Secrets Manager、GCP Secret Manager 等。 ### 配置中声明的处理器 ``` secret_handlers: vault: class: octorules_vault.VaultSecrets url: https://vault.internal token: env/VAULT_TOKEN # bootstrap: resolved via env handler providers: cloudflare: token: vault/secret/data/cf#token # resolved via vault handler ``` 处理器 kwargs 通过已注册的处理器(env + entry-points)解析,因此您可以使用 `env/` 引导凭据。 ### 入口点发现 Secret 处理器也可以通过 `octorules.secret_handlers` 入口点组自动发现: ``` # 在您的 handler 包的 pyproject.toml 中 [project.entry-points."octorules.secret_handlers"] vault = "octorules_vault:VaultSecrets" ``` ### 编写 secret 处理器 从 `octorules.secret` 继承 `BaseSecrets`: ``` from octorules.secret import BaseSecrets, SecretsException class VaultSecrets(BaseSecrets): def __init__(self, name, url="", token=""): super().__init__(name) self.client = VaultClient(url=url, token=token) def fetch(self, ref, source): try: return self.client.read(ref) except VaultError as e: raise SecretsException(f"Vault lookup failed for {ref!r}: {e}") ``` ### 解析规则 1. 在第一个 `/` 处拆分字符串 → `(prefix, reference)` 2. 在处理器注册表中查找 `prefix` 3. 找到 → 调用 `handler.fetch(reference, source_context)` 4. 未找到 → 返回字符串不变(像 `./rules` 或 `https://...` 这样的路径会安全通过) ## 处理器 处理器挂载到规划/同步流程中,用于在规划前转换规则并在规划后过滤变更。它们对于注入共享规则、强制执行策略或抑制跨 zone 的变更非常有用。 ``` processors: add_standard_headers: class: my_package.StandardHeaderProcessor header_name: X-Frame-Options zones: example.com: sources: - rules processors: - add_standard_headers ``` 处理器是一个具有两个可选钩子的 Python 类: - **`process_desired(zone_name, desired, provider)`** — 在规划前转换所需规则字典。返回修改后的字典。 - **`process_changes(zone_name, plan, provider)`** — 在规划后转换 ZonePlan。返回修改后的计划。 两者默认为空操作(透传)。处理器按列出的顺序运行。`class` 键是必需的;所有其他键都作为 kwargs 转发。 ### 内置过滤器 octorules 在 `octorules.processor.filters` 中提供了三个现成可用的处理器: | 过滤器 | 描述 | |--------|-------------| | **PhaseFilter** | 按名称包含或排除阶段(`include`/`exclude` 列表) | | **RefFilter** | 通过 `ref` 字段上的正则表达式包含或排除规则 | | **ChangeTypeFilter** | 阻止特定的变更类型:`ADD`、`REMOVE`、`MODIFY`、`REORDER` | 有关所有三个过滤器的可行示例,请参阅 [`examples/config.yaml`](examples/config.yaml)。 ## Zone 发现 可以从支持此功能的提供商自动发现 zones。在配置中使用 `'*'` 作为 zone 模板 — octorules 在初始化时调用目标提供商上的 `list_zones()`,并为每个已发现的、具有匹配 YAML 规则文件的 zone 扩展模板。显式的 zone 配置始终优先。请参阅 [`examples/config.yaml`](examples/config.yaml) 中的通配符条目。 ## 可选功能 提供商通过 `SUPPORTS` 类变量声明可选功能支持。框架会在调用可选方法之前检查支持情况。功能包括: | 功能 | 描述 | 提供商 | |---------|-------------|-----------| | `custom_rulesets` | 账户级 WAF 规则集(规则组) | Cloudflare, AWS | | `lists` | IP/ASN/主机名/重定向/正则列表(IP 集合、正则模式集合) | Cloudflare, AWS | | `page_shield` | 内容安全策略管理 | Cloudflare | | `zone_discovery` | 通过 `list_zones()` 自动枚举 zone | Cloudflare, AWS, Google, Azure, Bunny | 有关功能详细信息和 YAML 语法,请参阅每个提供商的文档。 ## Linting `octorules lint` 对您的规则文件运行离线静态分析 — 无需 API 调用,无需凭据。Lint 规则由提供商注册;安装提供商包即可获取其规则。有关标志和选项,请参阅 CLI 参考中的 [`octorules lint`](#octorules-lint)。 抑制注释的工作方式类似于 shellcheck — 在规则之前添加 `# octorules:disable=CF015`(多个规则用逗号分隔)以抑制特定发现。审计发现使用 `# octorules:accept=ip-overlap`。 ### 核心 lint 规则 | 规则 | 严重性 | 描述 | |------|----------|-------------| | CORE002 | WARNING | rules 目录中的规则文件与任何已配置的 zone 不匹配 | | CORE003 | WARNING | 一个阶段中的所有规则均被禁用(2 条及以上规则,所有 `enabled: false`) | | CORE004 | WARNING | 在一个 zone 的多个阶段中使用了相同的 `ref` 字符串 | | CORE006 | INFO | 规则文件不包含任何实际规则(所有阶段均为空) | 特定于提供商的规则(CF、WA、GA、AZ、BN 前缀)记录在每个提供商的 `docs/lint.md` 中。 ### 配置验证(非 lint 规则) 这些检查在配置加载时运行,并发出日志警告或引发错误。它们 **不是** lint 诊断 — 无法使用 `# octorules:disable=...` 抑制它们,也不会出现在 lint 输出中。 | 检查 | 级别 | 描述 | |-------|-------|-------------| | 重复的 YAML 键 | ERROR | 在重复键时引发 `ConfigError`(静默数据丢失 — 最后一个值生效) | | 倒置的安全阈值 | WARNING | 当 `delete_threshold` < `update_threshold` 时记录警告(删除的限制比更新更宽松) | ## CLI 参考 ### `octorules plan` 试运行:显示将要更改的内容,而不触及提供商。检测到更改时退出代码为 2(使用 `--exit-code`)。输出格式和目标通过配置文件中的 `manager.plan_outputs`(默认为 stdout 上的文本)。 ``` octorules plan [--zone example.com] [--phase redirect_rules] [--checksum] [--exit-code] ``` ### `octorules sync --doit` 将变更应用到提供商。需要 `--doit` 作为安全标志。每个阶段进行原子 PUT,遇错即止。 ``` octorules sync --doit [--zone example.com] [--phase redirect_rules] [--checksum HASH] [--force] ``` | 标志 | 描述 | |------|-------------| | `--doit` | 必需的安全标志,用于确认应应用更改 | | `--checksum HASH` | 验证自 `plan --checksum` 以来计划未发生偏差 | | `--force` | 绕过安全阈值检查 | | `--audit-log PATH` | 将同步结果的 JSON 行审计日志写入文件 | | `--format json` | 将结构化的 JSON 结果打印到 stdout(zone、状态、已同步阶段、错误) | ### `octorules rule` 浏览和搜索 lint 规则目录。 ``` octorules rule --all # List all rules octorules rule CF # Filter by prefix octorules rule CF201 # Show one rule octorules rule --all --format json # JSON output ``` ### `octorules dump` 将现有的提供商规则导出到 YAML 文件。用于引导或导入现有设置。 ``` octorules dump [--zone example.com] [--output-dir ./rules] ``` ### `octorules lint` 离线 lint 规则文件,检查错误、警告和样式问题。支持文本、JSON、SARIF 和摘要输出。 ``` octorules lint [FILE] [--config-only] [--format text|json|sarif] [--severity error|warning|info] [--plan free|pro|business|enterprise] [--rule RULE_ID] [--output PATH] [--exit-code] ``` | 标志 | 描述 | |------|-------------| | `FILE` | Lint 单个规则文件(无需配置)。省略时,使用配置文件发现所有 zones | | `--config-only` | 仅验证配置文件结构(跳过规则文件) | | `--format` | 输出格式:`text`(默认)、`json`、`sarif`、`summary` | | `--severity` | 要报告的最低严重性(默认:`info`) | | `--plan` | 用于权限检查的计划层级(默认:`enterprise`) | 当未指定 `--plan` 时,`lint` 会读取 `.zone_plans_cache.json`(由 `plan`、`sync` 和 `dump` 自动写入)以进行自动的逐 zone 层级检测。如果 `--plan` 和缓存都未提供层级,则假定为 `enterprise`(最宽松,误报最少)。将 `.zone_plans_cache.json` 添加到您的 `.gitignore` 中 — 它不包含密钥,仅包含 zone 到层级的映射。 | `--rule` | 仅检查特定的规则 ID;可重复使用 | | `--output` | 将结果写入文件而不是 stdout | | `--exit-code` | 遇到错误时退出代码为 1,遇到警告时退出代码为 2(用于 CI) | ### `octorules audit` 审计规则是否存在跨规则 IP 重叠、被遮蔽的规则、CDN 范围冲突和跨 zone 不一致。处理 rules 目录中的每个 `*.yaml` 文件(不仅是已配置的 zones)。无需 API 凭据。 ``` octorules audit [--check ...] [--severity error|warning|info] [--format text|json] [--output FILE] [--exit-code] [--cdn-timeout N] [--cdn-stale-days N] ``` | 标志 | 描述 | |------|-------------| | `--check` | 仅运行特定的检查;可重复使用(默认:全部) | | `--severity` | 要报告的最低严重性(默认:`info`) | | `--format` | 输出格式:`text`(默认)、`json`、`summary` | | `--output` | 将结果写入文件而不是 stdout | | `--exit-code` | 遇到错误时退出代码为 1,遇到警告时退出代码为 2(用于 CI) | | `--cdn-timeout` | CDN 范围 API 获取的超时时间(秒)(默认:15) | | `--cdn-stale-days` | 如果内置的 CDN 范围早于 N 天,则发出警告(默认:60) | **检查项:** - **ip-overlap** -- zone 内的跨规则和跨列表 IP 范围重叠。 - **ip-shadow** -- 被早期阶段中更广泛的规则遮蔽的规则(例如,速率限制规则,其 IP 已被 WAF 规则阻止)。 - **cdn-ranges** -- 匹配已知 CDN 提供商 IP 范围(Cloudflare、AWS CloudFront、Google Cloud)的规则。从公共 API 获取最新范围;离线时回退到内置数据。 - **zone-drift** -- 不同 zone 对同一 CIDR 的处理方式不同(例如,在 zone A 中阻止,在 zone B 中允许)。 接受注释会抑制已知发现(检查名称必须小写): ``` # octorules:accept=zone-drift # octorules:accept=ip-overlap,cdn-ranges ``` ### `octorules versions` 打印 octorules 和关键依赖项的版本。 ``` octorules versions ``` ### 通用标志 | 标志 | 描述 | |------|-------------| | `--config PATH` | 配置文件路径(默认:`config.yaml`) | | `--zone NAME` | 处理单个 zone(默认:全部) | | `--phase NAME` | 限制为特定阶段;可重复使用 | | `--scope SCOPE` | 范围:`all`(默认)、`zones` 或 `account` | | `--debug` | 启用调试日志记录 | | `--quiet` | 抑制所有信息性 stdout 输出(计划表格、lint 结果、审计发现)。仅报告错误和退出代码。文件输出(`--output`)不受影响 | ### 环境变量 | 变量 | 效果 | |----------|--------| | `NO_COLOR` | 禁用彩色终端输出(任何值,包括空值) | | `FORCE_COLOR` | 即使 stdout 不是 TTY 也强制彩色输出 | `NO_COLOR` 优先于 `FORCE_COLOR`。参见
标签:AppImage, AWS WAF, Azure WAF, Cloudflare, DevSecOps, EC2, Google Cloud Armor, IaC, MITRE ATT&CK, Python, WAF, Web应用防火墙, YAML, 上游代理, 二进制发布, 声明式配置, 多云管理, 安全可观测性, 安全库, 开源工具, 无后门, 版本控制, 网络安全, 自动化运维, 规则管理, 逆向工具, 隐私保护