gweber/logflow-sim

GitHub: gweber/logflow-sim

一个可解释的日志管道模拟器,用于验证和迁移日志配置,确保安全检测规则不被破坏。

Stars: 0 | Forks: 0

# logflow-sim [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/92e15ba6c4123010.svg)](https://github.com/gweber/logflow-sim/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![Node](https://img.shields.io/badge/node-%E2%89%A520-brightgreen.svg)](https://nodejs.org/) [![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md) **可解释的日志管道模拟器。** 解析您的路由配置,构建一个规范化的中间表示,并模拟一条 syslog 消息通过它 — 发出每一步匹配的输入、进入的规则集、评估的条件、执行的查找、更改的变量以及触发的操作的逐步跟踪,所有信息均带有源位置。 无需调用上游守护进程。无需固定测试数据。无需对配置文本进行正则表达式处理。解析器和评估器在进程内使用 TypeScript 实现。 一个来自 [**netverdict.io**](https://netverdict.io) 的开源项目。采用 MIT 许可证。 第三方内容和商标通知见 [NOTICE.md](NOTICE.md) — rsyslog、syslog-ng、Fluent Bit、NXLog、Vector、OpenTelemetry、Logstash、Filebeat、Promtail、Fluentd、Sigma、Wireshark、MCP 和 Claude 是各自所有者的商标;logflow-sim 与其中任何一方均无关联。 ## 作为 GitHub Action 使用 **在每次 PR 上进行验证:** ``` - uses: gweber/logflow-sim@v1 with: conf-path: ./rsyslog command: test fail-on: errors ``` 诊断信息将作为内联 PR 注释显示。 **差异模式 — 阻止那些会重新路由过多真实流量的 PR:** ``` # .github/workflows/logflow-diff.yml on: pull_request jobs: diff: permissions: contents: read pull-requests: write runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: { ref: ${{ github.base_ref }}, path: base } - uses: actions/checkout@v4 with: { path: head } - uses: gweber/logflow-sim@v1 with: command: diff conf-path: base/rsyslog overlay-dir: head/rsyslog lines: head/test/fixtures/replay-corpus.log max-route-change-pct: 5 pr-comment: true ``` 该 Action 在 PR 上发布的内容: 完整示例请参见 [`examples/github-workflows/`](examples/github-workflows/)。 ## 支持的方言 | 方言 | 解析 | 发出(转换目标) | |---|---|---| | rsyslog / RainerScript | ✓ 完整 | ✓ | | syslog-ng | ✓ 完整 | ✓ | | Fluent Bit | ✓ | ✓ | | NXLog | ✓ | ✓ | | Logstash | ✓ | ✓ | | Vector | ✓ | ✓ | | OpenTelemetry Collector | ✓ | ✓ | | Filebeat | ✓ | ✓ | | Promtail (Loki) | ✓ | ✓ | | Fluentd (经典) | ✓ | ✓ | 每种方言位于 `src/core/dialects//` 下,并在 [`src/core/dialects/types.ts`](src/core/dialects/types.ts) 中实现了 `Dialect` 接口。模拟器和 UI 使用规范化的 IR — 它们与方言无关。 ## 支持的 SIEM 目标平台 logflow-sim 了解 10 个主要 SIEM 平台以及一个透传 `generic` 目标的字段词汇。迁移同时转换管道语法(方言轴)和目标平台首选的字段/值词汇(SIEM 轴) — 或者通过 `logflow-sim retag` 独立转换任一轴。 | 目标平台 | 供应商 | 线路格式 | 主要分类法 | |---|---|---|---| | `generic` | — | 透传 | (无) | | `splunk` | Splunk | JSON (HEC) | sourcetype | | `elastic-ecs` | Elastic | JSON (ECS) | event.category / event.type | | `datadog` | Datadog | JSON (Intake API) | ddsource | | `loki` | Grafana Labs | JSON (Push API) | 低基数标签 | | `graylog-gelf` | Graylog | GELF 1.1 | facility | | `microsoft-sentinel` | Microsoft | JSON (DCR) | 自定义日志表 (*_CL) | | `sumo-logic` | Sumo Logic | JSON (HTTP) | _sourceCategory | | `chronicle-udm` | Google | UDM JSON | metadata.event_type | | `qradar-leef` | IBM | LEEF 2.0 (管道) | LEEF EventID | | `arcsight-cef` | OpenText | CEF 0 (管道) | CEF EventClassID | 转换通过 [OCSF](https://schema.ocsf.io) 枢纽进行 — 每个插件都映射到/来自 OCSF,而不是直接映射到其他插件,因此添加一个新的 SIEM 在映射工作上是 O(1) 复杂度。有损转换以 `SIEM_VALUE_LOSSY` 诊断形式呈现;原始值被逐字保留。 完整参考:[`content/docs/siem-targets.md`](content/docs/siem-targets.md)。 ### 方言 × SIEM 覆盖矩阵 支持每一种组合:OCSF 枢纽使值重写与方言无关,渲染器由目标 SIEM 选择,而不是源方言。下面的矩阵显示了每种方言驱动每个目标时使用的**原生输出驱动程序** — 对于标记为 `→` 的单元格,方言通过通用的 HTTP/syslog 转发器发出,而不是特定于方言的插件。 | 方言 ↓ \ SIEM → | Splunk | Elastic | Datadog | Loki | Graylog | Sentinel | Sumo | Chronicle | QRadar | ArcSight | |---|---|---|---|---|---|---|---|---|---|---| | **rsyslog** | `omsplunkhec` | `omelasticsearch` | `omhttp`→ | `omhttp`→ | `omfwd`+GELF | `omhttp`→ | `omhttp`→ | `omhttp`→ | `omfwd`+LEEF | `omfwd`+CEF | | **syslog-ng** | `http()`→ | `elasticsearch-http()` | `http()`→ | `http()`→ | `gelf()` | `http()`→ | `http()`→ | `http()`→ | `syslog(LEEF)` | `syslog(CEF)` | | **Fluent Bit** | `splunk` | `es` / `elasticsearch` | `datadog` | `loki` | `gelf` | `azure_logs_ingestion` | `http`→ | `http`→ | `syslog`+LEEF | `syslog`+CEF | | **NXLog** | `om_http`→ | `om_elasticsearch` | `om_http`→ | `om_http`→ | `om_udp`+GELF | `om_http`→ | `om_http`→ | `om_http`→ | `om_udp`+LEEF | `om_udp`+CEF | | **Logstash** | `splunk` | `elasticsearch` | `datadog_logs` | `loki` | `gelf` | `microsoft-sentinel-logstash` | `sumologic` | `google_cloud_chronicle` | `syslog`+LEEF | `syslog`+CEF | | **Vector** | `splunk_hec_logs` | `elasticsearch` | `datadog_logs` | `loki` | `socket`+gelf | `azure_monitor_logs` | `sumo_logic` | `gcp_chronicle_logging` | `socket`+LEEF | `socket`+CEF | | **OTel** | `splunk_hec` | `elasticsearch` | `datadog` | `loki` | `file`→GELF | `azuremonitor` | `sumologic` | `googlecloud` | `file`→LEEF | `file`→CEF | | **Filebeat** | `output`→ | `elasticsearch` ★ | `output`→ | `output`→ | `output`→ | `azure_logs_ingestion` | `output`→ | `output`→ | `output`→ | `output`→ | | **Promtail** | — | — | — | `clients` ★ | — | — | — | — | — | — | | **Fluentd** | `splunk_hec` | `elasticsearch` | `datadog` | `loki` | `gelf` | `azure_logs_ingestion` | `sumologic` | `google_cloud_chronicle` | `syslog`+LEEF | `syslog`+CEF | ★ = 规范配对(Promtail 是 Loki 代理;Filebeat 是 Elastic 的 beats 转发器)。 `→` = 通过通用 HTTP/syslog 转发器,无方言原生插件。 `+GELF`/`+LEEF`/`+CEF` = 线路负载由 logflow-sim 的专用渲染器渲染;方言只负责传输。 `—` = 该方言没有为此目标提供合理的输出(Promtail 是单一用途设计)。 ``` # 独立重标签(保留流水线语法) logflow-sim retag ./rsyslog \ --source-siem=splunk --target-siem=elastic-ecs \ --out-dir=./ecs/ # 流水线 + SIEM 一次性完成 logflow-sim convert ./rsyslog \ --target=vector --source-siem=splunk --target-siem=datadog \ --out-dir=./vector-dd/ ``` ## 跨方言迁移 使用您现有的 rsyslog 配置,生成一个可工作的 OpenTelemetry Collector 配置(或任何其他支持的目标)。`/migrate` 处的向导会引导您完成此过程;相同的流程也可以无头执行: ``` curl -s -X POST localhost:3000/api/convert \ -H 'content-type: application/json' \ -d '{"target":"otel"}' | jq -r .output > otel-collector.yaml ``` 跨方言发出是尽力而为的 — 表达式语言构造(rsyslog 的 `lookup()`、Vector VRL、OTel OTTL)无法 1:1 转换。发出器会将每个转换注意事项都作为诊断信息呈现,迁移 UI 会突出显示它们。要验证端到端的路由一致性: 1. 将生成的配置保存到一个文件夹中,该文件夹应镜像您的配置目录结构。 2. 在差异模式下将其用作叠加层(`/diff` 或 `logflow-sim diff`)。 3. 通过两者重放一个有代表性的语料库 — 任何非零的输出差异都是您需要手动协调的路由变更。 ## CLI `logflow-sim` CLI 是 Action 背后的引擎,同样适用于本地 pre-commit hook 或任何 CI 运行器。 ``` logflow-sim parse # parse + validator (silent drops, dead code, undef refs) logflow-sim test # parse + run conf/tests/*.json logflow-sim simulate --input=msg.json # one message, JSON trace logflow-sim replay --lines=corpus.log # batch, aggregate verdict logflow-sim replay --pcap=capture.pcap # accepts pcap classic and pcapng logflow-sim convert --target=otel --out-dir=./out # whole-tree migration + lookup sidecars [--source-siem=splunk] # also retag destination vocabulary [--target-siem=elastic-ecs] logflow-sim retag --target-siem=elastic-ecs # destination retag only (keep pipeline dialect) --out-dir=./out [--source-siem=…] logflow-sim diff --overlay-dir=pr-conf/ \ --lines=corpus.log \ --max-route-change-pct=5 # exit 1 if PCT exceeded ``` 输出格式:`--format=human`(默认),`--format=github`(用于 Action 的注释),`--format=json`(机器可读,可管道传输到 jq)。 ## 静态验证器 `logflow-sim parse`(以及 `/api/config/parse`)对解析后的 IR 运行静态分析器。它可以捕获那些在语法检查中不会显示的路由错误: - **静默丢弃路径**:规则集的最后一条语句是不带 `else` 的 `if`,或者以 `set/unset/reset` 结束 — 在 fall-through 路径上的消息不会产生任何输出,并被静默丢弃。 - **死代码**:定义了但从未从任何输入到达的规则集、查找表、模板。 - **未定义的引用**:`call rulename`、`lookup("table", ...)`、`template="x"` 引用了不存在的名称。 - **冲突的输出**:同一目标被多个无条件操作写入。 - **缺失的查找文件**:`lookup_table(...)` 引用了磁盘上不存在的 JSON 文件。 每个发现都包含源位置和人类可读的解释,例如: 可以通过 `--fail-on=warnings` 在 CI 门控中触发这些错误。 ## 实时配置预览("/config" + 方言选择器) 配置页面的方言选择器不仅仅是解析覆盖。当您将其切换到非源方言时,文件树和查看器会切换到即时转换的预览 — `rsyslog.conf` 变成了 `otel-collector.yaml`,所有引用的查找表都以 OTel 的 transform/OTTL 风格发出(或 Vector 的 enrichment_tables + CSV 附属文件等)。将选择器切换回 `auto` 以返回磁盘上的源文件。这与驱动 `/api/convert` 和 `logflow-sim convert` 的是同一个引擎。 ## 重放与差异 模拟器可以通过您的配置运行一批真实的消息: - **重放** — 接受 `/var/log/messages` 风格的逐行转储**或**线路捕获(libpcap classic + pcapng + LINUX_SLL,UDP + 重组的 TCP 用于 RFC 6587 八位字节计数和非透明帧)。返回聚合报告:按规则集、按输出目标、顶级程序/主机名,以及用于不匹配/静默丢弃/出错消息的深入分析样本。 - **差异** — 通过您的实时配置和一个叠加变体重放同一批消息,获取按输出和按规则集的差异,以及对于每个路由发生变化的消息的并排基线与叠加输出。支持多文件叠加。 尝试针对真实语料库运行: ``` # 从 Loghub 研究数据集中获取 25k 条真实 /var/log/messages 日志行 curl -sL https://zenodo.org/records/8196385/files/Linux.tar.gz | tar -xz # 通过捆绑的演示配置重放它们 ./scripts/replay-loghub.sh ``` ## 检测影响 通过您的实时配置将 Sigma 检测规则运行在重放语料库上 — 可选地与提议的更改进行差异比较 — 以查看在合并之前路由更改是否会降低 SOC 可见性: ``` curl -s -X POST localhost:3000/api/detection/impact \ -H 'content-type: application/json' \ -d '{ "rules": [...sigma rules...], "lines": "..." }' | jq .summary ``` 返回每个规则的命中次数,以及(在差异变体中)叠加配置下哪些规则获得或丢失了覆盖。完整文章: [这次路由更改会破坏您的 SIEM 吗?](https://netverdict.io/logflow/blog/2026-05-17-detection-impact-before-you-merge)。 ## 项目与本地模式 [`/projects`](http://localhost:3000/projects) 页面允许您完全在客户端加载配置 — 克隆实时服务器配置、上传文件夹、拖放单个文件,或拖放 `.zip`(页面任何位置均支持拖放)。加载后,UI 进入**本地模式**,所有解析/模拟/搜索/验证都在 Web Worker 中运行。项目文件不会离开浏览器。保存的项目在 `localStorage` 中持久化,可以随时重命名、导出回 ZIP 或删除。 ## MCP 服务器(从 LLM 使用 logflow-sim) 附带一个 [Model Context Protocol](https://modelcontextprotocol.io) 服务器 (`logflow-sim-mcp`),该服务器将内核暴露为 LLM 可以调用的工具:`logflow_parse`、`logflow_simulate`、`logflow_replay`、`logflow_diff`、`logflow_convert`、`logflow_retag`、`logflow_detect`、`logflow_validate`。 Stdio JSON-RPC 2.0 传输 — 注册到 Claude Desktop 或任何支持 MCP 的客户端。详情见 [`content/docs/mcp.md`](content/docs/mcp.md)。 ## 国际化 UI 提供 13 种语言:英语、德语、法语、西班牙语、葡萄牙语、意大利语、日语、中文、韩语、俄语、印地语、土耳其语、越南语。选择器位于顶部栏。工具/方言名称保持英文,以便 UI 词汇与您正在分析的配置相匹配。目录位于 [`src/ui/i18n/locales/`](src/ui/i18n/locales/) — 欢迎提交单文件 PR。 ## 快速开始 ``` docker compose up --build ``` 打开 。将您自己的配置挂载到 `./conf/`,或者通过将 compose 卷指向 `./conf-demo/` 来运行捆绑的演示。 ### 不使用 Docker ``` npm install npm run dev ``` API 运行在 `:3000`,Vite UI 开发服务器运行在 `:5173` 并带有 HMR。在生产环境(`npm run build && npm start`)中,服务器从 `dist/ui` 提供构建好的 UI。 ## 文件夹布局 ``` src/ ├── core/ pure TS — no Node deps │ ├── vfs.ts virtual filesystem interface │ ├── source-map.ts file/line/col tracking │ ├── diagnostics.ts severity-tagged error reporting │ ├── ir/ normalized intermediate representation (vendor-neutral) │ ├── simulate/ evaluator, expressions, templates │ ├── lookups/ parse-table + lookup query │ └── dialects/ │ ├── types.ts the Dialect plugin contract │ └── rsyslog/ RainerScript parser + AST + IR mapping ├── vfs/node.ts NodeVFS — fs + fast-glob adapter ├── config/ Node-side loaders (use VFS) ├── lookups/loader.ts Node-side lookup loader (uses VFS + core) ├── api/ Express routes ├── content/ blog + docs markdown loader ├── server.ts Express bootstrap └── ui/ Preact SPA conf-demo/ bundled demo configuration (tracked in git) conf/ your own configs (gitignored — mount your dir here) content/posts/, content/docs/ markdown for blog + docs pages test/ vitest suites ``` ## API 示例 ``` # 存活检测 curl -s localhost:3000/api/health # 解析摘要 + 诊断 curl -s localhost:3000/api/config/parse | jq . # 模拟一条防火墙消息命中 :6514/UDP curl -s -XPOST localhost:3000/api/simulate \ -H 'content-type: application/json' \ -d '{ "transport": "udp", "port": 6514, "fromhost": "fw01", "hostname": "fw01", "programname": "firewall", "msg": "TRAFFIC deny tcp 10.0.0.1 -> 8.8.8.8:53" }' | jq . # 跨加载的配置进行多文件 grep curl -s 'localhost:3000/api/config/search?q=10.254.0.20' curl -s -G --data-urlencode 'q=10\.252\.\d+\.\d+' --data 'regex=1' \ 'localhost:3000/api/config/search' # 运行 conf/tests 下的所有测试用例 curl -s -XPOST localhost:3000/api/tests/run -d '{}' \ -H 'content-type: application/json' | jq '.passed,.total' ``` ## 已知限制 这是一个**解释器**,而不是重新实现。完整列表请参见 [`content/docs/limitations.md`](content/docs/limitations.md)。 简而言之: - 无队列运行时,无实际文件/网络 I/O。 - 查找表:仅支持 JSON(普通对象、对象数组、rsyslog 原生格式)。 - 模板:支持完整的 `%property%` 替换及修饰符(小写、大写、子字符串、正则表达式提取、日期组件) — 但尚未支持晦涩的 rsyslog 属性替换器标志。 - 未知语句**永远不会被静默跳过** — 它们被保留为带有警告诊断的 `Unknown` IR 节点。 ## 测试 ``` npm test ``` 覆盖了词法分析器、解析器、include 解析、RFC 3164 / 5424 rawmsg 解码、查找表加载(所有三种格式),以及端到端的模拟器行为(输入选择、`$DefaultRuleset` 回退、if/elif/else、set/reset/unset、带 `nomatch` 的查找命中/未命中、`stop`、DynaFile 模板解析、omfwd target/port/protocol、数组 RHS `startswith_i`、`call` 跨规则集、正则表达式提取、`exec_template`、`tolower`/`toupper`、`&` 连接、数值比较、`continue`)。 ### 语料库回归套件 `test/corpus/` 包含 20 多个真实的 rsyslog 配置,这些配置是逐字从公共来源获取的(Debian / Fedora / Alpine / Gentoo 发行版默认配置以及来自大型开源项目的配置 — 请参见 [`SOURCES.md`](test/corpus/SOURCES.md))。 语料库测试解析每个配置,并断言其诊断计数和 IR 摘要与 `test/corpus/baseline.json` 中记录的基线匹配。任何偏差都是回归。 从上游刷新语料库: ``` ./scripts/fetch-corpus.sh git diff test/corpus/ # what changed upstream ``` 在有意更改解析器导致计数变化后,重新生成基线: ``` UPDATE_CORPUS_BASELINE=1 npm test -- corpus ``` ## 许可证 MIT。
标签:API集成, Filebeat, Fluent Bit, Fluentd, GitHub Actions, GNU通用公共许可证, Logstash, MITM代理, Node.js, NXLog, OISF, OpenTelemetry Collector, Promtail, PR验证, rsyslog, Sigma规则, syslog-ng, TypeScript, URL发现, Vector, 中间表示, 可观测性, 安全插件, 安全检测, 日志处理工具, 日志管理, 日志管道模拟, 步骤跟踪, 流量模拟, 目标导入, 管道配置验证, 自动化攻击, 自动笔记, 请求拦截, 路由差异, 配置解析, 错误检测