# Magos - Схема базы данных --- ## Обзор Magos работает с PostgreSQL базой данных, которая содержит конфигурации WAF платформы. Программа использует несколько основных таблиц для получения информации о хостах, клиентах, приложениях и backend серверах. ### Используемые таблицы 1. **instances_new** - информация о хостах/серверах 2. **client_info** - данные клиентов и контейнеров 3. **apps_settings** - настройки приложений и кастомные директивы 4. **sp_info** - кэш данных из API (origins, aliases) 5. **manual_info** - ручные данные (альтернатива API) 6. **ips** - IP адреса для WAF и antibot сетей --- ## Подключение к БД ### Параметры подключения ```bash DB_USER=login DB_PASSWORD=password DB_NAME=waf_info DB_PORT=5432 PRIMARY_DB_HOST=10.100.10.8 SECONDARY_DB_HOST=10.100.13.5 ``` ### Failover логика 1. Попытка подключения к Primary DB 2. Если неудача → подключение к Secondary DB 3. Если обе недоступны → программа останавливается **Функция:** `connectToDB()` --- ## Таблица: instances_new ### Назначение Хранит информацию о хостах/серверах в кластере WAF. ### Структура | Поле | Тип | Описание | Пример | |------|-----|----------|--------| | `hostname` | TEXT | Hostname сервера | `host01.example.com` | | `instance` | TEXT | Идентификатор инстанса | `waf-prod-01` | ### Используемые запросы #### Получение instances по hostname ```sql SELECT instance FROM instances_new WHERE hostname = $1; ``` **Функция:** `getInstancesByHostname(hostname string)` Один хост может принадлежать нескольким instances. #### Проверка принадлежности хоста к инстансу ```sql SELECT COUNT(*) FROM instances_new WHERE hostname = $1 AND instance = $2; ``` **Функция:** `checkHostBelongsToInstance(hostname, instance string)` --- ## Таблица: client_info ### Назначение Хранит информацию о клиентах: количество контейнеров, Docker-образ, режим отладки и привязка к инстансу. ### Структура | Поле | Тип | Описание | Пример | |------|-----|----------|--------| | `client_title` | TEXT | Идентификатор клиента | `CLIENT001` | | `containers_count` | INTEGER | Количество контейнеров (0 = drain всех) | `3` | | `ptaf_config` | TEXT | Строка подключения к PTAF-серверу | `{...}` | | `fluent_bit_port` | INTEGER | Порт Fluent Bit | `24224` | | `waf_instance` | TEXT | Instance для привязки к хосту | `waf-prod-01` | | `docker_image` | TEXT | Docker-образ (переопределяет глобальный) | `ptaf-core-nginx-agent:release-4.3.1...` | | `docker_image_download` | TEXT | URL для скачивания tar-архива образа | `https://...` | | `debug` | BOOLEAN | Режим отладки | `false` | | `shm_size` | INTEGER | Размер /dev/shm в GB | `1` | | `ptaf_fallback_code` | TEXT | Код ответа ptaf_fallback: число или 'pass' | `418` | | `sp_antiddos` | BOOLEAN | Использовать антиддос сети в set_real_ip | `true` | | `real_ip_networks` | INET[] | Кастомные сети для set_real_ip (если sp_antiddos=false) | `{10.0.0.0/8}` | | `worker_processes` | INTEGER | Количество worker процессов nginx | `4` | ### Используемые запросы #### Получение клиентов по instance ```sql SELECT containers_count, ptaf_config, client_title, fluent_bit_port, waf_instance, docker_image, docker_image_download, debug, shm_size, ptaf_fallback_code, sp_antiddos, real_ip_networks, worker_processes FROM client_info WHERE waf_instance = $1; ``` **Функция:** `getClientInfoByInstance(instance string)` #### Получение клиента по client_title ```sql SELECT containers_count, ptaf_config, client_title, fluent_bit_port, waf_instance, docker_image, docker_image_download, debug, shm_size, ptaf_fallback_code, sp_antiddos, real_ip_networks, worker_processes FROM client_info WHERE client_title = $1; ``` **Функция:** `getClientInfoByClientTitle(clientTitle string)` ### Миграции ```sql ALTER TABLE client_info ADD COLUMN IF NOT EXISTS docker_image TEXT DEFAULT NULL; ALTER TABLE client_info ADD COLUMN IF NOT EXISTS docker_image_download TEXT DEFAULT NULL; ALTER TABLE client_info ADD COLUMN IF NOT EXISTS debug BOOLEAN DEFAULT FALSE; ALTER TABLE client_info ADD COLUMN IF NOT EXISTS shm_size INTEGER DEFAULT 1; ALTER TABLE client_info ADD COLUMN IF NOT EXISTS ptaf_fallback_code TEXT DEFAULT '418'; ALTER TABLE client_info ADD COLUMN IF NOT EXISTS sp_antiddos BOOLEAN DEFAULT TRUE; ALTER TABLE client_info ADD COLUMN IF NOT EXISTS real_ip_networks INET[] DEFAULT NULL; ALTER TABLE client_info ADD COLUMN IF NOT EXISTS worker_processes INTEGER DEFAULT 4; ``` ### Ключевые поля #### containers_count - `containers_count = 3` → создать ptaf_client_001, ptaf_client_002, ptaf_client_003 - При увеличении → новые контейнеры добавляются, существующие не трогаются - При уменьшении → лишние контейнеры помечаются на graceful drain (90с) - `containers_count = 0` → все контейнеры и Angie-конфиг помечаются на drain #### docker_image / docker_image_download Если заполнены — используются вместо глобальных настроек `DOCKER_IMAGE` и `DOCKER_IMAGE_URL` из `magos.env`. Позволяют иметь разные версии агента для разных клиентов. #### debug При `true`: - В docker-compose добавляются `PTAF_DEBUG=True` и `ERROR_LOG_LEVEL=debug` - В nginx.conf: `PTAF_LOG_LEVEL=DEBUG`, `DEBUG=true`, `error_log stderr debug` - В Angie server-блоки добавляется `client_body_buffer_size 1m` #### shm_size Размер разделяемой памяти `/dev/shm` для Docker-контейнера в гигабайтах. Результат в docker-compose: `shm_size: '2gb'`. Дефолт: 1. #### ptaf_fallback_code Код HTTP ответа который PTAF возвращает когда WAF-модуль недоступен. Записывается в блок `http {}` файла `nginx.conf` — применяется глобально для всех ресурсов контейнера. ```sql UPDATE client_info SET ptaf_fallback_code = 'pass' WHERE client_title = 'CLIENT001'; UPDATE client_info SET ptaf_fallback_code = '503' WHERE client_title = 'CLIENT001'; ``` #### worker_processes Количество worker процессов nginx внутри контейнера. Изменение вызывает `nginx -s reload` без пересоздания контейнера. Дефолт: 4. ```sql UPDATE client_info SET worker_processes = 8 WHERE client_title = 'CLIENT001'; ``` #### sp_antiddos / real_ip_networks `sp_antiddos = true` (дефолт) — в Angie используются антиддос сети из таблицы `ips` для `set_real_ip_from`. `sp_antiddos = false` + непустой `real_ip_networks` — вместо антиддос сетей используются кастомные сети из `real_ip_networks`. WAF сети из `ips` при этом всегда присутствуют. ```sql UPDATE client_info SET sp_antiddos = false, real_ip_networks = '{10.0.0.0/8, 192.168.1.0/24}' WHERE client_title = 'CLIENT001'; ``` --- ## Таблица: apps_settings ### Назначение Основная таблица с настройками приложений и кастомными директивами Nginx/Angie. ### Структура | Поле | Тип | Описание | Значение по умолчанию | |------|-----|----------|----------------------| | `l7resourceid` | INTEGER | ID ресурса | Первичный ключ | | `client_title` | TEXT | Клиент (FK) | — | | `waf_enabled` | BOOLEAN | WAF включен | `true` | | `waf_vendor` | TEXT | Вендор: 'ptaf' или 'sw' | — | | `mode` | TEXT | auto/manual/disabled | `auto` | | `sni` | INTEGER | SNI режим (0=keepalive on, 1=keepalive off) | `0` | | `ssl_enabled` | BOOLEAN | SSL на HTTPS портах | `true` | | `custom_input_http_ports` | INTEGER[] | HTTP порты для прослушивания | `{80}` | | `custom_input_https_ports` | INTEGER[] | HTTPS порты для прослушивания | `{443}` | | `custom_output_http_ports` | INTEGER[] | HTTP порты к backend | `{80}` | | `custom_output_https_ports` | INTEGER[] | HTTPS порты к backend | `{443}` | | `upstream_angie_custom` | TEXT | Кастомные upstream директивы (Angie) | `NULL` | | `upstream_nginx_custom` | TEXT | Кастомные upstream директивы (Nginx/SW) | `NULL` | | `server_angie_custom` | TEXT | Кастомный server блок (Angie) | `NULL` | | `server_nginx_custom` | TEXT | Кастомный server блок (Nginx/SW) | `NULL` | | `server_directives_angie_custom` | TEXT | Кастомные server директивы (Angie) | `NULL` | | `server_directives_nginx_custom` | TEXT | Кастомные server директивы (Nginx/SW) | `NULL` | | `location_angie_custom` | TEXT | Кастомные location блоки (Angie) | `NULL` | | `location_nginx_custom` | TEXT | Кастомные location блоки (Nginx/SW) | `NULL` | | `custom_angie_ssl` | TEXT | Замена SSL директив (Angie) | `NULL` | | `custom_sw_nginx_ssl` | TEXT | Замена SSL директив (SW) | `NULL` | | `max_fails` | INTEGER | Попыток до пометки сервера недоступным | `5` | | `fail_timeout` | INTEGER | Время восстановления сервера (сек) | `15` | | `balancing_method` | TEXT | Метод балансировки upstream | `NULL` | | `proxy_next_upstream_codes` | TEXT | HTTP-коды для proxy_next_upstream | `'500,502,503,504'` | ### Используемые запросы #### Получение настроек по client_title ```sql SELECT l7resourceid, waf_enabled, waf_vendor, mode, custom_input_http_ports, custom_input_https_ports, custom_output_http_ports, custom_output_https_ports, upstream_angie_custom, upstream_nginx_custom, server_nginx_custom, server_angie_custom, location_angie_custom, location_nginx_custom, server_directives_angie_custom, server_directives_nginx_custom, custom_angie_ssl, custom_sw_nginx_ssl, client_title, sni, ssl_enabled, max_fails, fail_timeout, balancing_method, proxy_next_upstream_codes FROM apps_settings WHERE client_title = $1 ORDER BY l7resourceid ASC; ``` **Функция:** `getAppsSettingsByClientTitle(clientTitle string)` ### Миграции ```sql ALTER TABLE apps_settings ADD COLUMN IF NOT EXISTS custom_sw_nginx_ssl TEXT DEFAULT NULL; ALTER TABLE apps_settings ADD COLUMN IF NOT EXISTS balancing_method TEXT DEFAULT NULL; ALTER TABLE apps_settings ADD COLUMN IF NOT EXISTS proxy_next_upstream_codes TEXT DEFAULT '500,502,503,504'; ``` ### Кастомные поля (подробно) #### balancing_method Метод балансировки upstream. Записывается **без** точки с запятой. Вставляется первой строкой в upstream-блок. ```sql -- Включить least_conn UPDATE apps_settings SET balancing_method = 'least_conn' WHERE l7resourceid = 12345; -- Вернуть round-robin (дефолт) UPDATE apps_settings SET balancing_method = NULL WHERE l7resourceid = 12345; ``` Допустимые значения: `least_conn`, `ip_hash`, `random`, `random two least_conn` #### proxy_next_upstream_codes Коды HTTP ответов при которых Angie/nginx переключается на следующий upstream-сервер. Записывается через запятую **без** префикса `http_`. ```sql -- Убрать 500 из retry (бэкенд вернул 500, не нужно делать retry) UPDATE apps_settings SET proxy_next_upstream_codes = '502,503,504' WHERE l7resourceid = 12345; -- Вернуть дефолт UPDATE apps_settings SET proxy_next_upstream_codes = NULL WHERE l7resourceid = 12345; ``` Итоговая строка в конфиге: ```nginx proxy_next_upstream error timeout invalid_header http_502 http_503 http_504; ``` #### upstream_angie_custom / upstream_nginx_custom **Режим:** REPLACE (полная замена keepalive директив) ```sql -- Кастомный keepalive UPDATE apps_settings SET upstream_angie_custom = 'keepalive 200; keepalive_timeout 90s;' WHERE l7resourceid = 12345; ``` #### server_directives_angie_custom / server_directives_nginx_custom **Режим:** REPLACE (замена блока дефолтных таймаутов/буферов) **Важно:** при использовании кастома нужно указать ВСЕ нужные директивы, включая `proxy_set_header X-Request-ID`. #### server_angie_custom / server_nginx_custom Поддерживает формат SERVER_BLOCK для создания дополнительных server-блоков: ``` [SERVER_BLOCK:443:report.example.com:www.report.example.com] proxy_read_timeout 3600s; proxy_send_timeout 3600s; [/SERVER_BLOCK] ``` Синтаксис: `[SERVER_BLOCK:{порт}:{server_name}:{alias1}:{alias2}...]` #### custom_angie_ssl / custom_sw_nginx_ssl Полная замена SSL директив. При NULL используются дефолтные: ```nginx ssl_certificate ssl/cert.pem; ssl_certificate_key ssl/key.pem; ssl_protocols TLSv1.2 TLSv1.3; ``` --- ## Таблица: sp_info (кэш) ### Назначение Кэширует данные из ServicePipe API. TTL: 10 минут. ### Структура | Поле | Тип | Описание | |------|-----|----------| | `sid` | INTEGER | l7resourceid | | `domain_name` | TEXT | Основной домен | | `aliases` | JSON | Массив алиасов | | `origins` | JSON | Массив origin серверов | | `updated_at` | TIMESTAMP | Время последнего обновления | --- ## Таблица: manual_info ### Назначение Ручное управление данными ресурсов (альтернатива API). Используется при `mode = 'manual'`. ### Структура | Поле | Тип | Описание | |------|-----|----------| | `sid` | INTEGER | l7resourceid | | `domain_name` | TEXT | Основной домен | | `aliases` | JSON | Массив алиасов | | `origins` | JSON | Массив origin серверов | Данные не имеют TTL и всегда актуальны. --- ## Таблица: ips ### Структура | Поле | Тип | Описание | |------|-----|----------| | `id` | INTEGER | Всегда = 1 | | `antibot_networks` | TEXT[] | CIDR сети antibot | | `waf_networks` | TEXT[] | CIDR сети WAF (исключаются из origins) | --- ## Связи между таблицами ``` instances_new ↓ (hostname → instance) client_info (waf_instance) ↓ (client_title) apps_settings (client_title) ↓ (l7resourceid через API/manual_info) Origins, Aliases ``` --- ## Примеры типичных операций ### Добавить нового PTAF-клиента ```sql INSERT INTO client_info (client_title, containers_count, waf_instance) VALUES ('NewClient', 2, 'PTAFd_01'); INSERT INTO apps_settings (l7resourceid, client_title, waf_vendor, waf_enabled, mode) VALUES (99999, 'NewClient', 'ptaf', true, 'auto'); ``` ### Добавить нового SW-клиента ```sql INSERT INTO client_info (client_title, containers_count, waf_instance) VALUES ('NewSWClient', 0, 'SWd_01'); INSERT INTO apps_settings (l7resourceid, client_title, waf_vendor, waf_enabled, mode) VALUES (99998, 'NewSWClient', 'sw', true, 'auto'); ``` ### Изменить количество контейнеров ```sql -- Увеличить до 5 UPDATE client_info SET containers_count = 5 WHERE client_title = 'CLIENT001'; -- Отключить клиента (drain всех контейнеров) UPDATE client_info SET containers_count = 0 WHERE client_title = 'CLIENT001'; ``` ### Включить debug-режим ```sql UPDATE client_info SET debug = true WHERE client_title = 'CLIENT001'; ``` ### Задать индивидуальный Docker-образ ```sql UPDATE client_info SET docker_image = 'ptaf-core-nginx-agent:release-4.3.1.431839-debian-bullseye-nginx-1.28.0', docker_image_download = 'https://example.com/image.tar' WHERE client_title = 'CLIENT001'; ``` ### Настроить балансировку ```sql UPDATE apps_settings SET balancing_method = 'least_conn' WHERE l7resourceid = 12345; ``` ### Убрать 500 из retry ```sql UPDATE apps_settings SET proxy_next_upstream_codes = '502,503,504' WHERE l7resourceid = 12345; ``` ### Добавить кастомные SSL для SW ```sql UPDATE apps_settings SET custom_sw_nginx_ssl = 'ssl_certificate /etc/solidwall-nginx/ssl/custom.crt; ssl_certificate_key /etc/solidwall-nginx/ssl/custom.key; ssl_protocols TLSv1.2 TLSv1.3;' WHERE l7resourceid = 12345; ``` ### Добавить SERVER_BLOCK с увеличенными таймаутами ```sql UPDATE apps_settings SET server_angie_custom = '[SERVER_BLOCK:443:report.example.com:www.report.example.com] proxy_read_timeout 3600s; proxy_send_timeout 3600s; [/SERVER_BLOCK]' WHERE l7resourceid = 12345; ``` --- ## Best Practices ### NULL vs пустая строка ```sql -- Правильно: NULL для дефолтов UPDATE apps_settings SET upstream_angie_custom = NULL WHERE l7resourceid = 12345; -- Неправильно: пустая строка может вызвать ошибки UPDATE apps_settings SET upstream_angie_custom = '' WHERE l7resourceid = 12345; ``` ### Массивы портов ```sql -- Правильно: PostgreSQL array UPDATE apps_settings SET custom_input_https_ports = '{443, 8443}' WHERE l7resourceid = 12345; -- Неправильно: строка UPDATE apps_settings SET custom_input_https_ports = '443,8443' WHERE l7resourceid = 12345; ``` ### balancing_method — без точки с запятой ```sql -- Правильно UPDATE apps_settings SET balancing_method = 'least_conn' WHERE l7resourceid = 12345; -- Неправильно UPDATE apps_settings SET balancing_method = 'least_conn;' WHERE l7resourceid = 12345; ``` --- ## Мониторинг БД ```sql -- Количество клиентов на каждом instance SELECT waf_instance, COUNT(*) as clients_count FROM client_info GROUP BY waf_instance; -- Клиенты с debug-режимом SELECT client_title FROM client_info WHERE debug = true; -- Клиенты с индивидуальным образом SELECT client_title, docker_image FROM client_info WHERE docker_image IS NOT NULL; -- Клиенты с нестандартным количеством worker процессов SELECT client_title, worker_processes FROM client_info WHERE worker_processes != 4; -- Клиенты без антиддоса SELECT client_title, real_ip_networks FROM client_info WHERE sp_antiddos = false; -- Клиенты с кастомным ptaf_fallback SELECT client_title, ptaf_fallback_code FROM client_info WHERE ptaf_fallback_code != '418'; -- Ресурсы с кастомной балансировкой SELECT client_title, l7resourceid, balancing_method FROM apps_settings WHERE balancing_method IS NOT NULL; -- Ресурсы с кастомными upstream директивами SELECT client_title, l7resourceid FROM apps_settings WHERE upstream_angie_custom IS NOT NULL OR upstream_nginx_custom IS NOT NULL; ``` --- ## Индексы (рекомендуемые) ```sql CREATE INDEX idx_instances_new_hostname ON instances_new(hostname); CREATE INDEX idx_client_info_waf_instance ON client_info(waf_instance); CREATE INDEX idx_client_info_client_title ON client_info(client_title); CREATE INDEX idx_apps_settings_client_title ON apps_settings(client_title); CREATE INDEX idx_apps_settings_l7resourceid ON apps_settings(l7resourceid); ```