From 79a6814d4e0a1a687190a448c4c7c4ccdb70d21d Mon Sep 17 00:00:00 2001 From: Magnus Root Date: Wed, 10 Jun 2026 16:21:30 +0300 Subject: [PATCH] Update docs --- ARCHITECTURE.md | 76 ++++++++++++++++++++++++++++++++++++++++++++-- DATABASE_SCHEMA.md | 21 +++++++++++-- nginx.go | 4 +-- 3 files changed, 95 insertions(+), 6 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index a525c12..f7f20c4 100755 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -163,6 +163,7 @@ waf-host-02 | instance-c - fail_timeout # Время восстановления сервера (дефолт 15с) - balancing_method # Метод балансировки: least_conn, ip_hash, random и др. - proxy_next_upstream_codes # HTTP-коды для proxy_next_upstream (дефолт: 500,502,503,504) +- x_sid_check # Маршрутизация в Angie по X-Sid заголовку (дефолт: false) ``` #### Таблица `sp_info` (кэш API данных) @@ -558,7 +559,69 @@ proxy_next_upstream error timeout invalid_header http_502 http_503 http_504; --- -## Именование контейнеров +## Маршрутизация по X-Sid + +### Проблема + +Когда два разных тенанта WAF имеют одинаковый FQDN — возникает конфликт: +- На уровне Angie: два server-блока с одинаковым `server_name` — Angie выберет первый +- На уровне nginx внутри контейнера: два server-блока с одинаковым `server_name` — nginx выберет первый + +### Решение + +Используется комбинация двух механизмов: + +**1. `x_sid_check = true` в `apps_settings` — решает проблему на уровне Angie:** + +Вместо `server_name domain.ru` генерируется `server_name _` и map блок: + +```nginx +map $http_x_sid $x_sid_upstream_https_443 { + default ""; + "10111" "secure10111_443_domain.ru"; + "10112" "secure10112_443_domain.ru"; +} + +server { + listen 443 ssl; + server_name _; + location / { + if ($x_sid_upstream_https_443 = "") { return 444; } + proxy_pass http://$x_sid_upstream_https_443; + } +} +``` + +Клиент должен передавать заголовок `X-Sid: {l7ResourceID}` в каждом запросе. + +**Ограничения `x_sid_check`:** +- `proxy_pass` с переменной не использует keepalive пул upstream +- max_fails/fail_timeout для контейнера не работают +- Для Angie → контейнер (`127.0.0.1`) это некритично + +**2. Блочный режим (`one_container = false`) — решает проблему внутри контейнера:** + +Конфликтующие SID разносятся по разным контейнерам. Каждый контейнер содержит только свои SID — конфликта server_name внутри контейнера нет. + +При блочном режиме также генерируются отдельные Angie конфиги: +- `angie-ptaf-{clientTitle}_block1.conf` — SID блока 1 +- `angie-ptaf-{clientTitle}_block2.conf` — SID блока 2 + +Если FQDN одинаковый в разных блоках — нужно включить `x_sid_check = true` для этих ресурсов чтобы Angie корректно маршрутизировал между блоками. + +### Итоговая схема при одинаковых FQDN + +``` +x_sid_check = true + one_container = false + sid_block + +Клиент (X-Sid: 10111, Host: domain.ru) + → Angie: map[$http_x_sid] → upstream блока 1 → контейнер block1 + → nginx block1: server_name domain.ru → upstream к origin тенанта 1 + +Клиент (X-Sid: 10112, Host: domain.ru) + → Angie: map[$http_x_sid] → upstream блока 2 → контейнер block2 + → nginx block2: server_name domain.ru → upstream к origin тенанта 2 +``` Имя Docker-контейнера формируется динамически на основе hostname хоста: @@ -810,7 +873,16 @@ UPDATE client_info SET shm_size = 8 WHERE client_title = 'CLIENT001'; UPDATE apps_settings SET balancing_method = 'least_conn' WHERE l7resourceid = 12345; ``` -### Включить блочный режим (разбивка SID по контейнерам) +### Включить маршрутизацию по X-Sid для ресурса + +```sql +-- Включить x_sid_check для конкретного ресурса +UPDATE apps_settings +SET x_sid_check = true +WHERE l7resourceid = 10111; +``` + +Клиент должен передавать заголовок `X-Sid: 10111` в каждом запросе. ```sql -- Три блока SID, каждый в своём наборе контейнеров diff --git a/DATABASE_SCHEMA.md b/DATABASE_SCHEMA.md index fddf5c4..9b8c818 100755 --- a/DATABASE_SCHEMA.md +++ b/DATABASE_SCHEMA.md @@ -314,6 +314,7 @@ WHERE client_title = 'CLIENT001'; | `fail_timeout` | INTEGER | Время восстановления сервера (сек) | `15` | | `balancing_method` | TEXT | Метод балансировки upstream | `NULL` | | `proxy_next_upstream_codes` | TEXT | HTTP-коды для proxy_next_upstream | `'500,502,503,504'` | +| `x_sid_check` | BOOLEAN | Маршрутизация в Angie по X-Sid заголовку | `false` | ### Используемые запросы @@ -345,7 +346,8 @@ SELECT max_fails, fail_timeout, balancing_method, - proxy_next_upstream_codes + proxy_next_upstream_codes, + x_sid_check FROM apps_settings WHERE client_title = $1 ORDER BY l7resourceid ASC; @@ -364,6 +366,9 @@ ALTER TABLE apps_settings ALTER TABLE apps_settings ADD COLUMN IF NOT EXISTS proxy_next_upstream_codes TEXT DEFAULT '500,502,503,504'; + +ALTER TABLE apps_settings + ADD COLUMN IF NOT EXISTS x_sid_check BOOLEAN DEFAULT FALSE; ``` ### Кастомные поля (подробно) @@ -403,7 +408,16 @@ WHERE l7resourceid = 12345; proxy_next_upstream error timeout invalid_header http_502 http_503 http_504; ``` -#### upstream_angie_custom / upstream_nginx_custom +#### x_sid_check + +При `true` — Angie маршрутизирует запросы по заголовку `X-Sid` вместо `server_name`. Используется когда один и тот же FQDN присутствует в разных тенантах WAF. В связке с блочным режимом (`one_container = false`) даёт полное решение проблемы конфликта FQDN. + +```sql +-- Включить маршрутизацию по X-Sid для ресурса +UPDATE apps_settings SET x_sid_check = true WHERE l7resourceid = 10111; +``` + +Клиент должен передавать заголовок `X-Sid: {l7resourceid}` в каждом запросе. **Режим:** REPLACE (полная замена keepalive директив) @@ -641,6 +655,9 @@ SELECT client_title FROM client_info WHERE debug = true; -- Клиенты с индивидуальным образом SELECT client_title, docker_image FROM client_info WHERE docker_image IS NOT NULL; +-- Ресурсы с маршрутизацией по X-Sid +SELECT client_title, l7resourceid FROM apps_settings WHERE x_sid_check = true; + -- Клиенты в блочном режиме SELECT client_title, sid_block FROM client_info WHERE one_container = false; diff --git a/nginx.go b/nginx.go index bce17f9..dc8b394 100755 --- a/nginx.go +++ b/nginx.go @@ -525,7 +525,7 @@ func writeNginxStandardSettings(f *os.File, customDirectives string, proxyNextUp f.WriteString(fmt.Sprintf(" proxy_next_upstream %s;\n", proxyNextUpstream)) f.WriteString(" proxy_http_version 1.1;\n") f.WriteString("\n") - f.WriteString(" #proxy_set_header X-Real-IP $remote_addr;\n") + f.WriteString(" proxy_set_header X-Real-IP $remote_addr;\n") f.WriteString(" proxy_set_header X-Forwarded-For $remote_addr;\n") f.WriteString(" proxy_set_header Connection $proxy_connection;\n") f.WriteString(" proxy_set_header Upgrade $http_upgrade;\n") @@ -980,4 +980,4 @@ func generateCustomServerBlock(f *os.File, res ResourceData, block CustomServerB f.WriteString(fmt.Sprintf(" proxy_pass %s://%s;\n", protocol, upstreamName)) f.WriteString(" }\n") f.WriteString("}\n\n") -} \ No newline at end of file +}