montana/Node/External-Audit/ARCHITECTURE.md
2026-05-21 03:44:38 +03:00

6.1 KiB
Raw Blame History

Архитектура VPN-сети Montana

Версия: 2026-05-18

Поток подключения клиента

┌──────────────┐   1. DNS resolve cdn.montana.quest
│ iPhone Happ  │ ─────────────────────────────────────┐
└──────┬───────┘                                       │
       │                                               ▼
       │                              ┌──────────────────────────┐
       │                              │ Cloudflare DNS multi-A   │
       │                              │ TTL=120, не proxied      │
       │                              │ → FI 91.132.142.42       │
       │                              │ → FRA 89.19.208.158      │
       │                              │ → US 86.104.72.12        │
       │                              └────────┬─────────────────┘
       │                                       │
       │ 2. TLS handshake (Reality) ───────────┘
       │    SNI=www.googletagmanager.com
       │    pbk=EkTs2aGKnFNgFZ0f7wgft2sJp3VjwFQqIrwkZKM4gD8
       ▼
┌────────────────────────────────────────────────────┐
│ xray :443 на одном из узлов (любом — один keypair) │
│   vless + xtls-rprx-vision + reality               │
│   user=xray:xray, Restart=always, StartLimitBurst  │
│   outbound: freedom (direct internet)              │
└────────────────────────────────────────────────────┘

Поток управления (health watchdog)

┌────────────────────────────────────────────────┐
│ montana-orchestrator.service на Moscow         │
│ /opt/montana-orchestrator/server.py :5020      │
│                                                │
│  Flask:                                        │
│   POST /register   {ip, alias, …, secret}     │  ← admin
│   POST /deregister {ip, secret}               │  ← узел при shutdown
│   GET  /pool       — CF records + state       │  ← аудитор
│   GET  /health     — кол-во live              │  ← мониторинг
│                                                │
│  Background thread (каждые 30 сек):           │
│   for ip in registrypool:                    │
│     ok = tls_probe(ip:443, SNI)               │
│     if ok && success≥2 && not in_pool:        │
│       cf_api POST /dns_records                │
│     if !ok && fails≥2 && in_pool:             │
│       cf_api DELETE /dns_records/<id>         │
└────────────────────────────────────────────────┘
                       │
                       ▼
            Cloudflare API

Компоненты

Узел Хост Роль Сервисы
Helsinki 91.132.142.42 VPN-backend xray
Frankfurt 89.19.208.158 VPN-backend xray
New York 86.104.72.12 VPN-backend xray
Moscow 176.124.208.93 orchestrator + landing + p2p (НЕ VPN) nginx, montana-orchestrator, montana-node

Криптографические параметры

Параметр Значение Где
Reality protocol vless + xtls-rprx-vision inbound config
Server SNI / dest www.googletagmanager.com:443 realitySettings.dest
Universal UUID e6d355e2-2d79-4c96-a373-3b0e6b6f4b0d clients[0].id
Reality publicKey EkTs2aGKnFNgFZ0f7wgft2sJp3VjwFQqIrwkZKM4gD8 URL pbk=
Reality shortId 302805bc0c25e504 URL sid=
Reality privateKey (хранится только на узлах) /usr/local/etc/xray/config.json (600)

Сетевые потоки

От До Порт Назначение
Любой клиент VPN-узел 443/tcp Reality VPN
Moscow orchestrator VPN-узел 443/tcp watchdog TLS-probe
Moscow orchestrator api.cloudflare.com 443/tcp DNS API
Узел Любой destination 443/tcp etc. freedom outbound
Любой p2p-узел Любой узел 8444/tcp montana-node Bootstrap+VDF
Admin Moscow montana.quest/vpn/node/register 443/tcp POST с secret

Решения и обоснования

  • Universal keypair на всех backends — Reality требует, чтобы клиент знал publicKey сервера. Multi-A pool с разными keypair невозможен без подписки с несколькими vless://. Принято: один keypair с trade-off shared-secret (см. THREAT-MODEL.md T-2).
  • DNS multi-A вместо подписки с несколькими URL — даёт «один ключ распределяет» без логики на клиенте; iOS native resolver сам ротирует ANSWER.
  • TTL 120s — баланс между скоростью переключения при отказе и нагрузкой на DNS.
  • Watchdog interval 30s, threshold 2 — реакция за 60120 секунд при минимальной нагрузке на узлы (≈ 1 probe в минуту с одной точки).
  • orchestrator на Moscow, не на VPN-узле — изоляция управления от data-plane; падение orchestrator не роняет существующие подключения.
  • Moscow исключена из VPN pool — на :443 nginx (efir.org), :2053 — отдельный xray не для публики.