From eed2de05712ae69d0bf92dfa5300f16ef84e4ffc Mon Sep 17 00:00:00 2001 From: byrsapty Date: Wed, 22 Jul 2026 15:19:10 +0300 Subject: [PATCH] feat: add generic critical severity classification rule and update deployment documentation --- rules/rule18_generic_critical_severity.json | 4 +- vector-accel-ppp-setup.md | 59 +++++++++++++-------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/rules/rule18_generic_critical_severity.json b/rules/rule18_generic_critical_severity.json index 54c3a82..5b21e7c 100644 --- a/rules/rule18_generic_critical_severity.json +++ b/rules/rule18_generic_critical_severity.json @@ -1,5 +1,5 @@ { "title": "generic_critical_severity", - "description": "Universal fallback: any syslog message (any vendor) with RFC5424/3164 severity Emergency/Alert/Critical (0-2) that wasn't already classified by a more specific rule", - "source": "rule \"generic_critical_severity\"\nwhen\n !has_field(\"event_type\") && has_field(\"level\") && to_long($message.level) <= 2\nthen\n set_field(\"event_type\", \"generic_critical_syslog\");\n set_field(\"severity_tag\", \"critical\");\nend" + "description": "Universal fallback: any syslog message (any vendor) with RFC5424/3164 severity Emergency/Alert/Critical (0-2) that was not already classified by a more specific rule. Excludes level<0 (unparseable/unknown severity - e.g. raw text sent without a syslog PRI header, such as Vector socket sink output), which is NOT the same as an actually critical message.", + "source": "rule \"generic_critical_severity\"\nwhen\n !has_field(\"event_type\") && has_field(\"level\") && to_long($message.level) >= 0 && to_long($message.level) <= 2\nthen\n set_field(\"event_type\", \"generic_critical_syslog\");\n set_field(\"severity_tag\", \"critical\");\nend" } diff --git a/vector-accel-ppp-setup.md b/vector-accel-ppp-setup.md index 114c316..ecadc98 100644 --- a/vector-accel-ppp-setup.md +++ b/vector-accel-ppp-setup.md @@ -86,7 +86,7 @@ read_from: "beginning" # ========================================== - # 2. ПЕРЕТВОРЕННЯ (Transforms) — форматування та тегування + # 2. ПЕРЕТВОРЕННЯ (Transforms) — тегування джерела # ========================================== transforms: format_for_graylog: @@ -94,12 +94,11 @@ inputs: - "accel_ppp_log" source: | - .message = encode_key_value({ - "timestamp": to_string!(.timestamp), - "host": get_hostname!(), - "tag": "accel-remote-only", - "message": .message - }) + # Додаємо лише ім'я хоста спереду, як префікс — оригінальний + # рядок логу accel-ppp лишається без змін. Саме під його формат + # написані pipeline rules у Graylog (interface, RADIUS-атрибути + # тощо), тож його не можна перекручувати. + .message = "[" + get_hostname!() + "] " + to_string!(.message) # ========================================== # 3. ПРИЗНАЧЕННЯ (Sinks) — куди відправляти @@ -115,6 +114,19 @@ codec: "text" ``` + > **Чому не `encode_key_value()`?** Перша версія цього гайду огортала + > повідомлення в `encode_key_value({...})` (`timestamp=... host=... + > tag=... message="..."`). Це виглядало акуратно, але на практиці + > ламало обробку в Graylog двома способами: (1) `encode_key_value()` + > екранує лапки всередині значення `message` (`"NAS1"` ставало + > `\"NAS1\"`), через що regex-правила Graylog для RADIUS/accel-ppp + > переставали витягувати поля (`accelppp_interface`, + > `acct_status_type` тощо лишались порожніми); (2) Graylog-вхід тут — + > звичайний Syslog UDP, а не GELF/структурований, тож жодної реальної + > користі з "красивого" key-value формату однаково не було — усе одно + > зберігається як один текстовий рядок. Простий префікс з hostname + > дає ідентифікацію джерела без цих побічних ефектів. + 3. Збережіть файл (`Ctrl+O`, `Enter`) і вийдіть (`Ctrl+X`). 4. Перевірте синтаксис перед запуском: @@ -208,14 +220,14 @@ transforms: inputs: - "<унікальна_назва_джерела>" source: | - .message = encode_key_value({ - "timestamp": to_string!(.timestamp), - "host": get_hostname!(), - "tag": "<унікальний_тег_для_пошуку_в_graylog>", - "message": .message - }) + .message = "[" + get_hostname!() + "] " + to_string!(.message) ``` +> Не додавайте сюди `encode_key_value()` чи інше перепакування — +> дивіться пояснення "Чому не `encode_key_value()`?" у кроці 2. Якщо +> потрібно розрізняти джерела в Graylog, найпростіше — унікальний +> префікс замість hostname, наприклад `"[radius] " + to_string!(.message)`. + Потім допишіть `<унікальна_назва_transform>` у список `inputs` sink'у `graylog_out` (він уже є в конфізі з кроку 2): @@ -256,12 +268,7 @@ transforms: inputs: - "freeradius_log" source: | - .message = encode_key_value({ - "timestamp": to_string!(.timestamp), - "host": get_hostname!(), - "tag": "radius-server", - "message": .message - }) + .message = "[" + get_hostname!() + "] " + to_string!(.message) sinks: graylog_out: @@ -315,6 +322,8 @@ Graylog двічі з різними форматами. | Повідомлення доходять, але без полів `vendor`/`event_type` у Graylog | Pipeline rules у Graylog ще не мають правила під формат саме цього тегу/сервісу | Дайте кілька реальних рядків логу — можна додати нове pipeline rule за тим самим принципом, що й для accel-ppp/RADIUS | | Дублікати повідомлень у Graylog | Старе правило `rsyslog` досі активне паралельно з Vector | Виконайте крок 6 | | Vector запускається, але не бачить оновлень файлу | Файл ротується (logrotate) інакше, ніж очікує Vector | Перевірте `include`/`ignore_older_secs`; за потреби додайте `fingerprint` налаштування у `source`, щоб Vector коректно стежив за файлом після ротації | +| `vector validate` видає `error[E103]: unhandled fallible assignment` у `transform` | VRL вимагає явно гарантувати тип операнда перед конкатенацією/операцією (наприклад, `.message` без `to_string!()`) | Обгорніть проблемне поле в `to_string!(...)` (або іншу `!`-функцію відповідного типу) — саме так це вирішено в базовому конфізі кроку 2 | +| Критичні алерти в Discord на рутинні `info`-повідомлення від Vector-джерела | Syslog UDP input не бачить валідного `` заголовка в сирому тексті Vector, тож Graylog проставляє severity `-1` ("невідомо") — а не 0-2 (справді критично) | Це вже виправлено на стороні Graylog (правило `generic_critical_severity` тепер явно виключає `level < 0`); якщо побачите знову — перевірте, чи не відкотилось це правило | ## Довідка: структура конфігурації @@ -322,10 +331,14 @@ Graylog двічі з різними форматами. вказаний файл, `read_from: "beginning"` = при першому запуску прочитати файл з початку (а не тільки нові рядки). - **`transforms`** (тип `remap`) — обробка даних мовою VRL (Vector Remap - Language). У цьому гайді використовується `encode_key_value()`, щоб - зібрати повідомлення у вигляді `timestamp=... host=... tag=... message=...` - — простий, передбачуваний текстовий формат, який легко парсити правилами - в Graylog. + Language). У цьому гайді використовується лише конкатенація рядків + (`"[" + get_hostname!() + "] " + to_string!(.message)`), щоб додати + ідентифікацію хоста, не чіпаючи оригінальний формат рядка логу — саме + під цей оригінальний формат написані pipeline rules у Graylog. + `to_string!()` потрібен тому, що VRL вимагає явно гарантувати тип + рядка перед конкатенацією (`!` означає "перервати обробку цього + повідомлення, якщо не вдалось" — тут це станеться хіба що для зовсім + нетипових вхідних даних). - **`sinks`** (тип `socket`, `mode: "udp"`) — куди й як відправляти результат. Один sink може приймати від багатьох transforms одночасно (список `inputs`) — саме так додаються нові джерела логів без створення