12 KiB
Synapse Backupper
Инструмент для резервного копирования PostgreSQL Synapse с композитным шифрованием на основе двух механизмов обмена ключами (dual-KEM).
Обзор
synapse-backupper создает зашифрованные дампы PostgreSQL с использованием композитной схемы шифрования, которая объединяет постквантовый KEM (ML-KEM-768) и классический KEM (X25519). Для расшифровки резервной копии требуются оба ключа (модель AND). Инструмент поддерживает два режима работы: разовое резервное копирование (backup) и планировщик (run), который выполняет копирование по расписанию cron.
Копии хранятся локально на диске; устаревшие копии автоматически удаляются по возрасту.
Установка
Сборка Docker-образа:
make docker-build
В результате собирается образ synapse-backupper:latest. Внутри образа находится скомпилированный бинарник, клиентские утилиты PostgreSQL, а сам контейнер запускается от непривилегированного пользователя.
Быстрый старт
1. Генерация ключей шифрования
Сгенерируйте обе пары ключей (постквантовую и классическую) с помощью подкоманды keygen:
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-эндпоинт для проверки здоровья:
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)
Выполнить одну резервную копию немедленно:
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. Восстановление на отдельном хосте
Процедура восстановления специально выполняется на хосте, который не имеет доступа к базе данных. Достаточно только приватных ключей.
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:
pg_restore --clean --if-exists --dbname=synapse restored.dump
Конфигурация
Приоритет источников настроек: флаги командной строки → переменные окружения APP_* → файл конфигурации → значения по умолчанию.
Примеры в разделе «Быстрый старт» используют переменные окружения. Префикс — APP_, вложенные ключи разделяются подчеркиванием, например:
APP_PG_HOSTAPP_PG_DATABASEAPP_BACKUP_DIRAPP_PQ_PUBLIC_KEY_PATHAPP_CLASSICAL_PUBLIC_KEY_PATH
Чтобы использовать файл конфигурации, сгенерируйте пример и смонтируйте его в контейнер:
docker run --rm synapse-backupper:latest generate-config --lang ru > config.yaml
Отредактируйте config.yaml, затем смонтируйте его в /config.yaml при запуске контейнера:
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:
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) на офлайн-хост или хост, предназначенный только для восстановления.
Запуск планировщика:
docker compose up -d
Модель безопасности
Многоуровневая защита
Резервные копии шифруются по композитной схеме: общий секрет вычисляется независимо от постквантового и классического KEM, а полезная нагрузка шифруется симметричным ключом, полученным из обоих секретов. Злоумышленник должен взломать оба механизма, чтобы получить данные.
Модель AND
Для расшифровки требуются оба приватных ключа. Команда restore завершится с ошибкой, если хотя бы один ключ отсутствует или неверен. Это исключает компрометацию копий при компрометации одного ключа.
Plug-and-play KEM
Реализации KEM регистрируются в runtime-реестре по идентификатору схемы. Новые постквантовые или классические алгоритмы можно добавлять без изменения логики резервного копирования и восстановления.
Изоляция приватных ключей
Приватные ключи не нужны при создании резервной копии. Контейнер, выполняющий бэкап, монтирует только публичные ключи (:ro). Приватные ключи должны находиться на отдельном хосте восстановления или в офлайн-хранилище, что сужает зону поражения при компрометации сервера резервного копирования.
Ограничения
Это MVP-релиз. Следующие возможности не реализованы:
- S3 / объектное хранилище — копии пишутся только в локальный каталог.
- Развертывание в Kubernetes — Helm-чарт и оператор не предоставляются.
- Потоковое / инкрементальное резервное копирование — каждый запуск создает полный
pg_dump. - Поддержка нескольких баз данных — предполагается одна база данных на инстанс.
Разработка
Запуск unit-тестов:
make test
Запуск сквозного интеграционного теста (требуется Docker):
make integration-test
Кросс-компиляция:
make cross-build
Лицензия
MIT