api_sync/ARCHITECTURE.md

149 lines
11 KiB
Markdown
Raw 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.

# Архитектура API Sync
## Обзор
API Sync — однопроходная утилита (не демон), запускаемая по cron. При каждом запуске выполняет три последовательных этапа: синхронизацию данных из API в PostgreSQL, очистку устаревших записей и обновление whitelist-файла в Git-репозитории.
---
## Поток выполнения
```
main()
├─ 1. Подключение к PostgreSQL
├─ 2. Загрузка списка клиентов (client_info)
├─ 3. Сбор SID (apps_settings WHERE mode = 'auto')
├─ 4. Параллельная обработка SID (worker pool)
│ └─ processSID() для каждого SID
│ ├─ GET /l7/resource/{sid}/global → whois
│ ├─ GET /l7/origin/global?l7ResourceId={sid} → origins
│ ├─ GET /l7/alias/global?l7ResourceId={sid} → aliases
│ ├─ DNS резолв домена → проверка AntiDDOS
│ └─ upsertAPIInfo() → сравнение + запись в API_info + алерты
├─ 5. Очистка устаревших SID из API_info (cleanupRemovedSIDs)
└─ 6. Обновление WAF whitelist (updateWAFWhitelist)
├─ git pull
├─ Загрузка IP из API_info (auto)
├─ Загрузка IP из manual_info (ручные)
├─ Фильтрация WAF-сетей (таблица ips)
├─ Сравнение с текущим whitelist-файлом
├─ Запись файла + git commit + git push
└─ Отправка алерта об изменениях
```
---
## Модули
### main.go — точка входа и worker pool
Инициализирует подключение к БД, собирает все SID для обработки и запускает пул горутин. Количество воркеров задаётся через `MAX_CONCURRENT_WORKERS` (по умолчанию 5). SID передаются воркерам через буферизированный канал.
После завершения всех воркеров последовательно запускаются очистка устаревших записей и обновление whitelist.
### config.go — конфигурация
Загружает переменные окружения из `/etc/API_sync/API_sync.env` через `godotenv`. Если файл недоступен — использует системные переменные окружения. Все переменные инициализируются в `init()` до старта `main()`.
### api.go — HTTP-клиент и структуры API
Содержит единственный HTTP-клиент с таймаутом 20 секунд и функцию `apiGet()`, которая выполняет GET-запрос к API API с Bearer-авторизацией и десериализует JSON-ответ в переданную структуру.
Определены структуры ответов API: `originItem`, `aliasItem`, `whoisReAPIonse`, `apiList`.
### database.go — работа с PostgreSQL
**`loadClients()`** — загружает список клиентов из `client_info`.
**`loadL7IDs()`** — загружает SID из `apps_settings` для конкретного клиента с `mode = 'auto'`.
**`processSID()`** — оркестрирует обработку одного SID: делает три запроса к API, резолвит домен для проверки AntiDDOS, вызывает `upsertAPIInfo()`.
**`upsertAPIInfo()`** — сравнивает новые данные со старыми из БД и при наличии изменений формирует алерты:
- изменение домена → алерт + флаг необходимости обновления PT AF
- изменение origins (IP, mode, weight) — через `compareOrigins()`
- изменение aliases — через `compareAliases()`
- изменение WAF-настроек (vendor, instance, enabled) — отдельный алерт
Сохранение выполняется через `INSERT ... ON CONFLICT DO UPDATE` (upsert по `sid`).
**`cleanupRemovedSIDs()`** — сравнивает все SID в `API_info` с актуальным списком активных SID. Записи, которых нет в активном списке (ресурс удалён из `apps_settings` или сменил `mode`), удаляются из `API_info`. По каждому удалённому ресурсу отправляется алерт с указанием WAF-вендора (берётся из `apps_settings` через LEFT JOIN).
**`wafVendorWarning()`** — формирует строку предупреждения в зависимости от вендора: `ptaf` → PT AF, `sw` → SW, `wmx` → WMX.
### compare.go — функции сравнения
**`compareOrigins()`** — сравнивает два списка origins по IP-адресу. Определяет добавленные, удалённые и изменённые (mode/weight) записи. Возвращает отформатированную строку для алерта с текущим состоянием origins.
**`compareAliases()`** — сравнивает два отсортированных списка доменов. Возвращает строку с изменениями и булев флаг наличия изменений.
### dns.go — DNS-резолвер
Функция `resolveDomain()` возвращает первый IPv4-адрес для заданного домена. Используется в `processSID()` для проверки AntiDDOS: если resolvedIP совпадает с protectedIP из API — AntiDDOS активен.
### notify.go — система уведомлений
**`sendAlert()`** — единая точка отправки алертов. Последовательно отправляет сообщение во все настроенные каналы. Ошибка одного канала не блокирует остальные.
**Telegram**`buildTelegramClient()` при каждой отправке выбирает транспорт в порядке приоритета:
1. HTTP-прокси (`TELEGRAM_HTTP_PROXY`) — если задан и доступен
2. SOCKS5-прокси (`TELEGRAM_SOCKS5_PROXY`) — если задан и доступен
3. Прямое подключение — fallback
Доступность проверяется реальным GET-запросом на `api.telegram.org`. Сообщения отправляются в формате HTML (`parse_mode: HTML`).
**Mattermost** — POST на `/api/v4/posts` с Bearer-токеном. HTML-теги Telegram конвертируются в Markdown через `htmlToMarkdown()`. Отправляется только если заполнены все три переменные: `MATTERMOST_URL`, `MATTERMOST_BOT_TOKEN`, `MATTERMOST_CHANNEL_ID`.
**Email** — через стандартный `net/smtp`. Поддерживает несколько адресов получателей через запятую в `EMAIL_TO`. Авторизация опциональна — если `EMAIL_SMTP_USER` пуст, отправка идёт без аутентификации (relay). HTML-теги Telegram удаляются через `stripHTMLTags()`. Отправляется только если заполнены `EMAIL_SMTP_HOST`, `EMAIL_FROM`, `EMAIL_TO`.
### git.go — Git-операции
**`syncGitRepo()`** — если репозиторий не существует локально — клонирует (`git clone`), иначе обновляет (`git pull`). Автоматически настраивает `user.email` и `user.name` для коммитов.
**`gitCommitAndPush()`** — выполняет `git add <whitelist_file>`, `git commit -m <message>`, `git push`. Если нечего коммитить (`nothing to commit`) — завершается без ошибки.
### whitelist.go — управление whitelist
**`updateWAFWhitelist()`** — основная функция обновления whitelist:
1. Синхронизирует Git-репозиторий
2. Загружает WAF-сети из таблицы `ips`
3. Загружает origin IP из `API_info` (`loadAllOrigins`) и `manual_info` (`loadManualOrigins`), объединяет и дедуплицирует
4. Фильтрует IP попадающие в WAF-сети (`filterNonWAFOrigins`)
5. Сравнивает с текущим содержимым файла (`compareWhitelists`)
6. При наличии изменений — перезаписывает файл, коммитит и пушит, отправляет алерт
**`loadManualOrigins()`** — загружает все записи из `manual_info` как есть, без дополнительных условий. Таблица заполняется администратором вручную и программой не изменяется.
**`filterNonWAFOrigins()`** — исключает из списка IP-адреса, которые принадлежат WAF-сетям из таблицы `ips`. Такие адреса являются узлами самого WAF и не должны попадать в whitelist.
---
## Алерты
Все алерты отправляются через единую функцию `sendAlert()`. Типы алертов:
| Событие | Содержание |
|---|---|
| Изменение origins | Добавленные/удалённые/изменённые backend IP + текущее состояние |
| Изменение aliases | Добавленные/удалённые домены |
| Изменение домена | Старое и новое значение + предупреждение об обновлении WAF |
| Изменение WAF-настроек | Изменения waf_enabled, waf_vendor, waf_instance |
| Удаление ресурса | SID, домен, предупреждение с указанием конкретного WAF-вендора |
| Обновление whitelist | Добавленные/удалённые IP с привязкой к SID и домену, итоговое количество |
---
## Зависимости
| Пакет | Назначение |
|---|---|
| `github.com/lib/pq` | PostgreSQL драйвер |
| `github.com/joho/godotenv` | Загрузка `.env` файла |
| `golang.org/x/net` | SOCKS5 прокси для Telegram |
| `net/smtp` | Отправка email (стандартная библиотека) |