MAATRIX / Блог / Бэкап и восстановление Keycloak

Бэкап и восстановление Keycloak

MAATRIX

Keycloak — это не просто сервис с базой данных, это точка входа для всех остальных приложений компании: если он упадёт и бэкапа не окажется, вы теряете доступ разом ко всему, что на него завязано — от Grafana до внутренних API. Один pg_dump базы часто не спасает: теряются экспортированные realm-конфиги, кастомные темы, провайдеры и приватные ключи подписи токенов. Разберём, что именно нужно бэкапить, как это делать без даунтайма и как восстанавливаться, если что-то пошло не так.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что на самом деле нужно бэкапить

Keycloak хранит состояние в нескольких местах, и упустить хотя бы одно — значит после восстановления получить нерабочий SSO даже с виду «восстановленной» базой:

  • База данных (PostgreSQL или MySQL) — realms, клиенты, пользователи, роли, группы, сессии, события аудита. Это основной источник истины.
  • Ключи подписи и шифрования — если вы не используете дефолтную генерацию ключей в БД, а завели свой keystore (java.keystore или PKCS12), его нужно бэкапить отдельно. Потерять его — значит инвалидировать все выданные refresh-токены и разлогинить всех пользователей разом.
  • Кастомные темы (themes/) — если вы правили login-страницу под бренд, это файлы на диске, а не в БД.
  • Кастомные провайдеры (providers/*.jar) — самописные SPI (event listener, кастомная аутентификация, интеграции) живут как jar-файлы вне БД.
  • Конфиг сервераconf/keycloak.conf, переменные окружения, флаги реалма (hostname, proxy-режим).

Если Keycloak развёрнут в Docker Compose, три последних пункта — это volume’ы или bind-mount, а не часть базы. Про общий подход к бэкапу volume’ов есть отдельный разбор: бэкап Docker volume на сервере.

Бэкап PostgreSQL: полный дамп и логическая консистентность

Если Keycloak работает на PostgreSQL (самый частый вариант в проде), базовый снимок делается стандартным pg_dump:

docker exec -t keycloak-postgres pg_dump \
  -U keycloak -d keycloak -F c -f /tmp/keycloak_$(date +%F).dump

docker cp keycloak-postgres:/tmp/keycloak_$(date +%F).dump ./backups/

Формат -F c (custom) даёт сжатый дамп и позволяет восстанавливать выборочно — например, только таблицы конкретного realm при отладке, без полного pg_restore. Для крупных инсталляций (десятки тысяч пользователей, активные сессии) добавляйте --no-owner --no-acl, чтобы не тащить за собой права ролей, которые на новом сервере могут не совпадать.

Важный нюанс: таблицы USER_SESSION и OFFLINE_USER_SESSION растут быстро и в бэкапе почти бесполезны — после restore сессии всё равно инвалидируются логикой самого Keycloak при рестарте кластера. Если база большая и бэкап долго идёт, можно исключить их явно:

docker exec -t keycloak-postgres pg_dump \
  -U keycloak -d keycloak -F c \
  --exclude-table-data='USER_SESSION*' \
  --exclude-table-data='OFFLINE_USER_SESSION*' \
  -f /tmp/keycloak_$(date +%F).dump

Если поднимаете БД для Keycloak с нуля на выделенном сервере — общие принципы установки и настройки PostgreSQL под нагрузку стоит освоить отдельно, это база любой продовой инсталляции.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Экспорт realm через admin CLI: человекочитаемая альтернатива

Дамп БД — это бинарный снимок, который вы не откроете глазами и не сравните построчно в git. Для конфигурации realm (клиенты, роли, identity providers, флоу аутентификации) удобнее держать ещё и JSON-экспорт — он читается человеком и его можно версионировать.

Экспорт делается штатной утилитой kc.sh (в контейнере — /opt/keycloak/bin/kc.sh) в offline-режиме, то есть при остановленном сервисе:

docker exec keycloak /opt/keycloak/bin/kc.sh export \
  --dir /tmp/kc-export \
  --realm myrealm \
  --users realm_file

Флаг --users realm_file кладёт пользователей в тот же файл, что и остальную конфигурацию realm — удобно для небольших realm’ов. Для больших (тысячи пользователей) лучше --users different_files — экспорт разобьётся на чанки, и импорт не упрётся в лимит памяти JVM.

Полный экспорт всех realm без указания --realm:

docker exec keycloak /opt/keycloak/bin/kc.sh export --dir /tmp/kc-export

Минус этого способа — сервис на время экспорта недоступен (offline-режим специально блокирует запись, чтобы не получить рассинхрон). Поэтому JSON-экспорт держите как дополнительный слепок раз в день, а не как основной механизм бэкапа — основной всё равно pg_dump на живой базе.

Ключи, темы и провайдеры: файловая часть

Если keystore с ключами подписи хранится на диске (а не в defaultProvider БД), бэкапьте его отдельным архивом с шифрованием — это самый чувствительный файл во всей системе:

tar czf - -C /opt/keycloak/conf keycloak.keystore \
  | gpg --symmetric --cipher-algo AES256 -o keystore_$(date +%F).tar.gz.gpg

Темы и кастомные провайдеры бэкапятся проще, потому что они воспроизводимы из исходников (обычно лежат в вашем git-репозитории), но снимок на сервере всё равно нужен — на случай, если версия в проде разошлась с репозиторием:

tar czf themes_providers_$(date +%F).tar.gz \
  -C /opt/keycloak themes providers conf/keycloak.conf

Если Keycloak развёрнут через Docker Compose, эти пути — это смонтированные volume’ы, и весь набор проще снимать одной командой через docker run --rm --volumes-from, аналогично тому, как описано в материале про бэкап всего сервера целиком.

Docker Compose: собираем бэкап в один скрипт

На практике удобнее не дёргать три команды руками, а собрать один shell-скрипт, который берёт дамп БД, экспорт realm и файловую часть, упаковывает и шифрует за один проход:

#!/usr/bin/env bash
set -euo pipefail

DATE=$(date +%F_%H%M)
BACKUP_DIR="/opt/backups/keycloak"
mkdir -p "$BACKUP_DIR"

# 1. Дамп БД
docker exec keycloak-postgres pg_dump -U keycloak -d keycloak -F c \
  -f "/tmp/kc_db_${DATE}.dump"
docker cp "keycloak-postgres:/tmp/kc_db_${DATE}.dump" "$BACKUP_DIR/"

# 2. Файловая часть (без остановки сервиса)
docker run --rm --volumes-from keycloak \
  -v "$BACKUP_DIR:/backup" alpine \
  tar czf "/backup/kc_files_${DATE}.tar.gz" \
  /opt/keycloak/themes /opt/keycloak/providers /opt/keycloak/conf

# 3. Шифрование и упаковка в один архив
tar czf - -C "$BACKUP_DIR" "kc_db_${DATE}.dump" "kc_files_${DATE}.tar.gz" \
  | gpg --symmetric --cipher-algo AES256 --batch --passphrase-file /etc/kc-backup.key \
  -o "$BACKUP_DIR/kc_full_${DATE}.tar.gz.gpg"

# 4. Чистим промежуточные файлы, оставляем только зашифрованный архив
rm -f "$BACKUP_DIR/kc_db_${DATE}.dump" "$BACKUP_DIR/kc_files_${DATE}.tar.gz"

# 5. Ротация: храним 14 дней
find "$BACKUP_DIR" -name 'kc_full_*.tar.gz.gpg' -mtime +14 -delete

Подробнее о шифровании бэкапов и типичных граблях с passphrase-файлами — в статье бэкап с шифрованием на VPS: частые ошибки и решения.

Ставите скрипт в cron с запуском в период минимальной нагрузки:

0 3 * * * /opt/scripts/backup_keycloak.sh >> /var/log/kc_backup.log 2>&1

Восстановление: пошагово, без спешки

Восстановление Keycloak — операция с полным даунтаймом, планируйте окно заранее и предупредите зависимые сервисы.

1. Останавливаем Keycloak, но не базу:

docker stop keycloak

2. Расшифровываем и распаковываем архив:

gpg --decrypt kc_full_2026-08-20_0300.tar.gz.gpg --batch \
  --passphrase-file /etc/kc-backup.key | tar xzf -

3. Восстанавливаем базу. Если восстанавливаете на ту же БД поверх текущего состояния — сначала дропаем и создаём заново, чтобы не получить конфликт последовательностей и constraint’ов:

docker exec -it keycloak-postgres psql -U postgres -c "DROP DATABASE keycloak;"
docker exec -it keycloak-postgres psql -U postgres -c "CREATE DATABASE keycloak OWNER keycloak;"

docker cp kc_db_2026-08-20_0300.dump keycloak-postgres:/tmp/restore.dump
docker exec -it keycloak-postgres pg_restore -U keycloak -d keycloak \
  --no-owner --no-acl /tmp/restore.dump

4. Возвращаем файловую часть (темы, провайдеры, keystore) в те же пути, что были на volume:

tar xzf kc_files_2026-08-20_0300.tar.gz -C /

5. Запускаем Keycloak и проверяем:

docker start keycloak
docker logs -f keycloak

Первым делом зайдите в admin console, откройте нужный realm и проверьте, что клиенты и identity providers на месте. Затем протестируйте логин тестовым пользователем — если ключи подписи восстановились не полностью (например, забыли keystore), вы получите ошибку валидации токена на стороне клиентских приложений, а не в самом Keycloak, и искать причину придётся дольше.

Если восстанавливаете realm из JSON-экспорта (частичное восстановление одного realm без трогания остальных):

docker exec keycloak /opt/keycloak/bin/kc.sh import \
  --dir /tmp/kc-export --override true

--override true перезапишет существующий realm с тем же именем — без флага импорт откажется работать при конфликте.

Автоматизация, offsite-копия и мониторинг

Локальный бэкап на том же сервере, что и сам Keycloak, не защищает от отказа диска или потери сервера целиком. Выносите зашифрованные архивы за пределы сервера — например, через rclone на S3-совместимое хранилище или на отдельный VPS под бэкапы:

rclone copy /opt/backups/keycloak remote:kc-backups --min-age 1h

Сравнение инструментов для организации такого хранения — в материале restic или BorgBackup: что выгоднее и когда; оба неплохо ложатся поверх уже готового зашифрованного архива как второй слой дедупликации версий.

Минимальный набор проверок, который стоит завести с первого дня:

ПроверкаКак частоЧто делать при провале
Скрипт бэкапа отработал без ошибоккаждый запуск (лог + алерт)смотреть /var/log/kc_backup.log
Архив реально расшифровываетсяраз в неделютестовый gpg --decrypt в отдельной песочнице
Дамп восстанавливается на тестовом стендераз в месяцполный dry-run восстановления по шагам выше
Offsite-копия синхронизированаежедневнопроверка возраста последнего файла в remote-хранилище

Пункт про тестовое восстановление часто пропускают, а зря — нерабочий бэкап обнаруживается обычно в худший момент, а не при плановой проверке.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли бэкапить Keycloak «на горячую», без остановки сервиса?

Да, для pg_dump это штатный режим — PostgreSQL делает консистентный снимок на уровне транзакции без блокировки записи. А вот kc.sh export требует offline-режима, поэтому основным механизмом должен быть дамп БД, а JSON-экспорт — дополнительным слепком раз в день.

Что произойдёт, если потерять keystore с ключами подписи?

Все выданные access и refresh токены станут невалидными, всем пользователям придётся залогиниться заново. Само по себе это не катастрофа (данные не теряются), но неприятный простой для пользователей — поэтому keystore бэкапьте так же строго, как и базу.

Нужно ли бэкапить Redis/Infinispan, если он используется для кластерных сессий?

Обычно нет — это кэш сессий, а не источник истины. После восстановления Keycloak активные сессии всё равно инвалидируются, пользователи перелогиниваются, поэтому бэкапить кэш сессий смысла нет.

Как часто нужно делать полный бэкап?

Для прод-инсталляции с активными пользователями — не реже раза в сутки для БД, плюс перед любым обновлением версии Keycloak или миграцией схемы вручную, отдельно от расписания.

Восстановление на другой мажорной версии Keycloak сработает?

Не гарантированно — между мажорными версиями меняется схема БД, и pg_restore дампа со старой версии в контейнер с новой может не пройти без миграции. Безопаснее сначала поднять восстановленный дамп на той же версии, что делала бэкап, дать серверу применить миграции штатно при старте, и только потом обновлять образ.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →