docs: rewrite all documentation in Russian + add deployment guide

- docs/protocol.md, pki.md, split-tunnel.md, sing-box.md переведены на русский
  и сверены с текущим кодом (транспорт v2: свой UDP + TCP/443 + QUIC fallback,
  handover; PKI; split-tunnel; sing-box-план).
- docs/deployment.md (новый, 369 строк): пошаговое руководство для удалённого
  сервера — сборка, PKI init/issue-server/issue-client (проверено бинарём),
  server.toml/client.toml на основе фактических config/*.example, firewall +
  NAT/IP-форвардинг, sudo-запуск, бандл клиента (ca.crt + client.crt + client.key
  + server addr/sni), на каком транспорте идёт трафик, ограничения v1.
- README.md (новый, корень): краткий обзор + таблица крейтов + быстрый старт.

Всё на русском (проза); команды/идентификаторы/конфиги — как есть.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
xah30
2026-05-26 10:42:08 +03:00
parent d5b9a8611d
commit 083c441e4c
6 changed files with 1075 additions and 515 deletions
+115 -114
View File
@@ -1,20 +1,20 @@
# Aura PKI
# PKI Aura
Aura uses a small, self-contained X.509 PKI for **mutual authentication** of the inner
handshake. A single self-signed Aura **CA** issues one **server** certificate and one
**client** certificate per client. During the handshake the client verifies the server's
certificate and the server verifies the client's certificate, both against the CA.
Aura использует небольшую самодостаточную X.509-PKI для **взаимной аутентификации** во внутреннем
рукопожатии. Один самоподписанный **CA** Aura выдаёт один сертификат для **сервера** и по одному
сертификату для каждого **клиента**. Во время рукопожатия клиент проверяет сертификат сервера, а
сервер — сертификат клиента, и в обе стороны проверка идёт против этого CA.
The PKI is implemented in the `aura-pki` crate (`ca.rs`, `cert.rs`, `store.rs`) and exposed on
the command line as `aura pki ...` (`crates/aura-cli/src/pki.rs`,
`crates/aura-cli/src/main.rs`).
PKI реализована в крейте `aura-pki` (`ca.rs`, `cert.rs`, `store.rs`) и доступна в командной строке
как `aura pki ...` (`crates/aura-cli/src/pki.rs`, `crates/aura-cli/src/main.rs`).
> The outer QUIC/TLS layer does **not** use this PKI — it accepts any certificate (see
> `protocol.md`, "Mimicry layer"). All certificate trust lives in the inner Aura handshake.
> Внешний QUIC/TLS-слой эту PKI **не** использует — он принимает любой сертификат (см.
> `protocol.md`, раздел про слой мимикрии). Всё доверие сертификатам сосредоточено во внутреннем
> рукопожатии Aura.
---
## Trust model
## Модель доверия
```
Aura CA (self-signed)
@@ -24,55 +24,54 @@ the command line as `aura pki ...` (`crates/aura-cli/src/pki.rs`,
| |
server leaf client leaf(s)
CN = <domain> CN = <client_id>
SAN: DNS:<domain> (no SAN)
SAN: DNS:<domain> (нет SAN)
EKU: serverAuth EKU: clientAuth
```
- The **CA** is self-signed with `BasicConstraints: CA`, and key usages
`keyCertSign` + `crlSign` + `digitalSignature`. Default lifetime **3650 days**.
- A **server leaf** carries `CN = <domain>`, a **`DNS:<domain>` SAN**, and
`extendedKeyUsage = serverAuth`. The DNS SAN is what the client matches against its expected
`server_name`.
- A **client leaf** carries `CN = <client_id>` and `extendedKeyUsage = clientAuth`. The CN is
the identity the server learns and records as the session `peer_id`.
- Leaf key usages are `digitalSignature` + `keyEncipherment`. Default lifetime **365 days**.
- All issued certs (CA and leaves) backdate `not_before` by **5 minutes** to tolerate clock
skew.
- **CA** самоподписан, имеет `BasicConstraints: CA` (unconstrained) и `keyUsage`:
`keyCertSign` + `crlSign` + `digitalSignature`. Срок действия по умолчанию — **3650 дней**.
- **Server leaf** несёт `CN = <domain>`, **`DNS:<domain>` SAN** и
`extendedKeyUsage = serverAuth`. Именно DNS-SAN сравнивается клиентом с ожидаемым `server_name`.
- **Client leaf** несёт `CN = <client_id>` и `extendedKeyUsage = clientAuth`. Этот CN — та
идентичность, которую увидит сервер и запишет как `peer_id` сессии.
- `keyUsage` для листовых сертификатов: `digitalSignature` + `keyEncipherment`. Срок действия по
умолчанию — **365 дней**.
- У всех выпускаемых сертификатов (и у CA, и у листовых) `not_before` смещён назад на **5 минут**,
чтобы выдерживать небольшой расхождение часов.
### Algorithms
### Алгоритмы
All keys are **ECDSA P-256 / SHA-256** (rcgen's default `KeyPair::generate`). Private keys are
written in **PKCS#8 PEM**. Chain verification (in `cert.rs`) accepts ECDSA P-256/SHA-256
(required), and also ECDSA P-384/SHA-384 and Ed25519, so a deployment can switch key types
later without code changes.
Все ключи — **ECDSA P-256 / SHA-256** (`KeyPair::generate` rcgen по умолчанию). Приватные ключи
сохраняются в **PKCS#8 PEM**. Проверка цепочки (`cert.rs`) принимает ECDSA P-256/SHA-256
(обязательно), а также ECDSA P-384/SHA-384 и Ed25519, — так что развёртывание сможет позже сменить
тип ключа без изменения кода.
---
## File layout
## Раскладка файлов
The CLI keeps files in plain directories. Conventional names
(`crates/aura-cli/src/pki.rs`):
CLI хранит файлы в обычных директориях. Стандартные имена (`crates/aura-cli/src/pki.rs`):
| File | Constant | Contents |
|---------------|------------|-------------------------------------------|
| `ca.crt` | `CA_CERT` | CA certificate (PEM) |
| `ca.key` | `CA_KEY` | CA private key (PKCS#8 PEM) — **secret** |
| `server.crt` | | Server leaf certificate (PEM) |
| `server.key` | | Server leaf private key (PEM) — **secret**|
| `client.crt` | | Client leaf certificate (PEM) |
| `client.key` | | Client leaf private key (PEM) — **secret**|
| `revoked.crl` | `CRL_FILE` | Revocation list (one identifier per line) |
| Файл | Константа | Содержимое |
|---------------|------------|--------------------------------------------------|
| `ca.crt` | `CA_CERT` | Сертификат CA (PEM) |
| `ca.key` | `CA_KEY` | Приватный ключ CA (PKCS#8 PEM) — **секрет** |
| `server.crt` | | Листовой сертификат сервера (PEM) |
| `server.key` | | Приватный ключ сервера (PEM) — **секрет** |
| `client.crt` | | Листовой сертификат клиента (PEM) |
| `client.key` | | Приватный ключ клиента (PEM) — **секрет** |
| `revoked.crl` | `CRL_FILE` | Список отозванных идентификаторов (по одному в строке) |
`issue-server` and `issue-client` load the CA from `ca.crt` + `ca.key` in the CA directory and
write `server.{crt,key}` / `client.{crt,key}` into the output directory. Paths beginning with
`~` are expanded to the home directory (from `$HOME`, or `$USERPROFILE` on Windows).
Команды `issue-server` и `issue-client` загружают CA из `ca.crt` + `ca.key` в директории CA и
записывают `server.{crt,key}` / `client.{crt,key}` в выходную директорию. Пути, начинающиеся с
`~`, раскрываются в домашнюю директорию (из `$HOME`, либо `$USERPROFILE` на Windows).
These names map directly onto the `[pki]` section of `server.toml` / `client.toml`
Эти имена напрямую соответствуют секции `[pki]` в `server.toml` / `client.toml`
(`ca_cert`, `cert`, `key`).
---
## `aura pki` commands
## Команды `aura pki`
```
aura pki init --ca-name <CN> --out <DIR>
@@ -82,14 +81,14 @@ aura pki revoke --id <ID> [--crl <PATH>]
aura pki list [--crl <PATH>]
```
For `issue-server` / `issue-client`, `--ca` defaults to the value of `--out` (so the CA and
the issued leaf can live in the same directory). For `revoke` / `list`, `--crl` defaults to
`./revoked.crl`.
Для `issue-server` / `issue-client` параметр `--ca` по умолчанию равен значению `--out` (так что CA
и выпущенный лист могут лежать в одной директории). Для `revoke` / `list` параметр `--crl` по
умолчанию равен `./revoked.crl`.
### `init` — create a CA
### `init` — создать CA
Generates a fresh self-signed CA and writes `ca.crt` + `ca.key` into `--out` (creating the
directory if needed).
Генерирует свежий самоподписанный CA и записывает `ca.crt` + `ca.key` в `--out` (директория
создаётся при необходимости).
```bash
aura pki init --ca-name "Aura Root CA" --out ~/.aura
@@ -98,10 +97,10 @@ aura pki init --ca-name "Aura Root CA" --out ~/.aura
# key: ~/.aura/ca.key
```
### `issue-server` — issue a server certificate
### `issue-server` — выпустить сертификат сервера
Issues a server leaf for a DNS name, signed by the CA, with a `DNS:<domain>` SAN and
`serverAuth` EKU.
Выпускает листовой сертификат для DNS-имени, подписанный CA, с SAN `DNS:<domain>` и EKU
`serverAuth`.
```bash
aura pki issue-server --domain vpn.example.com --out ~/.aura --ca ~/.aura
@@ -110,14 +109,14 @@ aura pki issue-server --domain vpn.example.com --out ~/.aura --ca ~/.aura
# key: ~/.aura/server.key
```
> The `--domain` must equal the name the client expects in the handshake. In the shipped
> client config that name is taken from `[client] sni`, so the camouflage SNI and the
> verified server SAN are the same value.
> Значение `--domain` должно совпадать с тем именем, которое клиент ожидает в рукопожатии. В
> поставляемой конфигурации клиента это имя берётся из `[client] sni`, поэтому SNI камуфляжа и
> проверяемый SAN сервера — это одно и то же значение.
### `issue-client` — issue a client certificate
### `issue-client` — выпустить сертификат клиента
Issues a client leaf with `CN = <id>` and `clientAuth` EKU. The `<id>` becomes the verified
`peer_id` the server sees.
Выпускает листовой сертификат с `CN = <id>` и EKU `clientAuth`. Это `<id>` станет проверенным
`peer_id`, который увидит сервер.
```bash
aura pki issue-client --id laptop --out ~/.aura --ca ~/.aura
@@ -126,19 +125,20 @@ aura pki issue-client --id laptop --out ~/.aura --ca ~/.aura
# key: ~/.aura/client.key
```
### `revoke` — add to the revocation list
### `revoke` — добавить в список отзыва
Adds an identifier — a **client id / Common Name** or a **certificate serial** (lowercase
hex, no separators) — to the CRL file, creating it (and parent directories) if absent.
Добавляет идентификатор — это либо **client id / Common Name**, либо **серийный номер
сертификата** (строчные шестнадцатеричные цифры без разделителей) — в CRL-файл, создавая его (и
родительские директории) при отсутствии.
```bash
aura pki revoke --id laptop --crl ~/.aura/revoked.crl
# revoked 'laptop' (CRL: ~/.aura/revoked.crl)
```
### `list` — show revoked identifiers
### `list` — показать отозванные идентификаторы
Prints the identifiers in the CRL file (empty if the file does not exist).
Печатает идентификаторы из CRL-файла (пусто, если файла нет).
```bash
aura pki list --crl ~/.aura/revoked.crl
@@ -146,87 +146,88 @@ aura pki list --crl ~/.aura/revoked.crl
# laptop
```
### End-to-end example
### Полный пример
```bash
# 1. Create the CA.
# 1. Создать CA.
aura pki init --ca-name "Aura Root CA" --out ~/.aura
# 2. Issue the server cert for its public DNS name.
# 2. Выпустить серверный сертификат для публичного DNS-имени.
aura pki issue-server --domain vpn.example.com --out ~/.aura
# 3. Issue a client cert per device.
# 3. Выпустить клиентский сертификат — по одному на устройство.
aura pki issue-client --id laptop --out ~/.aura
# 4. (later) Revoke a compromised client.
# 4. (позже) Отозвать скомпрометированный клиент.
aura pki revoke --id laptop
```
---
## Verification
## Проверка
Verification is performed by `AuraCertVerifier` (`crates/aura-pki/src/cert.rs`), built from
the CA certificate PEM. It uses **`rustls-webpki`** to validate the peer's leaf against the CA
trust anchor. The Aura handshake invokes it on each side (see `protocol.md`).
Проверку выполняет `AuraCertVerifier` (`crates/aura-pki/src/cert.rs`), собранный из PEM-сертификата
CA. Внутри он использует **`rustls-webpki`** для валидации листового сертификата пира против CA как
trust anchor. Рукопожатие Aura вызывает его с обеих сторон (см. `protocol.md`).
**Server certificate** (`verify_server_cert`), run by the client:
**Сертификат сервера** (`verify_server_cert`), запускает клиент:
1. webpki chain verification against the CA with key usage **`serverAuth`**, plus validity
(time) check.
2. The leaf must be valid for the requested `server_name` (DNS SAN match); a mismatch is
1. webpki-валидация цепочки против CA с key usage **`serverAuth`** плюс проверка срока действия
(времени).
2. Лист должен быть валиден для запрошенного `server_name` (совпадение DNS-SAN); расхождение —
`NameMismatch`.
3. CRL check (see below).
3. Проверка по CRL (см. ниже).
**Client certificate** (`verify_client_cert`), run by the server:
**Сертификат клиента** (`verify_client_cert`), запускает сервер:
1. webpki chain verification against the CA with key usage **`clientAuth`**, plus validity.
2. The **client id** is extracted as the first Common Name from the leaf subject (missing CN
is `MissingIdentity`).
3. CRL check.
4. Returns the client id, which the handshake records as the session `peer_id`.
1. webpki-валидация цепочки против CA с key usage **`clientAuth`** плюс проверка срока действия.
2. **client id** извлекается как первый Common Name из subject листа (отсутствие CN
`MissingIdentity`).
3. Проверка по CRL.
4. Возвращает client id, который рукопожатие фиксирует как `peer_id` сессии.
The leaf certificate is sent **inline** in the handshake (DER, no intermediate chain); the CA
is the single trust anchor. Possession of the leaf's private key is proven separately by the
handshake signature over the transcript (see `protocol.md`).
Листовой сертификат передаётся **inline** в рукопожатии (DER, без промежуточной цепочки); CA — это
единственный trust anchor. Владение приватным ключом листового сертификата доказывается отдельно
подписью рукопожатия по транскрипту (см. `protocol.md`).
Errors surface as `PkiError`: `CertParse`, `EmptyChain`, `TrustAnchor`, `Verification`,
Ошибки сообщаются как `PkiError`: `CertParse`, `EmptyChain`, `TrustAnchor`, `Verification`,
`NameMismatch`, `MissingIdentity`, `Revoked`.
---
## Revocation (CRL)
## Отзыв (CRL)
Aura v1 revocation is deliberately minimal (`crates/aura-pki/src/store.rs`). `CrlStore` is a
**set of revoked identifier strings**, where an identifier is either:
Механизм отзыва в Aura v1 намеренно минимальный (`crates/aura-pki/src/store.rs`). `CrlStore` — это
**множество строк-идентификаторов отозванных сертификатов**, где идентификатор — это либо:
- a certificate **serial number** (lowercase hex, no separators), or
- a **client id / Common Name**.
- **серийный номер** сертификата (строчные hex-цифры без разделителей), либо
- **client id / Common Name**.
During verification, if the CRL is non-empty the leaf is rejected (`Revoked`) when **either**
its serial **or** its Common Name is present in the set. An empty CRL skips the check
entirely.
При проверке, если CRL непуст, листовой сертификат отвергается (`Revoked`), когда **либо** его
серийный номер, **либо** его Common Name присутствует в множестве. Пустой CRL пропускает проверку
полностью.
The on-disk format is one identifier per line; blank lines and `#` comments are ignored on
load. `aura pki revoke` / `aura pki list` manage this file.
Формат на диске — один идентификатор в строке; пустые строки и комментарии `#` игнорируются при
загрузке. Файл управляется командами `aura pki revoke` / `aura pki list`.
> v1 limitation: this is a flat allow/deny set, not a signed X.509 CRL. There is no CRL
> signature, no `nextUpdate`, and no automatic distribution — the file must be provisioned to
> the verifying side out of band. The verifier passes `None` for webpki's own revocation
> hooks and relies solely on this set.
> Ограничение v1: это плоское множество разрешения/запрета, а не подписанный X.509 CRL. Нет
> подписи CRL, нет `nextUpdate` и нет автоматического распространения — файл нужно доставить на
> проверяющую сторону вне протокола. Верификатор передаёт `None` в собственные крючки отзыва
> webpki и полагается исключительно на это множество.
---
## Security notes
## Замечания по безопасности
- **Protect the private keys.** `ca.key` is the root of all trust; anyone with it can mint
valid server/client certs. `server.key` / `client.key` must stay on their respective hosts.
The CLI writes them with default file permissions — restrict them at the OS level.
- **The CA is self-signed and unconstrained** (`BasicConstraints: CA` unconstrained). It is
the sole trust anchor; there is no intermediate CA tier in v1.
- **Server identity is name-bound.** The client only accepts a server leaf whose DNS SAN
matches the expected name, so a different valid leaf from the same CA will not be accepted
for the wrong host.
- **Revocation is best-effort** (see above): plan to distribute the CRL file and keep it in
sync on every server that verifies clients.
- **Leaf lifetime is 365 days**; plan re-issuance. There is no automated rotation in v1.
- **Защищайте приватные ключи.** `ca.key` — корень всего доверия; владея им, можно выпускать
любые валидные серверные/клиентские сертификаты. `server.key` / `client.key` должны оставаться
на своих хостах. CLI пишет их с дефолтными правами файловой системы — ограничивайте доступ
средствами ОС.
- **CA самоподписан и не ограничен** (`BasicConstraints: CA` unconstrained). Это единственный
trust anchor; в v1 нет уровня промежуточных CA.
- **Идентичность сервера связана с именем.** Клиент принимает только тот серверный лист, чей
DNS-SAN совпадает с ожидаемым именем, поэтому другой валидный лист от того же CA не будет
принят для чужого хоста.
- **Отзыв — best-effort** (см. выше): планируйте раздачу CRL-файла и поддерживайте его в актуальном
состоянии на каждом сервере, который проверяет клиентов.
- **Срок жизни листов — 365 дней**; планируйте перевыпуск. Автоматической ротации в v1 нет.