docs(waf): design composable rule graph

This commit is contained in:
ryan
2026-07-13 11:14:10 +08:00
parent 43e293e062
commit 30e09f5985
5 changed files with 134 additions and 5 deletions
+1
View File
@@ -130,6 +130,7 @@ function sidebarDesign(): DefaultTheme.SidebarItem[] {
{ text: 'Agent 与发布模型', link: 'agent-design' },
{ text: '内网穿透隧道设计', link: 'tunnel-design' },
{ text: 'WAF 设计', link: 'waf-design' },
{ text: 'WAF 可编排规则设计', link: 'waf-orchestration-design' },
{ text: 'Pages 静态托管设计', link: 'pages-design' },
{ text: 'Uptime Kuma 监控同步设计', link: 'kuma-design' },
{ text: '登录验证码设计', link: 'login-captcha' }
+6 -4
View File
@@ -130,8 +130,10 @@ OpenResty (Agent, TLS/WAF)
### 3. WAF 安全过滤流
* WAF 引擎嵌入在 OpenResty 请求生命周期中。
* 过滤规则直接从 Agent 落地在节点本地的 `waf_config.json` 及 `waf_ip_groups.json` 读取,判决逻辑白名单优先、黑名单层层过滤,完全在本地内存中完成,不产生数据库或网络 I/O 损耗。
* *IP组增量同步、自动 IP 组计算与拦截响应机制详见:[WAF 设计文档](./waf-design.md)*
* WAF 规则由控制面以可视化 DAG 编排,发布时编译为运行态图;OpenResty reload 后由每个 Worker 加载一次,后续请求只遍历内存对象。
* 全局规则固定前置,路由绑定规则按显式顺序执行;当前规则抵达“通过”后继续下一条,抵达“阻止”则立即返回该节点配置的拦截响应。
* IP 组成员独立热更新:协调 Worker 每 5 秒检查一次 checksum,仅在变化时加载完整快照,各 Worker 的请求路径始终读取本地内存对象。
* *IP 组来源与同步机制详见:[WAF 设计文档](./waf-design.md);图模型、执行语义与发布约束详见:[WAF 可编排规则设计](./waf-orchestration-design.md)。*
---
@@ -156,7 +158,7 @@ OpenResty (Agent, TLS/WAF)
| 全局单激活版本 | 降低控制面复杂度,保证所有节点默认一致;提供一键秒级回滚的稳定机制 |
| Zone 域名与路由策略分离 | Zone 提供根域入口与域名边界;路由仍可复用同一套站点级策略并按域名绑定证书 |
| 内网穿透基于 frp 整合 | 复用成熟隧道协议,避免自研隧道引起稳定性风险;其 Vhost 机制天然适配反代路由 |
| 运行时配置与控制库解耦 | 如 WAF 运行时只读取本地 JSON 规则包,配置变更通过差分广播或快速重载热生效 |
| 运行时配置与控制库解耦 | WAF 规则发布时编译并随 OpenResty reload 加载;动态 IP 组通过 checksum 驱动的内存快照独立刷新 |
---
@@ -169,7 +171,7 @@ OpenResty (Agent, TLS/WAF)
4. **细分领域设计**:
* Zone 与域名相关开发:阅读 [Zone 与域名资源设计](./zone-design.md)。
* 穿透相关开发:阅读 [内网穿透隧道设计](./tunnel-design.md)。
* WAF 相关开发:阅读 [WAF 设计](./waf-design.md)。
* WAF 相关开发:阅读 [WAF 设计](./waf-design.md) 与 [WAF 可编排规则设计](./waf-orchestration-design.md)。
* Pages 托管开发:阅读 [Pages 静态托管设计](./pages-design.md)。
* 监控同步开发:阅读 [Uptime Kuma 监控同步设计](./kuma-design.md)。
5. **[仓库结构](./index.md#仓库结构)**:明确各个物理目录分层职责,避免堆砌和重复开发。
+1 -1
View File
@@ -24,7 +24,7 @@ OpenFlare 适合需要统一管理多台 OpenResty 代理节点的团队,具
| **反代配置管理** | 以网站规则(Proxy Route)为聚合边界,支持多域名与多上游负载均衡 | [新建反代配置](../guide/proxy-config.md) |
| **Zone 与域名管理** | 以可注册根域为管理入口,聚合明确域名、域名证书与反代路由 | [Zone 与域名资源设计](./zone-design.md) |
| **配置版本控制** | 支持全局单一激活版本的预览、发布、不可变快照历史与秒级一键回滚 | [Agent 与发布模型](./agent-design.md) |
| **WAF 安全防护** | 全局与自定义规则组,支持手动/自动/订阅型 IP 组,GeoIP 准入与 PoW CC 防护 | [WAF 设计](./waf-design.md) / [WAF 使用指南](../guide/waf-usage.md) |
| **WAF 安全防护** | 支持可视化 DAG 编排规则、手动/自动/订阅型 IP 组、GeoIP 匹配与 PoW CC 防护 | [WAF 设计](./waf-design.md) / [WAF 可编排规则设计](./waf-orchestration-design.md) / [WAF 使用指南](../guide/waf-usage.md) |
| **内网穿透** | 通过中继节点(Relay)与内网客户端(OpenFlared),反向穿透暴露内网 Web 服务 | [内网穿透设计](./tunnel-design.md) / [穿透使用指南](../guide/tunnel-usage.md) |
| **Pages 静态托管** | 直接上传前端 zip 包,由边缘节点拉取并由 OpenResty 本地服务,支持 API 反代与 SPA Fallback | [Pages 静态托管设计](./pages-design.md) |
| **TLS 证书自动续期** | 将证书显式绑定到 Zone 域名,并通过 ACME 协议向 Let's Encrypt 申请/续期证书 | [Zone 与域名资源设计](./zone-design.md) |
+2
View File
@@ -1,5 +1,7 @@
# WAF 设计文档
> WAF 规则正在从固定的白名单、黑名单、PoW 判定链演进为可视化 DAG。新的图模型、执行顺序、发布加载和迁移边界以 [WAF 可编排规则设计](./waf-orchestration-design.md) 为准;本文保留 IP 组、GeoIP 与现有运行时背景说明。
你会学到:OpenFlare 边缘 Web 应用防火墙(WAF)的核心架构、动态 IP 组异步差分同步模型、OpenResty Lua 高性能缓存方案以及完整的请求过滤与判定逻辑。
---
+124
View File
@@ -0,0 +1,124 @@
# WAF 可编排规则设计
本文定义 OpenFlare WAF 从固定判定链重构为可视化有向无环图(DAG)的目标架构、数据模型、执行语义、发布模型与迁移边界。IP 组的来源与成员计算仍遵循 [WAF 设计](./waf-design.md),本文只改变规则如何组合和执行。
## 目标与边界
用户新增 WAF 规则时只输入名称。Server 随即创建一张合法的默认图 `开始 → 通过`,前端进入基于 React Flow 的独立编排页面。用户通过添加处理单元、配置节点并连接分支构建策略,不再填写固定顺序的黑白名单与 PoW 表单。
第一阶段支持以下节点:
| 节点 | 数量约束 | 输入 | 输出 | 配置 |
| --- | --- | --- | --- | --- |
| 开始 | 每张图恰好一个 | 无 | `next` | 无 |
| 通过 | 每张图恰好一个 | 一个或多个 | 无 | 无 |
| 阻止 | 可创建多个 | 一个或多个 | 无 | HTTP 状态码、HTML 响应体 |
| IP 匹配 | 可创建多个 | 一个或多个 | `true`、`false` | IP、CIDR、IP 组 ID |
| 地域匹配 | 可创建多个 | 一个或多个 | `true`、`false` | 国家代码、地区代码 |
| PoW | 可创建多个 | 一个或多个 | `next` | 算法、难度、会话 TTL、挑战 TTL |
IP 匹配和地域匹配不区分黑名单或白名单。`true` 只表示请求匹配节点配置,`false` 只表示未匹配;放行或阻止的业务含义完全由连线决定。PoW 验证完成后沿 `next` 继续,未完成时由挑战页面接管当前请求,不产生 `false` 分支。
不在第一阶段实现循环、脚本节点、任意表达式节点、子图调用和跨规则跳转。
## 控制面架构
规则图采用控制面编辑态和数据面运行态分离的双模型:
1. React Flow 编辑器提交版本化图 JSON,其中包含节点 ID、节点类型、显示名称、坐标、类型化配置和连线。
2. Server 对整张图执行权威校验,通过后以单个事务保存图并递增修订号。
3. 配置发布时,Server 再次校验所有启用规则,将图编译为不含坐标、标签等 UI 字段的紧凑运行时 DAG,并收集被引用的 IP 组 ID。
4. Agent 原子落盘完整发布快照并 reload OpenResty。新 Worker 启动时只加载和解析一次规则 JSON。
5. 请求热路径只遍历 Worker 内存中的不可变运行时图,不读取文件、不计算 checksum、不解析 JSON。
编辑态 JSON 使用明确的 `schema_version`。节点配置使用按节点类型区分的结构,不允许用无约束键值对象绕过 Server 校验。初始安全上限为每条规则 128 个节点、256 条边和 256 KiB 编辑态 JSON;这些限制由 API 和发布编译器共同执行。
## 图结构约束
规则保存与发布必须满足全部约束:
* 图是有向无环图,禁止自环和任意循环。
* 恰好存在一个开始节点和一个通过节点;阻止节点可以存在多个。
* 开始节点无入边且恰好有一个 `next` 出口;通过和阻止节点无出口。
* IP 匹配与地域匹配的 `true`、`false` 出口必须各连接一次;PoW 的 `next` 必须连接一次。
* 除终止节点外不得存在悬空出口;每个非开始节点至少有一条入边。
* 所有节点都必须从开始节点可达,且从每个可执行节点出发都能抵达通过或阻止。
* 边的源端口必须属于源节点类型;同一源端口不得连接多个目标。
* 节点 ID 在图内唯一,边 ID 在图内唯一,所有边引用的节点必须存在。
* 节点配置必须通过对应类型的字段、范围、引用存在性和体积校验。
前端提供即时校验和连线限制以改善体验,但 Server 是唯一权威校验方。删除节点时前端同步删除关联边并将规则标记为未保存;图恢复合法前禁止保存。
## 多规则执行语义
一个路由可以绑定多条自定义规则。绑定关系是有序列表,并遵循以下顺序:
1. 启用的全局规则固定最先执行,不参与路由侧排序。
2. 路由绑定的启用规则按绑定顺序依次执行。
3. 当前规则抵达阻止节点时立即输出该节点配置的响应并终止请求。
4. 当前规则抵达通过节点时,只表示当前规则执行完成;若仍有后续规则则继续执行。
5. 全部规则均抵达通过节点后,请求才真正放行并进入后续 OpenResty/回源链路。
运行时图在发布前已经过完整校验。若 Lua 执行器仍遇到未知节点、未知端口、缺失目标或超过节点步数上限,则记录限频错误并阻止请求,避免损坏的安全配置意外放行。
## IP 组内存刷新
规则拓扑只在发布并 reload OpenResty 时生效;IP 组成员仍可由手动、订阅或自动任务独立更新,不要求发布或 reload。
IP 组采用协调 Worker、共享快照和 Worker 本地对象的两级缓存:
1. 请求始终读取当前 Worker 内存中的 IP 组对象,不访问文件或共享字典中的 JSON。
2. 每 5 秒只有一个取得共享锁的 Worker 读取轻量 checksum 文件。
3. checksum 未变化时立即结束,不读取完整 `waf_ip_groups.json`。
4. checksum 变化时,协调 Worker 读取并验证一次完整 JSON,再把原始快照与新版本写入 `ngx.shared`。
5. 其他 Worker 发现共享版本变化后,从共享内存取得快照、解析并原子替换各自的本地对象,不重复读取磁盘。
6. 刷新失败时继续使用上一份有效对象,限频记录错误,并在下一周期重试。
Agent 必须先原子替换 IP 组 JSON,最后原子更新 checksum,使 Worker 永远不会把半写入文件识别为新版本。
## API 与编辑器
创建接口只接受规则名称,创建成功后返回带默认图的规则详情。规则元数据、图保存和路由绑定使用独立操作,避免修改启用状态或绑定时覆盖画布。
图详情包含 `revision`。保存请求提交 `revision + graph`,Server 仅在修订号匹配时更新并递增修订号;不匹配时返回冲突,前端提示重新加载,禁止静默覆盖其他页面的修改。路由绑定接口接受有序规则 ID 数组。
React Flow 编辑页采用全宽画布和固定右侧属性栏:
* 顶部提供返回、规则名称、启用状态、校验状态和保存操作。
* 画布支持缩放、平移、框选、删除、自动布局和 MiniMap/Controls 等必要导航能力。
* “添加处理单元”提供 IP 匹配、地域匹配、PoW 和阻止;开始与通过由默认图提供且不可删除或重复添加。
* 选中节点后在右侧属性栏编辑配置,画布与上下文始终可见。
* 离开存在未保存变更的页面前必须提示;保存冲突和 Server 校验错误应定位到相关节点或边。
WAF 列表展示规则名称、启用状态、节点数量、应用路由数量和更新时间。新建规则的对话框只有名称字段,成功后立即导航到编排页面。
## 持久化与迁移
规则记录增加版本化图 JSON 与修订号;绑定记录增加执行顺序。图作为一个聚合整体保存,不拆成节点表和边表,以保证编辑操作的事务边界,并让新增节点类型不必频繁扩展数据库 Schema。
升级现有安装时:
* 保留规则名称、全局标记、启用状态及路由绑定关系。
* 所有规则图重置为 `开始 → 通过`,不迁移旧 IP/地域名单、PoW 或拦截响应配置。
* 现有绑定按稳定顺序写入顺序字段;全局规则仍固定前置。
* 新图和运行时稳定后移除旧规则字段、固定顺序编译逻辑和旧前端表单,不长期维护双执行器。
该迁移会让旧防护配置停止生效,升级说明必须显著提示管理员在发布下一版本前重新编排规则。
## 发布、失败与回滚
规则图只在配置发布时生效。发布前校验或编译失败时拒绝发布,当前活动版本保持不变。Agent 写入、OpenResty 配置检查或 reload 失败时,应用流程失败并恢复上一份有效发布版本。
新 Worker 只接受完整且可解析的规则运行态配置。旧 Worker 在 OpenResty 优雅 reload 期间继续使用旧内存图,新 Worker 使用新图,因此请求不会观察到半更新状态。
地域数据库不可用时,地域匹配返回 `false` 并限频告警,保持现有行为。IP 组刷新失败时保留旧内存快照。PoW 未完成由挑战模块接管请求,不视为执行错误。
## 测试与验收
* Go 单元测试覆盖图结构、端口、可达性、终止性、节点配置、体积限制、编译结果、修订冲突和绑定顺序。
* 数据库测试覆盖 PostgreSQL/SQLite 迁移、默认图、旧绑定稳定排序和回滚。
* Lua 测试覆盖所有节点出口、多规则顺序、全局规则前置、多个阻止响应、PoW 接管和损坏运行时图保护。
* Agent/OpenResty 测试覆盖发布 reload、加载一次、失败回滚、IP 组五秒 checksum 刷新和旧快照保留。
* 前端测试覆盖创建后导航、特殊节点唯一性、连线限制、属性编辑、即时校验、未保存提示和并发冲突。
* 集成测试从控制面创建并编排规则,发布后用真实请求验证放行、阻止、PoW 和 IP 组热刷新。
* API 变更后运行 `make swagger`;完成实现后运行前端检查与构建以及 `make code-check`。