# 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-.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", "synapse-backupper", "healthcheck"] interval: 30s timeout: 3s start_period: 10s restart: unless-stopped ``` > **Важно:** В каталоге `./keys` должны находиться только публичные ключи (`*.pub.pem`). Перед запуском контейнера переместите приватные ключи (`*.priv.pem`) на офлайн-хост или хост, предназначенный только для восстановления. > > Перед промышленным развёртыванием замените `APP_PG_PASSWORD=secret` на надёжный пароль; указанное значение только пример. Запуск планировщика: ```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