146 lines
10 KiB
Markdown
146 lines
10 KiB
Markdown
# module-03-vm2. Nginx ВМ2 Processing
|
||
|
||
> Статус: целевая спецификация nginx на ВМ2.
|
||
> Канонический контракт (TLS/ACME, request id, internal 404, logs, reload) — [`arch-08-nginx.md`](../../architectory/arch-08-nginx.md).
|
||
> Контур ВМ1 — [`module-03-nginx-vm1.md`](../../VM1_app/documentation/module-03-nginx-vm1.md). Guest API, SPA, auth и SMS callback на этой машине не публикуются.
|
||
|
||
## 1. Назначение и границы
|
||
|
||
Nginx ВМ2 — самостоятельный ingress Processing:
|
||
|
||
- public `80/443` на отдельном DNS host: ACME/redirect и два exact CRM webhook;
|
||
- private `8443` с сертификатом internal CA: только server-to-server Message Safety и approved ops.
|
||
|
||
Публичный трафик ВМ2 не проходит через ВМ1. Отказ nginx ВМ1 не прерывает приём CRM webhook. SPA, `/api/`, `/auth/`, WS и Direct SMS callback здесь отсутствуют.
|
||
|
||
## 2. Routing matrix
|
||
|
||
### Public `80/443`
|
||
|
||
| Внешний путь | Upstream | Режим |
|
||
|---|---|---|
|
||
| exact `/bitrix/sync/webhook/contact` | `bitrix-sync:8080` | public HTTPS Contact event; source IP CIDR/method/body/rate limits, query-token auth в upstream |
|
||
| exact `/bitrix/sync/webhook/alert` | `bitrix-sync:8080` | public HTTPS smart-process event; те же ограничения |
|
||
|
||
До full sync cutover оба exact webhook route закрыты либо возвращают retryable `503`; успешный `2xx ignored` запрещён.
|
||
|
||
Query не участвует в exact location matching: URL штатного робота `/bitrix/sync/webhook/<type>?token=...&ID=...` попадает в соответствующий exact route.
|
||
|
||
`/internal/`, `/_internal/`, Redis/OTLP/admin/status/config files на public host → `404`. Fallback на ВМ1 или SPA запрещён. Прочие paths/methods → `404/405`.
|
||
|
||
### Private `8443`
|
||
|
||
| Path | Local upstream | Caller |
|
||
|---|---|---|
|
||
| `/internal/safety/v2/*` | `message-safety-api:8080` | api-backend ВМ1 |
|
||
| exact `/internal/safety/status` | `message-safety-api:8080/health/ready` | api-backend ВМ1, ops; capability snapshot, не correctness gate |
|
||
| `/internal/sync/v1/*` | `bitrix-sync:8080` | ops/allow-listed service |
|
||
|
||
Public и private server blocks не имеют общего fallback. Safety status alias доступен только на private listener; public `/health/ready` и `/internal/safety/status` не публикуются.
|
||
|
||
## 3. Webhook allow-list и preflight
|
||
|
||
До proxy nginx проверяет непосредственный source IP по version-controlled `BITRIX_WEBHOOK_ALLOWED_CIDRS`; пустой/невалидный список при enabled receiver блокирует deployment. Адрес из недоверенного `X-Forwarded-For` не используется.
|
||
|
||
`BITRIX_SYNC_ENABLED`, public route, readiness и allow-list согласуются одним
|
||
preflight: disabled требует `deny all;`, enabled — reviewed non-empty CIDR и
|
||
ready receiver. Обратные комбинации блокируют deployment.
|
||
|
||
Запрос вне allow-list получает generic `403` без proxy. В безопасном журнале с ограниченным retention сохраняются только timestamp, source IP, route class и outcome; query/body не сохраняются. Telemetry pipeline экспортирует `webhook_rejected_total{receiver,reason="source_ip"}` без IP label. Allow-list не расширяется автоматически: всплеск Contact, восстановленных инкрементальной reconciliation, инициирует проверку rejected-IP журнала, подтверждение принадлежности адреса Битрикс24 и reviewed reload конфигурации.
|
||
|
||
Bitrix webhook retries имеют отдельный достаточный burst, проходят source IP allow-list и проверяют query receiver token в сервисе.
|
||
|
||
## 4. Private `8443` fail-closed
|
||
|
||
До утверждённого Safety cutover active caller allow-list содержит только `deny all;`; после cutover он совпадает с SG/host-firewall источниками ВМ1. Расхождение любого из трёх слоёв (nginx allow-list, SG, host firewall) блокирует rollout.
|
||
|
||
Private listener доверяет forwarded headers только от allow-listed private caller.
|
||
|
||
## 5. Listeners и TLS
|
||
|
||
- `:80` — только ACME challenge и `308 https://$host$request_uri`;
|
||
- исключение: `/bitrix/sync/webhook/contact|alert` на HTTP возвращают generic `404/426` **без redirect и отражения query token**;
|
||
- `:443` — только ACME-совместимый TLS и exact CRM webhook;
|
||
- private `:8443` — internal CA, SAN совпадает с private DNS именем ВМ2;
|
||
- public и private сертификаты разные; public key недоступен приложению.
|
||
|
||
## 6. Timeouts и body limits ВМ2
|
||
|
||
CRM webhook: connect/send/read `3s / 30s / 60s` (arch-08). Private Safety не короче caller budget. JSON body webhook ограничен; file bytes через этот nginx не идут. Cache на webhook выключен.
|
||
|
||
## 7. Edge rate limits ВМ2
|
||
|
||
Отдельные зоны для двух exact webhook (мягкий burst под retries Битрикс24) и `limit_conn`. Зоны guest API/auth/WS/SPA/SMS на ВМ2 не создаются.
|
||
|
||
Ответ превышения — `429`, `Retry-After`, request id. Generic `403` для wrong source IP — до proxy, не `429`.
|
||
|
||
## 8. Security headers
|
||
|
||
Public webhook: не кэшировать, не ослаблять CSP ради SPA (SPA нет). `Server` / `X-Powered-By` скрыты (arch-08). CORS wildcard с credentials запрещён; webhook не требует browser CORS.
|
||
|
||
## 9. Health и synthetic ВМ2
|
||
|
||
Внутренний `/nginx-health/live` — arch-08 §8. Synthetic отдельно: HTTP redirect/ACME policy, internal 404 на public host, GET webhook `405/404`, valid отдельный cert, POST webhook allowed/denied source IP без помещения query token в shell history или логи. Private `8443` проверяется с VM1/ops host, не из интернета.
|
||
|
||
## 10. Layout и Compose ВМ2
|
||
|
||
Каркас arch-08 §10 плюс:
|
||
|
||
- отдельный template/server block private `8443`;
|
||
- snippet/allow-list `BITRIX_WEBHOOK_ALLOWED_CIDRS`;
|
||
- без `websocket.conf` и без `frontend-static`.
|
||
|
||
Public ports: `${NGINX_HTTP_PORT}:80`, `${NGINX_HTTPS_PORT}:443`. Private `8443` публикуется только в сеть/SG, разрешённую ВМ1 и ops — не как internet listener. Детали портов/SG — arch-03 / arch-06 / [`arch-10-deployment.md`](../../architectory/arch-10-deployment.md).
|
||
|
||
## 11. Failure behavior ВМ2
|
||
|
||
Дополнительно к arch-08 §12:
|
||
|
||
- rollback sync: закрыть public webhook routes либо вернуть retryable `503`; возврат к фиктивному `202 ignored` запрещён;
|
||
- ВМ1 при этом не изменяется;
|
||
- Safety slow на private `8443`: не маскировать ошибку `2xx`; caller ВМ1 держит poll budget.
|
||
|
||
## 12. Валидация и тесты ВМ2
|
||
|
||
Автоматические тесты:
|
||
|
||
- CRM webhook exact routes принимают query без изменения location matching;
|
||
- allowed source IP проксируется, wrong IP получает `403` до upstream;
|
||
- HTTP webhook URL с query token не перенаправляется на HTTPS и не отражает query в `Location`/error;
|
||
- source-IP rejects попадают в безопасный bounded-retention журнал и low-cardinality telemetry без query/body/IP label;
|
||
- disabled/`deny all` и enabled/ready/CIDR preflight: обратные комбинации блокируют deployment;
|
||
- public `/internal/safety/*` и `/internal/sync/*` → `404`;
|
||
- private exact `/internal/safety/status` возвращает capability readiness Safety, а соседние неразрешённые health paths → `404`;
|
||
- private `8443` до cutover `deny all`, после cutover только источники ВМ1;
|
||
- GET webhook `405/404`; прочие paths `404`;
|
||
- TLS scan public host и отдельная проверка internal CA на `8443`;
|
||
- ACME/redirect rehearsal без остановки приёма (кроме контролируемого окна);
|
||
- logs/traces не содержат query token, form body, Authorization.
|
||
|
||
Acceptance не использует public host ВМ1 и не требует running nginx ВМ1.
|
||
|
||
## 13. Definition of Done ВМ2
|
||
|
||
Дополнительно к arch-08 §13:
|
||
|
||
- независимые public `80/443` и private `8443`;
|
||
- routing matrix §2 покрыта;
|
||
- CRM webhook достигает ВМ2 напрямую и продолжает приниматься при остановленном nginx ВМ1;
|
||
- CRM webhook ограничен version-controlled source IP CIDR allow-list; query token и form body отсутствуют в access/error logs и traces;
|
||
- preflight `BITRIX_SYNC_ENABLED` согласован с route/allow-list/readiness;
|
||
- private Safety не опубликован на public host.
|
||
|
||
## 14. TBD ВМ2
|
||
|
||
- N1: доверенные WAF/LB CIDR перед public host ВМ2, если появятся; до этого allow-list — непосредственный source IP.
|
||
- N3: нужен ли публичный health на processing host.
|
||
- N6: финальный burst webhook зон.
|
||
|
||
## 15. Ссылки
|
||
|
||
- Контракт: [`arch-08-nginx.md`](../../architectory/arch-08-nginx.md).
|
||
- ВМ1: [`module-03-nginx-vm1.md`](../../VM1_app/documentation/module-03-nginx-vm1.md).
|
||
- Указатель: [`module-03-nginx.md`](module-03-nginx.md).
|
||
- Safety / sync / observability: [`module-05-message-safety.md`](module-05-message-safety.md), [`module-07-bitrix-sync.md`](module-07-bitrix-sync.md), [`module-09-observability-vm2.md`](module-09-observability-vm2.md).
|
||
- Деплой: [`module-10-deployment-vm2.md`](module-10-deployment-vm2.md).
|