24 KiB
Magos - Схема базы данных
Обзор
Magos работает с PostgreSQL базой данных waf_info, которая содержит конфигурации WAF платформы. Программа использует 5 основных таблиц для получения информации о хостах, клиентах, приложениях и backend серверах.
Используемые таблицы
- instances - информация о хостах/серверах
- client_info - данные клиентов и контейнеров
- apps_settings - настройки приложений и кастомные директивы
- origins - backend серверы (получаются через REST API)
- aliases - дополнительные домены (получаются через REST API)
- ips - IP адреса для WAF и antibot сетей
Подключение к БД
Параметры подключения
DB_USER=login
DB_PASSWORD=password
DB_NAME=waf_info
DB_PORT=5432
PRIMARY_DB_HOST=10.10.10.8
SECONDARY_DB_HOST=10.10.10.5
Failover логика
- Попытка подключения к Primary DB (10.10.10.8)
- Если неудача → подключение к Secondary DB (10.10.10.5)
- Если обе недоступны → программа останавливается
Функция: connectToDB()
Таблица: instances
Назначение
Хранит информацию о хостах/серверах в кластере PTAF.
Структура
| Поле | Тип | Описание | Пример |
|---|---|---|---|
hostname |
TEXT | Hostname сервера | host01.example.com |
instance |
TEXT | Идентификатор инстанса | waf-prod-01 |
Используемые запросы
1. Получение instance по hostname
SELECT instance
FROM instances
WHERE hostname = $1;
Функция: getInstanceByHostname(hostname string)
Использование: При старте программы для определения какой это инстанс.
Пример:
hostname := "host01.example.com"
instance, err := getInstanceByHostname(db, hostname)
// instance = "waf-prod-01"
2. Проверка принадлежности хоста к инстансу
SELECT COUNT(*)
FROM instances
WHERE hostname = $1 AND instance = $2;
Функция: checkHostBelongsToInstance(hostname, instance string)
Использование: Валидация что хост принадлежит данному инстансу.
Пример:
hostname := "host01.example.com"
instance := "waf-prod-01"
err := checkHostBelongsToInstance(db, hostname, instance)
// err == nil если хост принадлежит инстансу
Примеры данных
INSERT INTO instances (hostname, instance) VALUES
('host01.example.com', 'waf-prod-01'),
('host02.example.com', 'waf-prod-01'),
('host03.example.com', 'waf-prod-02');
Таблица: client_info
Назначение
Хранит информацию о клиентах: количество контейнеров, привязка к инстансу.
Структура
| Поле | Тип | Описание | Пример |
|---|---|---|---|
client_title |
TEXT | Идентификатор клиента | CLIENT001 |
containers_count |
INTEGER | Количество контейнеров | 3 |
ptaf_config |
TEXT | Конфигурация PTAF (JSON) | {"key": "value"} |
fluent_bit_port |
INTEGER | Порт Fluent Bit | 24224 |
waf_instance |
TEXT | Instance для apps_settings | waf-prod-01 |
Используемые запросы
1. Получение клиентов по instance
SELECT
containers_count,
ptaf_config,
client_title,
fluent_bit_port,
waf_instance
FROM client_info
WHERE waf_instance = $1;
Функция: getClientInfoByInstance(instance string)
Использование: Получение всех клиентов для данного инстанса.
Пример:
instance := "waf-prod-01"
clients, err := getClientInfoByInstance(db, instance)
// clients = [{ContainersCount: 3, ClientTitle: "CLIENT001", ...}, ...]
2. Получение клиента по client_title
SELECT
containers_count,
ptaf_config,
client_title,
fluent_bit_port,
waf_instance
FROM client_info
WHERE client_title = $1;
Функция: getClientInfoByClientTitle(clientTitle string)
Использование: Получение информации о конкретном клиенте.
Примеры данных
INSERT INTO client_info
(client_title, containers_count, ptaf_config, fluent_bit_port, waf_instance)
VALUES
('CLIENT001', 3, '{"version": "1.0"}', 24224, 'waf-prod-01'),
('CLIENT002', 5, '{"version": "1.0"}', 24225, 'waf-prod-01'),
('CLIENT003', 2, '{"version": "1.0"}', 24226, 'waf-prod-02');
Ключевое поле: containers_count
Назначение: Определяет сколько Docker контейнеров нужно создать для клиента.
Логика:
containers_count = 3→ создать ptaf_client_001, ptaf_client_002, ptaf_client_003- При увеличении → создаются новые контейнеры
- При уменьшении → лишние контейнеры помечаются на graceful shutdown (90s)
Пример изменения:
-- Увеличить до 5 контейнеров
UPDATE client_info
SET containers_count = 5
WHERE client_title = 'CLIENT001';
-- Manager автоматически создаст ptaf_client_004 и ptaf_client_005
Таблица: apps_settings
Назначение
Основная таблица с настройками приложений и кастомными директивами Nginx/Angie.
Структура
| Поле | Тип | Описание | Значение по умолчанию |
|---|---|---|---|
l7resourceid |
INTEGER | ID ресурса | Первичный ключ |
client_title |
TEXT | Клиент (FK) | CLIENT001 |
waf_enabled |
BOOLEAN | WAF включен | true |
sni |
INTEGER | SNI режим (0=keepalive on, 1=keepalive off) | 0 |
custom_input_http_ports |
INTEGER[] | HTTP порты для прослушивания | {80, 8080} |
custom_input_https_ports |
INTEGER[] | HTTPS порты для прослушивания | {443, 8443} |
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) | NULL |
server_angie_custom |
TEXT | Полная замена server блока (Angie) | NULL |
server_nginx_custom |
TEXT | Полная замена server блока (Nginx) | NULL |
server_directives_angie_custom |
TEXT | Кастомные server директивы (Angie) | NULL |
server_directives_nginx_custom |
TEXT | Кастомные server директивы (Nginx) | NULL |
location_angie_custom |
TEXT | Кастомные location блоки (Angie) | NULL |
location_nginx_custom |
TEXT | Кастомные location блоки (Nginx) | NULL |
Используемые запросы
Получение настроек по client_title
SELECT
l7resourceid,
waf_enabled,
custom_input_http_ports,
custom_input_https_ports,
custom_output_http_ports,
custom_output_https_ports,
upstream_angie_custom,
server_nginx_custom,
server_angie_custom,
client_title,
upstream_nginx_custom,
location_angie_custom,
location_nginx_custom,
server_directives_angie_custom,
server_directives_nginx_custom,
sni
FROM apps_settings
WHERE client_title = $1
ORDER BY l7resourceid ASC;
Функция: getAppsSettingsByClientTitle(clientTitle string)
Использование: Получение всех настроек приложений для клиента.
Примеры данных
INSERT INTO apps_settings
(l7resourceid, client_title, waf_enabled, sni,
custom_input_http_ports, custom_input_https_ports,
custom_output_http_ports, custom_output_https_ports)
VALUES
(12323, 'CLIENT001', true, 0, '{80}', '{443}', '{80}', '{443}'),
(12324, 'CLIENT001', true, 0, '{80,8080}', '{443,8443}', '{80}', '{443}'),
(15000, 'CLIENT002', true, 0, '{80}', '{443}', '{80}', '{443}');
Кастомные поля (подробно)
upstream_angie_custom / upstream_nginx_custom
Режим: REPLACE (полная замена keepalive директив)
NULL значение:
upstream backend {
server 127.0.0.1:21000;
# Default upstream directives
keepalive 60;
keepalive_timeout 70s;
}
НЕ NULL значение:
upstream backend {
server 127.0.0.1:21000;
# Custom upstream directives (replace defaults)
keepalive 200;
keepalive_timeout 90s;
least_conn;
}
Пример SQL:
-- Изменить балансировку на least_conn
UPDATE apps_settings
SET upstream_angie_custom = 'keepalive 60;
keepalive_timeout 70s;
least_conn;'
WHERE l7resourceid = 12323;
-- Вернуть дефолты
UPDATE apps_settings
SET upstream_angie_custom = NULL
WHERE l7resourceid = 12323;
server_directives_angie_custom / server_directives_nginx_custom
Режим: REPLACE (замена else блока в server)
NULL значение:
server {
listen 443 ssl;
# Default directives
keepalive_timeout 80s;
send_timeout 60s;
proxy_connect_timeout 60s;
proxy_read_timeout 120s;
proxy_send_timeout 120s;
large_client_header_buffers 4 128k;
proxy_buffers 4 32k;
proxy_buffer_size 16k;
proxy_busy_buffers_size 32k;
}
НЕ NULL значение:
server {
listen 443 ssl;
# Custom directives (replace defaults)
keepalive_timeout 120s;
client_max_body_size 100m;
# Нужно указать ВСЕ директивы, включая буферы!
}
Пример SQL:
-- Увеличить таймауты
UPDATE apps_settings
SET server_directives_angie_custom = 'keepalive_timeout 120s;
send_timeout 90s;
proxy_connect_timeout 90s;
proxy_read_timeout 180s;
proxy_send_timeout 180s;
large_client_header_buffers 4 128k;
proxy_buffers 4 32k;
proxy_buffer_size 16k;'
WHERE l7resourceid = 12323;
server_angie_custom / server_nginx_custom
Режим: SERVER_BLOCK (полная замена всего server блока)
NULL значение: Используется стандартный шаблон server блока
НЕ NULL значение: Полная замена server блока
Пример SQL:
-- Создать полностью кастомный server блок
UPDATE apps_settings
SET server_angie_custom = 'server {
listen 9999;
server_name special.example.com;
location / {
return 200 "Custom response";
}
}'
WHERE l7resourceid = 12323;
location_angie_custom / location_nginx_custom
Режим: APPEND (добавление к дефолтному location)
NULL значение: Только стандартный location / { proxy_pass }
НЕ NULL значение: Добавляются дополнительные location блоки
Пример SQL:
-- Добавить location для API
UPDATE apps_settings
SET location_nginx_custom = 'location /api {
proxy_pass http://api.backend.com;
proxy_set_header X-API-Key secret;
}
location /static {
alias /var/www/static;
}'
WHERE l7resourceid = 12323;
sni (Server Name Indication)
Значения:
0- Keepalive ВКЛЮЧЕН (дефолт)1- Keepalive ОТКЛЮЧЕН
Когда sni = 1:
- Директивы
keepaliveиkeepalive_timeoutНЕ добавляются в upstream - Используется для SNI passthrough (прямая передача без терминации SSL)
Пример SQL:
-- Отключить keepalive для SNI passthrough
UPDATE apps_settings
SET sni = 1
WHERE l7resourceid = 12323;
custom_input_ports и custom_output_ports
custom_input_http_ports / custom_input_https_ports:
- Порты на которых Angie и Nginx контейнеры будут слушать
- Angie слушает на этих портах (80, 443, 8080, 8443)
- Nginx контейнеры слушают на этих же портах
custom_output_http_ports / custom_output_https_ports:
- Порты к которым Nginx контейнеры будут проксировать на backend
- Обычно {80} для HTTP и {443} для HTTPS
- Могут быть нестандартные порты (8080, 8443)
Пример:
-- Приложение слушает на портах 80, 8080 (HTTP) и 443, 8443 (HTTPS)
-- Backend работает на порту 443
UPDATE apps_settings
SET
custom_input_http_ports = '{80, 8080}',
custom_input_https_ports = '{443, 8443}',
custom_output_http_ports = '{80}',
custom_output_https_ports = '{443}'
WHERE l7resourceid = 12323;
Результат:
# Angie
server {
listen 80; # custom_input_http_ports[0]
listen 8080; # custom_input_http_ports[1]
listen 443 ssl; # custom_input_https_ports[0]
listen 8443 ssl; # custom_input_https_ports[1]
}
# Nginx upstream
upstream backend {
server 185.22.65.148:443; # custom_output_https_ports[0]
}
Таблица: ips
Назначение
Хранит IP адреса для WAF и antibot сетей (белые списки).
Структура
| Поле | Тип | Описание |
|---|---|---|
antibot_networks |
TEXT[] | IP сети для antibot |
waf_networks |
TEXT[] | IP сети для WAF |
Используемые запросы
SELECT antibot_networks, waf_networks
FROM ips;
Функция: loadIPsFromDB()
Использование: При старте программы для загрузки IP сетей.
Пример данных:
INSERT INTO ips (antibot_networks, waf_networks) VALUES
(
'{172.16.0.0/12, 10.0.0.0/8}',
'{172.16.0.0/12, 10.100.0.0/16}'
);
Использование в конфигах:
server {
# Доверенные IP для получения реального IP клиента
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 10.100.0.0/16;
real_ip_header X-Forwarded-For;
}
REST API (origins и aliases)
Origins (Backend серверы)
Не хранятся в БД, получаются через REST API.
Эндпоинт: /api/waf-proxy/get-apps-and-resourses
Функция: makeAPIRequest(), getResourceDataFromCache()
Пример ответа:
{
"data": {
"result": {
"items": [
{
"id": 1,
"ip": "185.22.65.148",
"weight": 100,
"mode": "active",
"comment": "Primary backend"
},
{
"id": 2,
"ip": "185.22.65.149",
"weight": 50,
"mode": "backup",
"comment": "Backup backend"
}
]
}
}
}
Использование в конфигах:
upstream backend {
server 185.22.65.148:443 weight=100;
server 185.22.65.149:443 weight=50 backup;
}
Aliases (Дополнительные домены)
Не хранятся в БД, получаются через REST API.
Эндпоинт: /api/waf-proxy/get-apps-and-resourses
Пример ответа:
{
"data": {
"result": {
"items": [
{
"id": 1,
"alias": "www.example.com"
},
{
"id": 2,
"alias": "app.example.com"
}
]
}
}
}
Использование в конфигах:
server {
listen 443 ssl;
server_name example.com www.example.com app.example.com;
}
Связи между таблицами
instances
↓ (hostname → instance)
client_info (waf_instance)
↓ (client_title)
apps_settings (client_title)
↓ (l7resourceid через API)
Origins (от REST API)
Aliases (от REST API)
Поток данных:
- Program запускается на хосте с hostname =
host01.example.com - Запрос к
instances→ получаемinstance = "waf-prod-01" - Запрос к
client_infoWHEREwaf_instance = "waf-prod-01"→ получаем клиентов - Для каждого клиента запрос к
apps_settingsWHEREclient_title = "CLIENT001" - Для каждого ресурса API запрос → получаем origins и aliases
- Генерируем конфиги на основе всех данных
Примеры типичных запросов
Получить все ресурсы клиента
SELECT
a.l7resourceid,
a.custom_input_https_ports,
a.upstream_angie_custom,
c.containers_count
FROM apps_settings a
JOIN client_info c ON a.client_title = c.client_title
WHERE a.client_title = 'CLIENT001'
ORDER BY a.l7resourceid;
Изменить количество контейнеров
-- Увеличить до 5
UPDATE client_info
SET containers_count = 5
WHERE client_title = 'CLIENT001';
-- Проверка
SELECT client_title, containers_count
FROM client_info
WHERE client_title = 'CLIENT001';
Добавить кастомную балансировку
UPDATE apps_settings
SET upstream_nginx_custom = 'keepalive 60;
keepalive_timeout 70s;
least_conn;'
WHERE l7resourceid = 12323;
-- Проверка
SELECT l7resourceid, upstream_nginx_custom
FROM apps_settings
WHERE l7resourceid = 12323;
Включить SNI passthrough
UPDATE apps_settings
SET sni = 1
WHERE l7resourceid = 12323;
-- Проверка
SELECT l7resourceid, sni
FROM apps_settings
WHERE sni = 1;
Добавить дополнительные порты
UPDATE apps_settings
SET
custom_input_https_ports = '{443, 8443, 9443}',
custom_output_https_ports = '{443, 8443, 9443}'
WHERE l7resourceid = 12323;
-- Проверка
SELECT l7resourceid, custom_input_https_ports, custom_output_https_ports
FROM apps_settings
WHERE l7resourceid = 12323;
Индексы (рекомендуемые)
-- Для быстрого поиска по hostname
CREATE INDEX idx_instances_hostname ON instances(hostname);
-- Для быстрого поиска клиентов по instance
CREATE INDEX idx_client_info_waf_instance ON client_info(waf_instance);
CREATE INDEX idx_client_info_client_title ON client_info(client_title);
-- Для быстрого поиска настроек по client_title
CREATE INDEX idx_apps_settings_client_title ON apps_settings(client_title);
CREATE INDEX idx_apps_settings_l7resourceid ON apps_settings(l7resourceid);
Миграции и изменения схемы
Добавление нового кастомного поля
-- Добавить новое поле для header манипуляций
ALTER TABLE apps_settings
ADD COLUMN headers_custom TEXT DEFAULT NULL;
-- Обновить код для чтения этого поля
Изменение типа поля
-- Изменить тип sni на boolean (если сейчас integer)
ALTER TABLE apps_settings
ALTER COLUMN sni TYPE BOOLEAN
USING (sni::integer = 0);
Best Practices
1. NULL vs пустая строка
Правильно:
UPDATE apps_settings
SET upstream_angie_custom = NULL -- NULL для дефолтов
WHERE l7resourceid = 12323;
Неправильно:
UPDATE apps_settings
SET upstream_angie_custom = '' -- Пустая строка может вызвать ошибки
WHERE l7resourceid = 12323;
2. Массивы портов
Правильно:
UPDATE apps_settings
SET custom_input_https_ports = '{443, 8443}' -- PostgreSQL array
WHERE l7resourceid = 12323;
Неправильно:
UPDATE apps_settings
SET custom_input_https_ports = '443,8443' -- Строка, не массив
WHERE l7resourceid = 12323;
3. Многострочные кастомные директивы
Правильно:
UPDATE apps_settings
SET server_directives_angie_custom = 'keepalive_timeout 80s;
send_timeout 60s;
proxy_buffers 4 32k;'
WHERE l7resourceid = 12323;
Также правильно (с экранированием):
UPDATE apps_settings
SET server_directives_angie_custom = E'keepalive_timeout 80s;\nsend_timeout 60s;'
WHERE l7resourceid = 12323;
Мониторинг БД
Проверка соединения
-- Проверить активные соединения
SELECT
datname,
usename,
client_addr,
state,
query_start
FROM pg_stat_activity
WHERE datname = 'waf_info';
Проверка данных
-- Количество клиентов на каждом instance
SELECT waf_instance, COUNT(*) as clients_count
FROM client_info
GROUP BY waf_instance;
-- Количество ресурсов на клиента
SELECT client_title, COUNT(*) as resources_count
FROM apps_settings
GROUP BY client_title;
-- Клиенты с кастомными upstream директивами
SELECT client_title, l7resourceid
FROM apps_settings
WHERE upstream_angie_custom IS NOT NULL
OR upstream_nginx_custom IS NOT NULL;
Резервное копирование
# Дамп всей БД
pg_dump -h 10.100.10.8 -U install -d waf_info > waf_info_backup.sql
# Дамп только структуры
pg_dump -h 10.100.10.8 -U install -d waf_info --schema-only > schema.sql
# Дамп только данных
pg_dump -h 10.100.10.8 -U install -d waf_info --data-only > data.sql
# Восстановление
psql -h 10.100.10.8 -U install -d waf_info < waf_info_backup.sql
Итого
Основные таблицы
| Таблица | Записей (примерно) | Частота изменений |
|---|---|---|
| instances | 10-50 | Редко (при добавлении хостов) |
| client_info | 50-500 | Редко (при добавлении клиентов) |
| apps_settings | 500-5000 | Часто (изменение настроек) |
| ips | 1 | Очень редко |
Ключевые связи
instances.instance→client_info.waf_instanceclient_info.client_title→apps_settings.client_titleapps_settings.l7resourceid→ REST API (origins, aliases)
Кастомизация
Все кастомные поля в apps_settings:
- 8 полей для кастомных директив
- 4 режима: REPLACE (upstream, server_directives), SERVER_BLOCK, APPEND (location)
- NULL = дефолты, NOT NULL = кастом