graylog-deploy/vector-accel-ppp-setup.md
byrsapty 31258eee01 Add error/warn-only Vector filter + 5 new pipeline rules + repetition alert
Analyzed a real 1GB accel-ppp log (2026-07-23): only 2,819 of its lines
were error:/warn:, and one pattern - "can't determine router address" -
repeated 2,746 times over ~4 hours for two specific subscriber interfaces
before self-resolving, completely unalerted since no alert covered it.

- New pipeline rules for 3 previously-unclassified real message types
  (radius:dm_coa session not found, mac change detected, dhcpv4 short
  packet) plus a text-based fallback pair (accelppp_unclassified_error/
  warn) for anything not yet specifically classified - needed because
  Vector-shipped accel-ppp lines have no real syslog PRI header, so the
  numeric-severity generic_critical_severity rule never fires for this
  source.
- New alert7: group by gl2_remote_ip + event_type, fires on >5 occurrences
  in 5 minutes - low enough to have caught the real incident within its
  first cycle, high enough to tolerate a single transient warning.
- vector-accel-ppp-setup.md gained a "keep only error/warn" filter option
  (Step 2b), explicitly documented as a deliberate tradeoff: it also drops
  RADIUS accounting, so the Servers & Sessions dashboard and session
  correlation go empty for any server that applies it. Both the
  with-filter and without-filter full configs are included so the choice
  is per-server, not global.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 16:20:13 +03:00

510 lines
27 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Vector: перетрансляція логів у Graylog (Debian)
Інструкція з встановлення та налаштування агента [Vector](https://vector.dev)
для збору логів з окремих файлів (сервіси на кшталт `accel-ppp`, які не
пишуть у syslog, а тільки у власний лог-файл) і пересилання їх на
централізований Graylog по UDP. Використовується там, де сервіс не вміє
писати напряму в syslog, або де потрібен більш гнучкий контроль над
форматом і тегуванням повідомлень, ніж дає стандартний `rsyslog`.
## Зміст
- [Огляд архітектури](#огляд-архітектури)
- [Передумови](#передумови)
- [Крок 1. Встановлення Vector](#крок-1-встановлення-vector)
- [Крок 2. Базова конфігурація (приклад: accel-ppp)](#крок-2-базова-конфігурація-приклад-accel-ppp)
- [Крок 2b. (Опційно) Фільтрація DHCP-шуму](#крок-2b-опційно-фільтрація-dhcp-шуму)
- [Крок 3. Права доступу (запуск від root)](#крок-3-права-доступу-запуск-від-root)
- [Крок 4. Запуск та перевірка роботи](#крок-4-запуск-та-перевірка-роботи)
- [Крок 5. Додавання інших джерел логів](#крок-5-додавання-інших-джерел-логів)
- [Крок 6. Прибирання старих правил rsyslog](#крок-6-прибирання-старих-правил-rsyslog)
- [Діагностика проблем](#діагностика-проблем)
- [Довідка: структура конфігурації](#довідка-структура-конфігурації)
## Огляд архітектури
```
/var/log/accel-ppp/accel-ppp.log ──┐
/var/log/freeradius/radius.log ────┼──▶ Vector ──▶ UDP:5140 ──▶ Graylog
/var/log/<інший файл>.log ──────────┘ (read + tag + forward) (Servers Syslog input)
```
Кожен лог-файл — це окреме **джерело** (`source`) у Vector. Кожне джерело
проходить через своє **перетворення** (`transform`), яке додає тег і
метадані. Усі перетворення збираються в одне **призначення** (`sink`),
яке одним UDP-потоком шле все на Graylog. Додавання нового файлу логів
= один новий `source` + один новий `transform` + один рядок у списку
`inputs` існуючого sink — сам sink і адреса Graylog не міняються.
## Передумови
- [ ] Операційна система: Debian Linux (11/12)
- [ ] Сервіс, що пише лог у файл (наприклад `accel-ppp`, `freeradius`)
- [ ] Доступ до сервера під root або користувачем із sudo
- [ ] Адреса Graylog-сервера: `10.254.254.202:5140` (UDP, вхід "Servers
Syslog (RADIUS-accel-ppp)")
- [ ] Порт 5140/udp відкритий між цим сервером і Graylog (перевірте
firewall/маршрутизацію заздалегідь — Vector мовчки "губить" пакети,
якщо порт недоступний, без явної помилки)
## Крок 1. Встановлення Vector
1. Додайте офіційний репозиторій Vector і встановіть його:
```bash
bash -c "$(curl -sSfL https://setup.vector.dev)"
sudo apt update
sudo apt install vector -y
```
2. Перевірте, що встановилось коректно:
```bash
vector --version
```
## Крок 2. Базова конфігурація (приклад: accel-ppp)
1. Створіть конфігураційний файл:
```bash
sudo nano /etc/vector/vector.yaml
```
2. Вставте базову конфігурацію. Це робочий приклад для `accel-ppp` —
використовуйте його як шаблон і довідку, коли додаватимете інші
джерела в кроці 5:
```yaml
# ==========================================
# 1. ДЖЕРЕЛА (Sources) — які файли читати
# ==========================================
sources:
accel_ppp_log:
type: "file"
include:
- "/var/log/accel-ppp/accel-ppp.log"
read_from: "beginning"
# ==========================================
# 2. ПЕРЕТВОРЕННЯ (Transforms) — тегування джерела
# ==========================================
transforms:
format_for_graylog:
type: "remap"
inputs:
- "accel_ppp_log"
source: |
# Додаємо лише ім'я хоста спереду, як префікс — оригінальний
# рядок логу accel-ppp лишається без змін. Саме під його формат
# написані pipeline rules у Graylog (interface, RADIUS-атрибути
# тощо), тож його не можна перекручувати.
.message = "[" + get_hostname!() + "] " + to_string!(.message)
# ==========================================
# 3. ПРИЗНАЧЕННЯ (Sinks) — куди відправляти
# ==========================================
sinks:
graylog_out:
type: "socket"
inputs:
- "format_for_graylog"
address: "udp://10.254.254.202:5140"
mode: "udp"
encoding:
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. Перевірте синтаксис перед запуском:
```bash
vector validate /etc/vector/vector.yaml
```
Якщо є помилка — `vector validate` вкаже точний рядок і причину; не
запускайте службу, поки ця команда не відповість без помилок.
## Крок 2b. (Опційно) Фільтрація — лишити тільки error/warn
**Навіщо:** `accel-ppp` на кожну оренду DHCP, кожен RADIUS
accounting-цикл і кожен ipoe-хендшейк пише повний `info`/`debug` обмін.
Порахували наживо на реальних цифрах (2 активні NAS-сервери, ~634
байти/повідомлення в Graylog): при масштабуванні до 10+ таких серверів
це ~38.5 GiB/добу лише "сирих" даних — диск, розрахований на 14-21 день
retention, заповниться за лічені дні. У реальному 1GB лозі одного
сервера за добу лише **2,819 рядків** виявились `error:`/`warn:` — решта
(мільйони рядків) це info/debug-шум.
**Свідомий компроміс:** цей фільтр лишає **тільки** `error:` і `warn:`,
відкидаючи все інше — включно з RADIUS Accounting (сесії, трафік
Input/Output-Octets). Якщо для вас важлива аналітика сесій/трафіку
(дашборд "Servers & Sessions", кореляція за `accelppp_interface`/
`radius_session_id` у Graylog) — **не застосовуйте цей фільтр**, або
тримайте один сервер без нього для порівняння. Це рішення per-server: у
`vector.yaml` кожного сервера обирається окремо.
Додайте `filter`-transform між `format_for_graylog` і `sinks`:
```yaml
transforms:
format_for_graylog:
# ... як у кроці 2, без змін ...
# Лишає тільки error:/warn: - усе info/debug (RADIUS accounting, DHCP,
# ipoe housekeeping) відкидається. Умова true = повідомлення проходить
# далі.
keep_error_warn_only:
type: "filter"
inputs:
- "format_for_graylog"
condition: 'contains(string!(.message), "error:") || contains(string!(.message), "warn:")'
sinks:
graylog_out:
type: "socket"
inputs:
- "keep_error_warn_only" # було "format_for_graylog" - тепер через фільтр
address: "udp://10.254.254.202:5140"
mode: "udp"
encoding:
codec: "text"
```
Перевірка після зміни:
```bash
vector validate /etc/vector/vector.yaml
sudo systemctl restart vector
sudo journalctl -u vector -f # переконайтесь, що йдуть лише error:/warn: рядки
```
**Знайдені наживо типи `error:`/`warn:`** (з реального 1GB логу,
2026-07-23), усі вже покриті pipeline rules у Graylog:
- `error: <interface>: can't determine router address` — стабільно
повторювався 2,746 разів поспіль ~4 години для двох конкретних
інтерфейсів, перш ніж саморозв'язатись; саме цей випадок і привів до
появи алерту на повторюваність нижче
- `warn: <interface>: radius: server(N) not responding` — чергування між
серверами кожні ~30с
- `warn: radius:dm_coa: session not found` — CoA/DM-запит на вже
завершену сесію
- `warn: <interface>: mac change detected` — зміна MAC-адреси абонента
під час сесії
- `warn: dhcpv4: short packet received` — пошкоджений/обрізаний
DHCP-пакет
Для будь-якого нового типу `error:`/`warn:`, якого ще нема серед
специфічних правил, спрацює fallback-правило
(`accelppp_unclassified_error`/`accelppp_unclassified_warn`) — воно
тегує `event_type` і `severity_tag`, тож нічого не губиться навіть без
власного правила.
### Алерт на повторюваність
Одне повідомлення `error:`/`warn:` часто нормальне (одна невдала спроба
RADIUS, разова зміна MAC) — тривожний сигнал саме **повторюваність**.
Алерт `alerts/alert7_accelppp_repeated_error_warn.json` групує за
`gl2_remote_ip` + `event_type` і спрацьовує, якщо той самий тип
повідомлення з того самого сервера трапляється **>5 разів за 5 хвилин**
— поріг підібраний так, щоб гарантовано зловити знайдений
"router address"-інцидент у перший же цикл, але не спамити на поодинокі
попередження.
### Повний конфіг — без фільтра
Базовий варіант (усе: RADIUS accounting, DHCP, ipoe housekeeping,
error/warn — усе разом):
```yaml
sources:
accel_ppp_log:
type: "file"
include:
- "/var/log/accel-ppp/accel-ppp.log"
read_from: "beginning"
transforms:
format_for_graylog:
type: "remap"
inputs:
- "accel_ppp_log"
source: |
.message = "[" + get_hostname!() + "] " + to_string!(.message)
sinks:
graylog_out:
type: "socket"
inputs:
- "format_for_graylog"
address: "udp://10.254.254.202:5140"
mode: "udp"
encoding:
codec: "text"
```
### Повний конфіг — з фільтром "тільки error/warn"
Той самий конфіг плюс один `transform` і зміна `inputs` у `sinks`:
```yaml
sources:
accel_ppp_log:
type: "file"
include:
- "/var/log/accel-ppp/accel-ppp.log"
read_from: "beginning"
transforms:
format_for_graylog:
type: "remap"
inputs:
- "accel_ppp_log"
source: |
.message = "[" + get_hostname!() + "] " + to_string!(.message)
keep_error_warn_only:
type: "filter"
inputs:
- "format_for_graylog"
condition: 'contains(string!(.message), "error:") || contains(string!(.message), "warn:")'
sinks:
graylog_out:
type: "socket"
inputs:
- "keep_error_warn_only"
address: "udp://10.254.254.202:5140"
mode: "udp"
encoding:
codec: "text"
```
**Коли який обирати:** без фільтра — коли потрібна аналітика сесій/трафіку
(дашборд "Servers & Sessions", кореляція сесій); з фільтром — коли
головне економія диска/мережі і головний інтерес саме в проблемах
(error/warn + алерт на повторюваність). Рішення приймається окремо для
кожного сервера — нічого не заважає тримати частину серверів з фільтром,
частину без.
## Крок 3. Права доступу (запуск від root)
Лог-файли на кшталт `accel-ppp.log` часто мають права `600` (читає лише
власник, зазвичай root), тож стандартний користувач `vector` не зможе їх
прочитати. Найпростіше рішення — запускати службу від `root`.
> Альтернатива, якщо не хочете давати `vector` права root: додайте
> користувача `vector` у групу-власника файлу (`usermod -aG <група>
> vector`) і виставте на файл права `640`. Це вужче за обсягом, але
> вимагає стежити за правами при кожному новому джерелі логів. Для
> простоти цей гайд іде шляхом `root`.
1. Відкрийте редактор перевизначення systemd-юніта:
```bash
sudo systemctl edit vector
```
2. У порожні рядки вгорі файлу вставте:
```ini
[Service]
User=root
Group=root
```
3. Збережіть і закрийте (`Ctrl+O`, `Enter`, `Ctrl+X`).
## Крок 4. Запуск та перевірка роботи
1. Перечитайте конфігурацію systemd і запустіть Vector з автозавантаженням:
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now vector
```
2. Перевірте статус і логи в реальному часі:
```bash
sudo systemctl status vector
sudo journalctl -u vector -f
```
Успішний результат — рядок виду:
```
INFO source{...}: Found new file to watch. file=/var/log/accel-ppp/accel-ppp.log
```
без жодних `Permission denied`.
3. Згенеруйте тестовий рядок у файлі логу і перевірте, що він долетів до
Graylog (System → Inputs → відповідний input → "Received messages",
або Search з широким часовим діапазоном):
```bash
echo "vector test line $(date)" | sudo tee -a /var/log/accel-ppp/accel-ppp.log
```
## Крок 5. Додавання інших джерел логів
Щоб додати ще один лог-файл (наприклад, FreeRADIUS, або будь-який інший
сервіс, що пише у файл), потрібні три зміни в `/etc/vector/vector.yaml`:
новий `source`, новий `transform`, і додати назву цього transform у
список `inputs` існуючого `sink`. Сам `sink` (адреса Graylog) лишається
один — усі джерела йдуть через нього.
### Шаблон
```yaml
sources:
<унікальнаазва_джерела>:
type: "file"
include:
- "<повний шлях до файлу логів>"
read_from: "beginning"
transforms:
<унікальнаазва_transform>:
type: "remap"
inputs:
- "<унікальнаазва_джерела>"
source: |
.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):
```yaml
sinks:
graylog_out:
type: "socket"
inputs:
- "format_for_graylog" # вже було (accel-ppp)
- "<унікальнаазва_transform>" # новий рядок
address: "udp://10.254.254.202:5140"
mode: "udp"
encoding:
codec: "text"
```
**Правила іменування**, щоб уникнути конфліктів при кількох джерелах:
- назва `source` і `transform` мають бути унікальними в межах усього
конфігураційного файлу (не тільки в межах одного сервісу);
- `tag` — це те, за чим ви шукатимете в Graylog (`tag:radius-server` тощо),
тож робіть його осмисленим і не повторюваним для різних сервісів.
### Готовий приклад: додавання логу FreeRADIUS
```yaml
sources:
# ... accel_ppp_log вже є ...
freeradius_log:
type: "file"
include:
- "/var/log/freeradius/radius.log"
read_from: "beginning"
transforms:
# ... format_for_graylog вже є ...
format_freeradius_for_graylog:
type: "remap"
inputs:
- "freeradius_log"
source: |
.message = "[" + get_hostname!() + "] " + to_string!(.message)
sinks:
graylog_out:
type: "socket"
inputs:
- "format_for_graylog"
- "format_freeradius_for_graylog"
address: "udp://10.254.254.202:5140"
mode: "udp"
encoding:
codec: "text"
```
Після будь-якої зміни конфігурації:
```bash
vector validate /etc/vector/vector.yaml # спершу перевірити синтаксис
sudo systemctl restart vector # застосувати
sudo journalctl -u vector -f # переконатись, що нове джерело підхопилось
```
> Якщо новий лог-файл має інші права доступу/власника — переконайтесь,
> що користувач, від якого запущено Vector (за кроком 3 — `root`), може
> його прочитати, інакше повторите проблему з кроку 3 для нового файлу.
## Крок 6. Прибирання старих правил rsyslog
Якщо раніше для відправки логів цього файлу використовувався `rsyslog`
(наприклад, через модуль `imfile`), після переходу на Vector варто
прибрати дублюючі правила, щоб те саме повідомлення не потрапляло в
Graylog двічі з різними форматами.
1. Відкрийте конфігурацію rsyslog (`/etc/rsyslog.conf` або файли у
`/etc/rsyslog.d/`).
2. Знайдіть і видаліть/закоментуйте правила з модулем `imfile`, тегом,
що відповідає файлу (наприклад `accel-remote-only`), і командою
видалення повідомлення (`~`, щоб воно не йшло далі за замовчуванням).
3. Перезапустіть rsyslog:
```bash
sudo systemctl restart rsyslog
```
## Діагностика проблем
| Симптом | Ймовірна причина | Що перевірити |
|---|---|---|
| `Permission denied` у `journalctl -u vector` | Vector не має прав читати лог-файл | Крок 3 виконано? `ls -la <файл>` — хто власник і які права |
| Служба запущена, файл читається, але в Graylog нічого немає | Порт 5140 недоступний з цього сервера (firewall/маршрутизація) | `nc -u -zv 10.254.254.202 5140` з цього сервера; `tcpdump -i eth0 udp port 5140` на стороні Graylog |
| `vector validate` видає помилку | Помилка синтаксису YAML або VRL у `transform` | Читайте повідомлення про помилку — воно вказує точний рядок; перевірте відступи (YAML чутливий до пробілів) |
| Повідомлення доходять, але без полів `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 не бачить валідного `<PRI>` заголовка в сирому тексті Vector, тож Graylog проставляє severity `-1` ("невідомо") — а не 0-2 (справді критично) | Це вже виправлено на стороні Graylog (правило `generic_critical_severity` тепер явно виключає `level < 0`); якщо побачите знову — перевірте, чи не відкотилось це правило |
| RADIUS accounting/DHCP/ipoe-рядки більше не з'являються в Graylog | Це очікувано, якщо додано `keep_error_warn_only` з кроку 2b — фільтр лишає тільки error:/warn: | Перевірте `vector.yaml` — якщо потрібна аналітика сесій/трафіку, приберіть цей transform з ланцюжка `inputs` sink'у (див. "Повний конфіг без фільтра" у кроці 2b) |
| Алерт "abnormal message volume" щойно після першого запуску Vector на новому сервері | `read_from: "beginning"` (крок 2) означає, що при першому старті Vector вичитує весь наявний лог-файл одразу, а не тільки нові рядки — одноразовий сплеск, не триваюча проблема | Перевірте обсяг від цього джерела через кілька хвилин (`gl2_remote_ip:<ip>` у Search) — має впасти до звичайного рівня |
## Довідка: структура конфігурації
- **`sources`** — звідки Vector бере дані. Тип `file` = читає (і "хвостить")
вказаний файл, `read_from: "beginning"` = при першому запуску прочитати
файл з початку (а не тільки нові рядки).
- **`transforms`** (тип `remap`) — обробка даних мовою VRL (Vector Remap
Language). У цьому гайді використовується лише конкатенація рядків
(`"[" + get_hostname!() + "] " + to_string!(.message)`), щоб додати
ідентифікацію хоста, не чіпаючи оригінальний формат рядка логу — саме
під цей оригінальний формат написані pipeline rules у Graylog.
`to_string!()` потрібен тому, що VRL вимагає явно гарантувати тип
рядка перед конкатенацією (`!` означає "перервати обробку цього
повідомлення, якщо не вдалось" — тут це станеться хіба що для зовсім
нетипових вхідних даних).
- **`sinks`** (тип `socket`, `mode: "udp"`) — куди й як відправляти
результат. Один sink може приймати від багатьох transforms одночасно
(список `inputs`) — саме так додаються нові джерела логів без створення
нового sink чи нової адреси.