Рыба проекта. Минимальная функциональность

This commit is contained in:
2026-08-03 22:22:24 +03:00
commit 8c8631ac9c
80 changed files with 10618 additions and 0 deletions
+229
View File
@@ -0,0 +1,229 @@
# Synapse Backupper
Инструмент для резервного копирования PostgreSQL [Synapse](https://github.com/element-hq/synapse) с композитным шифрованием на основе двух механизмов обмена ключами (dual-KEM).
## Обзор
`synapse-backupper` создает зашифрованные дампы PostgreSQL с использованием **композитной** схемы шифрования, которая объединяет постквантовый KEM (ML-KEM-768) и классический KEM (X25519). Для расшифровки резервной копии требуются оба ключа (модель AND). Инструмент поддерживает два режима работы: разовое резервное копирование (`backup`) и планировщик (`run`), который выполняет копирование по расписанию cron.
Копии хранятся локально на диске; устаревшие копии автоматически удаляются по возрасту.
## Установка
Сборка Docker-образа:
```bash
make docker-build
```
В результате собирается образ `synapse-backupper:latest`. Внутри образа находится скомпилированный бинарник, клиентские утилиты PostgreSQL, а сам контейнер запускается от непривилегированного пользователя.
## Быстрый старт
### 1. Генерация ключей шифрования
Сгенерируйте обе пары ключей (постквантовую и классическую) с помощью подкоманды `keygen`:
```bash
mkdir -p ./keys
docker run --rm -u root -v "$(pwd)/keys:/keys" synapse-backupper:latest \
keygen --type both --out-prefix /keys/synapse
chown -R "$(id -u):$(id -g)" ./keys
```
> **Примечание:** Образ контейнера по умолчанию запускается от непривилегированного пользователя `app`. Подкоманда `keygen` должна писать в смонтированный с хоста каталог, поэтому здесь она запускается от `root`, а затем владение файлами возвращается текущему пользователю. Если вы не работаете от `root`, скорректируйте команду `chown` (например, через `sudo`).
В каталоге `./keys/` появятся четыре файла:
| Файл | Назначение |
|------|------------|
| `synapse.pq.pub.pem` | Постквантовый публичный ключ (для резервного копирования) |
| `synapse.pq.priv.pem` | Постквантовый приватный ключ (для восстановления, хранить офлайн) |
| `synapse.classical.pub.pem` | Классический публичный ключ (для резервного копирования) |
| `synapse.classical.priv.pem` | Классический приватный ключ (для восстановления, хранить офлайн) |
**Важно:** приватные ключи никогда не следует монтировать в контейнер, который делает резервные копии. Храните их офлайн или на отдельном хосте, предназначенном только для восстановления.
### 2. Режимы работы
#### Режим планировщика (`run`)
Команда по умолчанию запускает планировщик по расписанию cron и HTTP-эндпоинт для проверки здоровья:
```bash
docker run -d -u root \
--name synapse-backupper \
-v "$(pwd)/keys:/keys:ro" \
-v "$(pwd)/backups:/backups" \
-e APP_PG_HOST=db \
-e APP_PG_DATABASE=postgres \
-e APP_PG_USER=synapse \
-e APP_PG_PASSWORD=changeme \
-e APP_PQ_PUBLIC_KEY_PATH=/keys/synapse.pq.pub.pem \
-e APP_CLASSICAL_PUBLIC_KEY_PATH=/keys/synapse.classical.pub.pem \
-e APP_BACKUP_DIR=/backups \
synapse-backupper:latest
```
По умолчанию резервное копирование выполняется ежедневно в `03:00`. Расписание задается параметром `backup.cron` в конфигурационном файле или переменной окружения `APP_BACKUP_CRON`.
#### Разовое резервное копирование (`backup`)
Выполнить одну резервную копию немедленно:
```bash
docker run --rm -u root \
-v "$(pwd)/keys:/keys:ro" \
-v "$(pwd)/backups:/backups" \
-e APP_PG_HOST=5432 \
-e APP_PG_DATABASE=postgres \
-e APP_PG_USER=synapse \
-e APP_PG_PASSWORD=changeme \
-e APP_PQ_PUBLIC_KEY_PATH=/keys/synapse.pq.pub.pem \
-e APP_CLASSICAL_PUBLIC_KEY_PATH=/keys/synapse.classical.pub.pem \
-e APP_BACKUP_DIR=/backups \
synapse-backupper:latest backup
```
Результирующий файл получает имя `synapse-<timestamp>.dump.pqenc` и сохраняется в каталог резервных копий. Дамп создается в формате PostgreSQL custom (`--format=custom`), который ожидает `pg_restore`.
### 3. Восстановление на отдельном хосте
Процедура восстановления специально выполняется на хосте, который **не** имеет доступа к базе данных. Достаточно только приватных ключей.
```bash
docker run --rm \
-v "$(pwd)/keys:/keys:ro" \
-v "$(pwd)/backups:/backups:ro" \
-v "$(pwd)/restored:/out" \
synapse-backupper:latest restore \
--in /backups/synapse-20260102-150405.dump.pqenc \
--privkey-pq /keys/synapse.pq.priv.pem \
--privkey-classical /keys/synapse.classical.priv.pem \
--out /out/restored.dump
```
После этого восстановите расшифрованный дамп стандартными средствами PostgreSQL:
```bash
pg_restore --clean --if-exists --dbname=synapse restored.dump
```
## Конфигурация
Приоритет источников настроек: флаги командной строки → переменные окружения `APP_*` → файл конфигурации → значения по умолчанию.
Примеры в разделе «Быстрый старт» используют переменные окружения. Префикс — `APP_`, вложенные ключи разделяются подчеркиванием, например:
- `APP_PG_HOST`
- `APP_PG_DATABASE`
- `APP_BACKUP_DIR`
- `APP_PQ_PUBLIC_KEY_PATH`
- `APP_CLASSICAL_PUBLIC_KEY_PATH`
Чтобы использовать файл конфигурации, сгенерируйте пример и смонтируйте его в контейнер:
```bash
docker run --rm synapse-backupper:latest generate-config --lang ru > config.yaml
```
Отредактируйте `config.yaml`, затем смонтируйте его в `/config.yaml` при запуске контейнера:
```bash
docker run -d \
--name synapse-backupper \
-v "$(pwd)/config.yaml:/config.yaml" \
-v "$(pwd)/keys:/keys:ro" \
-v "$(pwd)/backups:/backups" \
synapse-backupper:latest
```
Переменные окружения переопределяют значения из файла конфигурации.
## Docker Compose
Планировщик можно запустить через Docker Compose. Пример `docker-compose.yml`:
```yaml
version: '3.8'
services:
synapse-backupper:
image: synapse-backupper:latest
volumes:
- ./backups:/backups
- ./keys:/keys:ro
environment:
- APP_PG_HOST=synapse-pg
- APP_PG_DATABASE=synapse
- APP_PG_USER=synapse
- APP_PG_PASSWORD=secret
- APP_PQ_PUBLIC_KEY_PATH=/keys/synapse.pq.pub.pem
- APP_CLASSICAL_PUBLIC_KEY_PATH=/keys/synapse.classical.pub.pem
- APP_BACKUP_DIR=/backups
- APP_BACKUP_CRON=0 0 3 * * *
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:8080/healthz"]
interval: 30s
timeout: 3s
start_period: 10s
restart: unless-stopped
```
> **Важно:** В каталоге `./keys` должны находиться только публичные ключи (`*.pub.pem`). Перед запуском контейнера переместите приватные ключи (`*.priv.pem`) на офлайн-хост или хост, предназначенный только для восстановления.
Запуск планировщика:
```bash
docker compose up -d
```
## Модель безопасности
### Многоуровневая защита
Резервные копии шифруются по **композитной** схеме: общий секрет вычисляется независимо от постквантового и классического KEM, а полезная нагрузка шифруется симметричным ключом, полученным из обоих секретов. Злоумышленник должен взломать **оба** механизма, чтобы получить данные.
### Модель AND
Для расшифровки требуются **оба** приватных ключа. Команда `restore` завершится с ошибкой, если хотя бы один ключ отсутствует или неверен. Это исключает компрометацию копий при компрометации одного ключа.
### Plug-and-play KEM
Реализации KEM регистрируются в runtime-реестре по идентификатору схемы. Новые постквантовые или классические алгоритмы можно добавлять без изменения логики резервного копирования и восстановления.
### Изоляция приватных ключей
Приватные ключи **не нужны** при создании резервной копии. Контейнер, выполняющий бэкап, монтирует только публичные ключи (`:ro`). Приватные ключи должны находиться на отдельном хосте восстановления или в офлайн-хранилище, что сужает зону поражения при компрометации сервера резервного копирования.
## Ограничения
Это MVP-релиз. Следующие возможности **не реализованы**:
- **S3 / объектное хранилище** — копии пишутся только в локальный каталог.
- **Развертывание в Kubernetes** — Helm-чарт и оператор не предоставляются.
- **Потоковое / инкрементальное резервное копирование** — каждый запуск создает полный `pg_dump`.
- **Поддержка нескольких баз данных** — предполагается одна база данных на инстанс.
## Разработка
Запуск unit-тестов:
```bash
make test
```
Запуск сквозного интеграционного теста (требуется Docker):
```bash
make integration-test
```
Кросс-компиляция:
```bash
make cross-build
```
## Лицензия
MIT