Files

12 KiB
Raw Permalink Blame History

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_HOST
  • APP_PG_DATABASE
  • APP_BACKUP_DIR
  • APP_PQ_PUBLIC_KEY_PATH
  • APP_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", "synapse-backupper", "healthcheck"]
      interval: 30s
      timeout: 3s
      start_period: 10s
    restart: unless-stopped

Важно: В каталоге ./keys должны находиться только публичные ключи (*.pub.pem). Перед запуском контейнера переместите приватные ключи (*.priv.pem) на офлайн-хост или хост, предназначенный только для восстановления.

Перед промышленным развёртыванием замените APP_PG_PASSWORD=secret на надёжный пароль; указанное значение только пример.

Запуск планировщика:

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