145 lines
6.5 KiB
Markdown
145 lines
6.5 KiB
Markdown
# Incident response — VPN-сеть Montana
|
||
|
||
Версия: **2026-05-18**
|
||
|
||
## Severity матрица
|
||
|
||
| Sev | Симптом | Reaction time |
|
||
|---|---|---|
|
||
| **S1** | ВСЕ узлы в pool недоступны (нет VPN ни у кого) | < 15 минут |
|
||
| **S2** | Один из узлов недоступен > 5 минут после автоматического prune не отрабатывает | < 30 минут |
|
||
| **S3** | Утечка любого секрета подтверждена | < 1 час, по ротации |
|
||
| **S4** | DPI начал блокировать наш Reality в одной стране | < 4 часа, переключение SNI |
|
||
| **S5** | Падение orchestrator | < 1 час (multi-A продолжает работать) |
|
||
|
||
## Playbook
|
||
|
||
### S1: вся сеть лежит
|
||
|
||
```
|
||
# 1. Проверить multi-A:
|
||
dig @1.1.1.1 cdn.montana.quest A
|
||
# если пусто или мало → CF API упал, либо watchdog ошибся и удалил всё
|
||
|
||
# 2. Прямой probe каждого узла:
|
||
for n in 91.132.142.42 89.19.208.158 86.104.72.12; do
|
||
echo "$n: $(timeout 4 openssl s_client -connect $n:443 -servername www.googletagmanager.com -tls1_3 </dev/null 2>&1 | grep -c 'Verification: OK')"
|
||
done
|
||
|
||
# 3. Если узлы живы, а pool пуст — force re-register:
|
||
TOKEN=$(security find-generic-password -s montana-orchestrator-admin -a token -w)
|
||
for spec in "91.132.142.42|helsinki|FI" "89.19.208.158|frankfurt|DE" "86.104.72.12|newyork|US"; do
|
||
ip=$(echo $spec|cut -d'|' -f1); alias=$(echo $spec|cut -d'|' -f2); c=$(echo $spec|cut -d'|' -f3)
|
||
curl -sX POST -H 'Content-Type: application/json' \
|
||
https://montana.quest/vpn/node/register \
|
||
--data "{\"ip\":\"$ip\",\"alias\":\"$alias\",\"country\":\"$c\",\"hosting\":\"x\",\"label\":\"$alias\",\"coords\":[0,0],\"secret\":\"$TOKEN\"}"
|
||
done
|
||
|
||
# 4. Если узлы тоже мертвы — каскад инфраструктурного фейла:
|
||
# a) Проверить статус хостинга (Timeweb dashboard / THE.Hosting)
|
||
# b) Если хостинг ОК — SSH к узлу, проверить xray
|
||
ssh montana-finland 'systemctl status xray && tail -50 /var/log/xray/error.log'
|
||
```
|
||
|
||
### S2: один узел мёртв > 5 мин, не выпал
|
||
|
||
```
|
||
# 1. Проверить watchdog работает:
|
||
ssh montana-moscow 'cat /var/lib/montana-orchestrator/pool-health.json | jq'
|
||
|
||
# 2. Проверить probe от Moscow к узлу:
|
||
ssh montana-moscow 'python3 -c "import ssl,socket;
|
||
ctx=ssl.create_default_context()
|
||
s=socket.create_connection((\"<dead-ip>\",443),timeout=5)
|
||
ws=ctx.wrap_socket(s,server_hostname=\"www.googletagmanager.com\")
|
||
print(ws.getpeercert())"'
|
||
|
||
# Если timeout — но узел живой → проверить ufw/CrowdSec на узле
|
||
ssh <dead-node> 'cscli decisions list 2>/dev/null | grep 176.124.208.93'
|
||
|
||
# 3. Если watchdog не работает — restart orchestrator:
|
||
ssh montana-moscow 'systemctl restart montana-orchestrator'
|
||
|
||
# 4. Ручное удаление IP:
|
||
TOKEN=$(security find-generic-password -s montana-orchestrator-admin -a token -w)
|
||
curl -X POST -H 'Content-Type: application/json' \
|
||
https://montana.quest/vpn/node/deregister \
|
||
--data "{\"ip\":\"<dead-ip>\",\"secret\":\"$TOKEN\"}"
|
||
```
|
||
|
||
### S3: утечка секрета
|
||
|
||
#### S3a: утечка Reality privateKey
|
||
|
||
1. Ввести **ускоренную ротацию** (см. OPERATIONS.md → "Ротация ключей Reality").
|
||
2. Уведомить пользователей через канал коммуникации (Telegram, sitemontana.quest баннер).
|
||
3. Заблокировать старый pbk (xray на узле не примет старый клиент после смены privateKey).
|
||
|
||
#### S3b: утечка admin TOKEN
|
||
|
||
```
|
||
# 1. Сгенерировать новый:
|
||
NEW=$(openssl rand -hex 32)
|
||
# 2. Положить на Moscow:
|
||
ssh montana-moscow "install -m 600 /dev/stdin /etc/montana/orchestrator-admin-token <<<'$NEW'"
|
||
ssh montana-moscow 'systemctl restart montana-orchestrator'
|
||
# 3. Обновить Keychain:
|
||
security add-generic-password -s montana-orchestrator-admin -a token -w "$NEW" -U
|
||
```
|
||
|
||
#### S3c: утечка CF API token
|
||
|
||
1. Сразу revoke в Cloudflare dashboard.
|
||
2. Создать новый scoped token (Zone montana.quest, Permissions: Zone.DNS.Edit).
|
||
3. Обновить в Keychain `cloudflare-api-token` и в `/etc/montana/cf-api-token` на Moscow.
|
||
4. Restart orchestrator.
|
||
|
||
### S4: DPI блокировка в стране
|
||
|
||
```
|
||
# Временное решение: сменить SNI в realitySettings на другой популярный домен.
|
||
# Все узлы должны иметь тот же SNI (привязан к pbk).
|
||
|
||
for n in montana-finland montana-frankfurt montana-us; do
|
||
ssh $n "python3 -c \"
|
||
import json
|
||
p='/usr/local/etc/xray/config.json'
|
||
c=json.load(open(p))
|
||
ib=c['inbounds'][0]
|
||
ib['streamSettings']['realitySettings']['serverNames']=['www.gstatic.com']
|
||
ib['streamSettings']['realitySettings']['dest']='www.gstatic.com:443'
|
||
json.dump(c,open(p,'w'),indent=2)\" && systemctl restart xray"
|
||
done
|
||
|
||
# Обновить /vpn/sub: в URL sni=www.gstatic.com
|
||
ssh montana-moscow 'sed -i "s/www.googletagmanager.com/www.gstatic.com/g" <path-to-vpn-sub-source>'
|
||
```
|
||
|
||
### S5: orchestrator упал, не поднимается
|
||
|
||
```
|
||
ssh montana-moscow 'journalctl -u montana-orchestrator -n 200 --no-pager'
|
||
# Типичные причины:
|
||
# - синтакс ошибка в server.py → откатить из *.bak
|
||
ssh montana-moscow 'ls /opt/montana-orchestrator/server.py.bak-*'
|
||
# - /etc/montana/cf-api-token нечитаем → chmod 600 root:root
|
||
# - Flask недоступен → apt install python3-flask
|
||
|
||
# Существующие подключения клиентов НЕ затронуты до DNS TTL expire (120s).
|
||
# Если orch будет down > 30 минут — manual prune через CF API напрямую.
|
||
```
|
||
|
||
## Эскалация
|
||
|
||
| Уровень | Кто | Канал |
|
||
|---|---|---|
|
||
| L1 | Архитектор сети | efir369999@gmail.com |
|
||
| L2 | Cloudflare support (DNS issues) | https://dash.cloudflare.com → support |
|
||
| L3 | Хостинг провайдер | Timeweb / THE.Hosting dashboard |
|
||
|
||
## После инцидента
|
||
|
||
1. Записать в `OPEN-RISKS.md` если выявлен новый риск.
|
||
2. Если фикс уровня кода — соответствующее изменение в `Montana/Node/join.sh` или orchestrator.
|
||
3. Записать дату и причину в `AUDIT-READINESS.md → История проверки`.
|