Шифрование
Модель
Section titled “Модель”Чувствительные значения в БД шифруются envelope-паттерном: данные шифрует DEK (AES-256-GCM), сам DEK хранится в БД обёрнутым (wrapped) корневым ключом KMS-провайдера.
flowchart TB
KMS["KMS-провайдер<br/>(локальный ключ или Vault Transit)"] -->|wrap / unwrap| DEK["data_keys.wrapped_dek"]
DEK -->|AES-256-GCM| Data["🔒-поля таблиц:<br/>ciphertext + nonce + data_key_id"]
Зашифрованное поле — тройка колонок *_ciphertext, *_nonce, *_data_key_id (Схема БД). DEK-и разделены по scope (credentials, certificates, node_secrets, billing) — компрометация одного ключа не раскрывает все категории данных.
KMS-провайдер
Section titled “KMS-провайдер”Корень доверия — интерфейс с двумя операциями:
type KMSProvider interface { Wrap(ctx, dek []byte) (wrapped []byte, keyVersion string, err error) Unwrap(ctx, wrapped []byte) (dek []byte, err error)}| Провайдер | Корневой ключ | Когда выбирать |
|---|---|---|
local (default) |
32 байта в файле (ASTRAL_MASTER_KEY_FILE); генерируется при первом старте, если файла нет |
Типовая self-hosted-инсталляция |
vault |
Vault Transit: ключ не покидает Vault, автотротация версий, аудит обращений | Инсталляции, где Vault уже есть |
Обязательный Vault был бы правильнее криптографически, но нереалистичен для целевого пользователя self-hosted-панели: это второй stateful-сервис с собственной процедурой unseal ради одного ключа. Поэтому корень — плагин: по умолчанию локальный мастер-ключ (с явным предупреждением в документации о бэкапе), Vault — опция без изменения схемы данных (data_keys.kms_key_version абстрагирует версию корня у обоих).
Что шифруется
Section titled “Что шифруется”| Данные | Где |
|---|---|
| Секреты протоколов подписок | protocol_credentials.secret |
| Токены ссылок подписок | subscriptions.token |
| Приватные ключи сертификатов | certificates.key_pem, internal_ca.key_pem |
| Reality private keys | inbound_profiles, chain_hops |
| Секреты хопов цепочек | chain_hops.secret |
| Креденшелы DNS-провайдеров, ACME-аккаунтов, EAB | dns_providers, acme_accounts |
| API-ключи платёжных агрегаторов | payment_providers.credentials |
Не шифруются, а хэшируются (одностороннее): пароли админов (Argon2id), refresh-токены, magic-link-токены, enrollment-токены — их не нужно читать обратно.
Запись и чтение
Section titled “Запись и чтение”Запись: активный DEK своего scope (кэшируется в памяти процесса после unwrap) → AES-256-GCM со случайным nonce → тройка колонок. Чтение: по data_key_id → unwrap (или кэш) → расшифровка. DEK в открытом виде существует только в памяти процесса.
Ротация
Section titled “Ротация”- DEK — фоновая задача раз в 30 дней на scope: новый DEK, старый помечается
retired_at(новые записи — новым ключом), ленивая перешифровка существующих строк батчами, удаление старого DEK, когда ссылок не осталось. - Корневой ключ — зависит от провайдера.
vault: Transit ротирует версии сам, задачаrewrapпериодически переобёртываетwrapped_dekсвежей версией (DEK-ов мало, операция дешёвая).local: смена файла ключа + командаastral rewrap-keys(переобёртка всех DEK старым→новым ключом; сами данные не перешифровываются).
Восстановление корневого ключа
Section titled “Восстановление корневого ключа”Провайдер local использует модель слотов (как LUKS): один мастер-ключ, несколько независимых способов его получить (ADR-011).
| Слот | Носитель | Секрет |
|---|---|---|
| Файл | Сервер панели (ASTRAL_MASTER_KEY_FILE) |
Сам ключ |
| Recovery | БД: мастер-ключ, обёрнутый ключом из recovery-кода (Argon2id) | Recovery-код |
- Мастер-ключ и recovery-код генерируются панелью при первом старте; код (~130 бит энтропии, формат
XXXX-XXXX-…) показывается один раз на экране установки. Код именно генерируется, а не выбирается: пользовательская парольная фраза свела бы свойство «дамп БД сам по себе бесполезен» к стойкости пароля. - Потерян файл ключа →
astral recover --recovery-code …: слот из БД восстанавливает файл. Бэкап БД + recovery-код = полное восстановление инсталляции. - Потерян recovery-код (файл жив) →
astral recovery-code new: старый слот заменяется новым кодом. - Ротация мастер-ключа (
astral rewrap-keys) обновляет оба слота атомарно.
Потеряно всё (файл + код) — 🔒-поля невосстановимы, но худший случай автоматизирован: astral crypto reset генерирует новый мастер-ключ и запускает перевыпуск — новые секреты всех подписок (bump ревизий), ACME-перевыпуск сертификатов, новый внутренний CA с re-enrollment нод. Существующие ссылки подписок продолжают работать: поиск идёт по незашифрованному token_hash, клиенты получают новые секреты по старой ссылке. Руками восстанавливаются только внешние креденшелы (DNS-провайдеры, платёжные агрегаторы) и MANUAL-сертификаты.
Отказ KMS
Section titled “Отказ KMS”Недоступность KMS-провайдера (для vault) блокирует операции с 🔒-полями, но не работу нод: desired state уже применён, VPN-трафик не зависит от backend. Кэш unwrapped DEK смягчает короткие недоступности для чтения.