feat(cli,pki): v3.3 bridge discovery via signed CA manifest
Closes the v3.3 "bridges by hand" honest limitation. Admins now publish a
CA-signed manifest with the current bridge list; clients re-read it from
disk on a timer and merge it with the static [client] bridges. Cuts the
"rotate the bridge list" cycle from "edit every client config" to
"distribute one signed file".
- New aura sign-bridges CLI:
aura sign-bridges --ca /etc/aura/pki \
--bridges "ip1:443,ip2:443" \
--ttl-days 7 \
--out /var/aura/bridges.signed
- Manifest format (single file, text + signature block, same shape as the
in-band CRL):
AURA-BRIDGES-v1
{"version":1,"generated_at":...,"expires_at":...,"bridges":[...]}
--SIGNATURE--
<hex ECDSA-P256/SHA-256 over body>
- aura-pki now exports `sign_ecdsa_p256` / `verify_ecdsa_p256` so CRL and
bridges share ONE signing primitive (no copy-paste). CRL keeps working.
- aura-cli::bridges::BridgeManifest + BridgesDiscoveryWatcher: new
module. encode_signed/load_signed_verified verifies signature + rejects
expired manifests. Watcher spawns a tokio interval that re-reads the
file; on load failure (truncated, expired, bad sig) the previous
snapshot is kept — bridges never collapse to empty.
- New [client.bridges_discovery] {enabled, manifest_path,
refresh_interval_secs}; serde(default) so v3.2 configs keep working.
- Merge strategy: manifest EXTENDS static [client] bridges, dedup by
SocketAddr, static-first ordering. Static remains as fallback.
- 13 new tests (8 lib unit + 4 integration + 1 config). Workspace: 310
tests passed (+13), clippy -D warnings clean, fmt clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+24
-7
@@ -437,6 +437,17 @@ aura status
|
||||
`Session` (поле `_adapter` в `AuraTun` держит адаптер живым на всё время сессии).
|
||||
- ✓ **Cross-compile.** Весь workspace проверен под `cargo check --target
|
||||
x86_64-pc-windows-gnu` без warnings.
|
||||
- ✓ **Bridge-discovery через подписанный CA-манифест (v3.3).**
|
||||
`[client.bridges_discovery] enabled = true` плюс файл `bridges.signed` на диске. Админ
|
||||
собирает манифест командой
|
||||
`aura sign-bridges --ca /etc/aura/pki --bridges "203.0.113.10:443,198.51.100.20:443" --ttl-days 7 --out /etc/aura/bridges.signed`
|
||||
(подпись ECDSA-P256/SHA-256 ключом CA — той же примитивой что in-band CRL). Клиент верифицирует
|
||||
подпись против `[pki] ca_cert`, отвергает истёкшие манифесты (`expires_at < now`), и **расширяет**
|
||||
статический список из `[client] bridges` (дубликаты по `SocketAddr` удаляются; статика остаётся
|
||||
fallback'ом если файл повреждён / отсутствует). Фон-таск перечитывает файл каждые
|
||||
`refresh_interval_secs` секунд (default 3600), горячее обновление без рестарта клиента. Сам HTTP-
|
||||
пуш через CDN — план v3.4 (опциональная зависимость `reqwest` под feature gate). См.
|
||||
`crates/aura-cli/src/bridges.rs` и интеграционный тест `tests/bridges_discovery.rs`.
|
||||
|
||||
### Остающиеся честные ограничения
|
||||
|
||||
@@ -450,9 +461,12 @@ aura status
|
||||
- **Нативного Go-клиента для телефона нет** — через sing-box (Option B нативный Go-outbound,
|
||||
по `protocol.md` + KAT из Rust, см. [`sing-box.md`](sing-box.md)). Сейчас доступен только
|
||||
десктоп-клиент / process-bridge. Это явно исключённый из v2 пункт.
|
||||
- **Bridge-discovery без хардкода IP в конфиге** — план v3.3. Сейчас `[client] bridges`
|
||||
хардкодит список запасных IP; если их все заблокируют (включая российские entry-узлы из
|
||||
сценария §7), восстановление требует обновления конфига клиента вручную.
|
||||
- **Bridge-discovery через push без рестарта клиента** — частично реализовано в v3.3:
|
||||
подписанный CA-манифест на диске (`[client.bridges_discovery]`) горячо перечитывается фон-
|
||||
таском; админ переподписывает файл и рассылает любым каналом (rsync/ansible/scp). HTTP-fetch
|
||||
напрямую с CDN — план v3.4. Если все статически-перечисленные IP заблокированы и манифест не
|
||||
обновлён до экспирации, восстановление требует доставки нового `bridges.signed` через
|
||||
out-of-band канал.
|
||||
|
||||
---
|
||||
|
||||
@@ -674,10 +688,13 @@ exit, и они не пересекаются (см. `aura provision-client --ci
|
||||
при заходе на запрещённый ресурс через VPN — вопрос юрисдикции exit-узла и применимого
|
||||
законодательства, не технический.
|
||||
- **Не защищает от блокировки самого entry-IP.** Если СОРМ-система или Роскомнадзор начнут
|
||||
активно блокировать конкретные VPS-IP, придётся ротировать IP / bridges. Сейчас это решается
|
||||
через `[client] bridges = [...]` — список запасных российских entry-узлов; клиент пробует их
|
||||
в случайном порядке при отказе primary. Полноценный bridge-discovery (без хардкода IP в
|
||||
конфиге) — план v3.3.
|
||||
активно блокировать конкретные VPS-IP, придётся ротировать IP / bridges. v3.3 решает это в две
|
||||
ступени: (а) `[client] bridges = [...]` — статический список запасных entry-узлов, клиент
|
||||
пробует их в случайном порядке при отказе primary; (б) `[client.bridges_discovery] enabled = true`
|
||||
— клиент горячо перечитывает CA-подписанный манифест `bridges.signed` на диске (см. v3.3
|
||||
раздел в §6 «Устранено в v2/v3»), так что админ ротирует список без рестарта клиентского
|
||||
процесса — достаточно переподписать файл и доставить новой копией (rsync / ansible / любой
|
||||
out-of-band канал). HTTP-fetch с CDN — план v3.4.
|
||||
- **Cell padding не скрывает наличие туннеля.** Constant-size cells устраняют per-packet
|
||||
size-fingerprinting внутри multi-hop, но не делают сам поток неотличимым от HTTPS — общий
|
||||
объём и временные паттерны остаются. Это компромисс между обфускацией и накладными расходами.
|
||||
|
||||
Reference in New Issue
Block a user