核心概念

领域模型

Tiyi 的领域被刻意保持得很小。七个一等资源覆盖了所有运维动作、所有 CLI 命令、所有 UI 页面。理解了这些,产品的其他部分就显而易见了。

七个资源

站点(Site)
Tiyi 代理的一个 HTTP 主机。携带 TLS 设置、上游池引用与挂载的 WAF 策略。是你启用或停用的最小单元。
上游池(Upstream pool)
站点背后的一组后端。轮询或加权负载均衡、SNI 感知健康检查,可在多个站点之间共用。
证书(Certificate)
一对 TLS 密钥。要么上传(自签、CA 购买、企业签发),要么ACME 签发(HTTP-01 或 DNS-01)。在静态用 KEK 信封加密。
WAF 策略(Policy)
Coraza 在每个请求上执行的编译产物。CRS Core 层 + HTTP 策略 + 限制 + 规则调优 + IP 列表 + 自定义规则 + 插件 + 限速 + 排除项。
节点(Agent)
运行数据平面(Caddy + Coraza)的一台机器。通过长连 gRPC 流从主节点接收已签名的配置 bundle。
遥测汇总(Telemetry rollup)
开桶管道产生的计数器与 Top-K 采样。驱动 dashboard、Top-K 浏览器与 Prometheus 导出器。
审计行(Audit row)
每一次变更对应一行哈希链记录,归属到 JWT subject。这是合规面 —— 每一次变更都有一份防篡改回执。

站点与上游池

站点把主机名绑到 TLS 设置、上游池与 WAF 策略上。写入器在 apply 时把每一个启用的站点翻译成一个 Caddy server 块 —— Caddy JSON 是编译目标,不是存储格式

上游池默认与站点解耦。一个池可以背后挂多个站点;删除被引用的池会被拒绝并附带 UPSTREAM_IN_USE 与引用列表。站点也可以使用内联 upstream URL 作为不需要复用的特例。

访问日志录入模式

每个站点有一个 recording_mode 字段控制访问日志体量:

无论访问日志模式如何,安全事件(Coraza 规则命中)都会被写入。

证书

TLS 材料是一等资源 —— 永远不内联到站点上。Tiyi 支持四种签发路径,全部用从 crypto.kek_file 加载的 32 字节 KEK 在静态时信封加密:

Dashboard 把 certs_expiring_14d / certs_expiring_30d / acme_renewals_failed_24h / acme_orders_pending 暴露为 KPI。首次启动种入两个默认告警:证书即将到期ACME 续期失败

WAF 策略

策略是一个结构化的领域对象,apply 时编译成 Coraza SecLang。编译器是确定的 —— 同样的策略输入产生同样的 SecLang 输出。12 个可调层(按应用顺序):

  1. CRS Core —— 偏执等级、阻断与执行 PL、入站/出站阈值、采样。
  2. HTTP 策略 —— 方法、版本、Content-Type、字符集、受限扩展名/Header、方法覆盖。
  3. 限制 —— 6 个数值字段:最大请求体、最大响应体等,CRS 默认值作为 placeholder。
  4. 规则调优 —— 按规则的覆盖:DEFAULTDISABLELOG_ONLYSCORE_OVERRIDE,可选限定到单个站点。
  5. IP 列表 —— 允许 / 拒绝 / 监控列表。条目可以是 CIDR 或 geo:CC 伪条目(alpha-2/alpha-3 国家代码加 PRIVATE / LOOPBACK)。
  6. 自定义规则 —— 运维写的 SecLang 或可视化规则,ID 在 8000000–8999999 区间。
  7. 插件 —— CRS 排除包(WordPress、Drupal、Nextcloud、phpBB、phpMyAdmin、XenForo、cPanel、DokuWiki)。支持离线归档导入。
  8. 限速 —— 按端点与按客户端范围的桶,动作可选阻断或仅记录。
  9. 排除项 —— 阶段-1 的 tx.crs_exclusions_<slug> 选项,可选用 @beginsWith 限定。
  10. 预览 —— 当前版本的只读 SecLang dump。
  11. 版本 —— 每次保存一个快照,任意两个版本之间并排 diff。
  12. 测试台 —— 用 fixture 请求打编译后的 bundle,不会触碰生产数据平面。

按站点覆盖会把标量字段(偏执、阈值、采样)叠加到挂载的策略上而不必 fork 它。

节点

每一个代理流量的节点都跑一个嵌入式节点 —— 包括主节点与热备。节点持有一条长连 ConnectRPC 双向流到主节点。重连循环先试主节点、再试备节点、然后用指数退避重试。备节点接受只读的节点流。

更新以 ConfigUpdate{revision, bundle, signature} 消息流转。节点用首次连接固定的 ed25519 公钥校验 bundle 签名(首次连接 TOFU,之后拒绝重新固定),检查版本号严格大于上次应用的,再 apply 到本地 Caddy 并上报结果。重放与乱序都安全 —— 更新按版本号幂等。

为什么节点保持一致?主节点的嵌入式节点没有特殊地位。它通过与任何远程节点完全相同的入网与流协议连到自己的 API 地址。这意味着数据平面在所有地方都被同一段代码路径测试 —— 不存在 "主节点是不一样的" 这种特例。

遥测

遥测作为一条并行管道运行,结束了每事件 SQL 写入。路径:

  1. 分片入流环 —— 日志转发器事件按站点 key 散到分片环。
  2. 10 秒开桶聚合 —— 分片 worker 把计数器累加到 10 秒桶。
  3. Misra-Gries Top-K —— 高基数维度(客户端 IP、路径、UA、ASN、攻击标签)的有界摘要,带 __other__ 桶让 SUM(*) 等于真实流量。
  4. 每日 SQLite 分区位于 logs/rollup_10s/YYYY-MM-DD.db;降采样器把它们幂等地折叠成 rollup_hourrollup_dayrollup_month
  5. 采样环 —— 按 IP 的 LRU + 全局环,带启动时回放的循环文件 WAL。
  6. API 树 —— 按站点的 URL 前缀树,节点数与深度均有上限;空闲叶子撤入 api_tree_archive
  7. 读路径 —— REST API 位于 /api/v1/telemetry/*,本地管理 socket 上的 Prometheus 导出器位于 /metrics

审计链

每一次变更(站点、上游、证书、策略、IP 列表绑定、限速端点、信任配置、自定义规则、告警规则等)都会向 audit_event 追加一行。每一行存:

Vben Admin 上的校验链按钮会走完整条链并确认每一段。SIEM 转发可在 siem.filter.include_audit 下把每一行审计转发到 Splunk / Elastic / Sentinel 管道。


这就是整个模型。每一个 CLI 命令、每一个 UI 页面、每一个 RPC 都作用于这七个资源中的一个。文档其余部分按名引用,不再重复定义。