montana/Node/External-Audit/SINGLE-SOURCE-OF-TRUTH.md

138 lines
7.4 KiB
Markdown
Raw Normal View History

2026-05-21 03:44:38 +03:00
# Single Source of Truth — VPN-сеть Montana
Версия: **2026-05-19**
## Принцип
Вся канонически верифицируемая правда о состоянии VPN-сети живёт в **одном append-only signed event log**:
```
https://montana.quest/vpn/events.jsonl
```
Каждая строка — событие, индивидуально подписанное **ed25519**:
```jsonl
{"data":{...},"seq":N,"sig":"ed25519:...","ts":"2026-05-19T19:00:00Z","type":"node_register"}
```
**Свойства:**
- **Append-only:** запись только в конец, прошлые события не переписываются.
- **Подписанные:** каждое событие проверяется публичным ключом `d9a8bf07871d35c8e85f7de4a9b62896c330ba0987732468515c7bda8bb4adde`.
- **Монотонный seq:** счётчик никогда не убывает, гэпы запрещены.
- **Pure-function state:** state = replay(events).
## Типы событий
| type | data | когда |
|---|---|---|
| `node_register` | `{alias, ip, country, label}` | admin регистрирует узел через /vpn/node/register |
| `node_deregister` | `{alias, ip}` | узел остановлен (xray ExecStopPost) |
| `node_online` | `{alias, ip}` | orchestrator watchdog: probe OK после offline |
| `node_offline` | `{alias, ip}` | orchestrator watchdog: 2 probe fails подряд |
| `unique_user` | `{ip_hash}` | новый sha256(client_IP) в логе xray |
| `metric` | произвольное | периодические метрики (нагрузка, throughput) |
| `checkpoint` | `{seq_range, merkle}` | каждые 1000 событий (план) |
## Derived state
`https://montana.quest/vpn/state.json` — кешированный результат `build_state(events)`. Любой может перепостроить и сравнить.
```json
{
"head_seq": 1502,
"head_ts": "2026-05-19T19:25:30Z",
"built_at": "...",
"nodes": {
"helsinki": {"online": true, "ip": "91.132.142.42", "country": "FI", ...},
"frankfurt": {"online": true, ...},
"newyork": {"online": true, ...}
},
"unique_users": 957,
"unique_users_merkle": "...",
"pubkey_hex": "d9a8bf07...",
"event_log_url": "https://montana.quest/vpn/events.jsonl"
}
```
`state.json` rebuilds каждые 30 секунд через `montana-state-builder.timer` на Moscow.
## Что НЕ публикуется
- IP-адреса пользователей (это PII). В события `unique_user` идёт **только sha256 IP** — не обратимо без brute-force на 32-битное IPv4 пространство (~4 сек на rainbow tabe).
- Чтобы усложнить brute-force, в roadmap — добавить **secret salt** с публикацией с задержкой 7 дней.
## Архитектура emitters
```
┌─────────────────────────┐
│ /opt/montana-vpn-stats │
│ /event_log.py │
│ (sign + append) │
└────────────┬────────────┘
┌────────────────────────────┼────────────────────────────┐
│ │ │
orchestrator watchdog xray-stats collector admin /register
(online/offline transitions) (new unique IPs) (manual events)
│ │ │
└────────────────────────────▼────────────────────────────┘
/var/www/montana_quest/vpn/events.jsonl
montana-state-builder.timer (30s)
/var/www/montana_quest/vpn/state.json
сайт + /vpn/sub + /vpn/node/uptime (читают state.json)
```
## Гарантии
| Гарантия | Как доказывается |
|---|---|
| Число уникальных пользователей не подделано | каждое событие `unique_user` подписано; state.json содержит merkle root; replay воспроизводит число |
| Узел не «фейково онлайн» | переходы online↔offline — отдельные подписанные события с timestamp |
| История не переписана | append-only; seq монотонный без гэпов; любой имеет полный лог |
| Нельзя backdate | timestamp на каждом событии; запланировано daily anchoring через OpenTimestamps |
## Что НЕ гарантируется (пока)
- **Forced inclusion:** мы можем замедлить добавление события в лог. Защита: автоматический rebuild каждые 30 секунд.
- **Privatekey compromise:** если ключ утечёт, можно подделать события. Защита: privateKey 600 root на Moscow.
- **Tampering архивных событий:** теоретически root доступом на Moscow можно переписать `events.jsonl`. **Защита roadmap:** ежедневный snapshot хеша всего лога в Bitcoin через OpenTimestamps — нельзя backdate.
## Аудит
Любой может проверить single-source-of-truth:
```bash
bash Montana/Node/External-Audit/scripts/verify-state.sh
```
Этот скрипт:
1. Скачивает `events.jsonl` и `state.json`.
2. Проверяет ed25519-подпись каждого события.
3. Проверяет монотонность seq без гэпов.
4. Replay events до `head_seq` из state.json.
5. Сравнивает результат replay со state.json: `head_seq`, `unique_users`, `merkle root`, `nodes online/offline`.
Если хотя бы один тест провалится — мы лжём.
## Сейчас зелёные тесты
```
✓ все 1531 events подписаны валидно, seq непрерывен
✓ replay matches claimed state: head_seq=1502, nodes=3, unique_users=957
=== ВСЕ ПРОВЕРКИ ЗЕЛЁНЫЕ ===
```
## Roadmap
- **P1:** daily checkpoint в Bitcoin через OpenTimestamps. Дописать `transparency.md`.
- **P2:** мульти-эмиттер — каждый узел независимо подписывает свои события + threshold-signature (2 of 3). Устраняет single trust на Moscow privateKey.
- **P3:** GraphQL-like derivation API — клиенты запрашивают subset state через `?fields=...`.
- **P4:** Public mirror лога на IPFS/GitHub raw — анти-цензура.