diff --git a/docs/config.ts b/docs/config.ts index 0a44fe63..cab01868 100644 --- a/docs/config.ts +++ b/docs/config.ts @@ -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' } diff --git a/docs/design/architecture.md b/docs/design/architecture.md index 1284771c..4f83a43e 100644 --- a/docs/design/architecture.md +++ b/docs/design/architecture.md @@ -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#仓库结构)**:明确各个物理目录分层职责,避免堆砌和重复开发。 diff --git a/docs/design/index.md b/docs/design/index.md index 78cf8b56..4bdbaf6e 100644 --- a/docs/design/index.md +++ b/docs/design/index.md @@ -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) | diff --git a/docs/design/waf-design.md b/docs/design/waf-design.md index e04259fc..9658b98b 100644 --- a/docs/design/waf-design.md +++ b/docs/design/waf-design.md @@ -1,5 +1,7 @@ # WAF 设计文档 +> WAF 规则正在从固定的白名单、黑名单、PoW 判定链演进为可视化 DAG。新的图模型、执行顺序、发布加载和迁移边界以 [WAF 可编排规则设计](./waf-orchestration-design.md) 为准;本文保留 IP 组、GeoIP 与现有运行时背景说明。 + 你会学到:OpenFlare 边缘 Web 应用防火墙(WAF)的核心架构、动态 IP 组异步差分同步模型、OpenResty Lua 高性能缓存方案以及完整的请求过滤与判定逻辑。 --- diff --git a/docs/design/waf-orchestration-design.md b/docs/design/waf-orchestration-design.md new file mode 100644 index 00000000..6cc622fd --- /dev/null +++ b/docs/design/waf-orchestration-design.md @@ -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`。