Рыба проекта. Минимальная функциональность
This commit is contained in:
+229
@@ -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
|
||||
Reference in New Issue
Block a user