Что такое Keycloak#
Если вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти (ссылка в разделе контакты).
Keycloak - open-source решение для управления идентификацией и доступом (IAM) от Red Hat, с поддержкой SSO, OAuth2, OpenID Connect, SAML 2.0 и ещё доброго десятка стандартов помельче. Это, пожалуй, самый “тяжёлый” и одновременно самый функциональный игрок из всех IAM-решений, которые я разбирал в этой серии - в enterprise-среде он де-факто стандарт, и если вам когда-нибудь приходилось логиниться в корпоративный портал через страницу с логотипом “Keycloak” внизу - вот это оно и было.
В домашней лаборатории Keycloak оправдан не всегда - он ощутимо тяжелее, чем тот же Authentik или Authelia, и требует Java-стек под капотом. Но если вы хотите пощупать тот самый инструмент, с которым реально работают в проде на работе, или вам нужны специфичные корпоративные фичи вроде реалмов и федерации - это то, что нужно.
Зачем нужен Keycloak#
Централизованно управлять аутентификацией пользователей Keycloak умеет широко:
- единый вход (SSO) сразу во все подключённые приложения;
- вход через внешних провайдеров - Google, GitHub и другие через OAuth2/OIDC;
- подключение LDAP и Active Directory, если у вас уже есть корпоративный каталог пользователей;
- полноценная веб-админка, а не только конфиг-файлы;
- нативная поддержка OpenID Connect и OAuth 2.0 без костылей.
Что понадобится#
- Docker и Docker Compose;
- обратный прокси - в этой статье я использую Traefik;
- домен с настроенным DNS (у меня
keycloak.stilicho.ru); - SSL-сертификат, проще всего через Let’s Encrypt силами того же Traefik.
Возможности Keycloak#
Возможностей у Keycloak действительно много, и разложу их по смысловым группам, чтобы было понятно, что вообще получаете при установке.
Аутентификация и авторизация. Single Sign-On для всех подключённых приложений, вход через социальные провайдеры (Google, Facebook, GitHub и другие), поддержка OAuth2/OIDC/SAML 2.0 и многофакторная аутентификация через TOTP (Google Authenticator и аналоги).
Управление пользователями и ролями. Полноценное создание и управление пользователями, группами и ролями, делегированное администрирование - можно разграничить, кто из админов какими пользователями управляет, - плюс импорт и экспорт пользователей через LDAP, CSV или REST API.
Интеграция с корпоративной инфраструктурой. Прямая интеграция с LDAP и Active Directory, SCIM-подобные возможности через REST API, полноценный CLI-клиент и Admin REST API для автоматизации.
Multi-tenancy и реалмы. Пожалуй, главная архитектурная фишка Keycloak - реалмы (realms), изолированные домены аутентификации. У каждого реалма свои настройки, пользователи, клиенты и политики - можно держать один Keycloak на несколько независимых проектов или клиентов, не боясь, что они “увидят” пользователей друг друга.
Кастомизация. Можно кастомизировать UI экранов входа и регистрации под свой бренд, расширять функциональность через Java SPI и плагины, локализовать интерфейс под нужный язык.
Аудит и безопасность. Аудит логов входа и действий пользователей, гибко настраиваемые политики паролей, ограничения по IP и встроенная защита от brute-force атак.
Docker Compose файл, который используется в ролике#
Ниже - конфигурация, с которой я разворачивал Keycloak в видео. Она состоит из двух сервисов: базы PostgreSQL и самого Keycloak за Traefik.
services:
postgres:
image: postgres:16-alpine
container_name: keycloak-db
restart: always
expose:
- 5432
volumes:
- /home/path/to/keycloak/database:/var/lib/postgresql/data
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
healthcheck:
test:
[
"CMD",
"pg_isready",
"-q",
"-d",
"${POSTGRES_DB}",
"-U",
"${POSTGRES_USER}",
]
interval: 10s
timeout: 5s
retries: 3
start_period: 60s
networks:
- keycloak
keycloak:
image: quay.io/keycloak/keycloak:26.6.4 # не используйте :latest - зафиксируйте версию явно, актуальную смотрите на https://quay.io/repository/keycloak/keycloak?tab=tags
container_name: keycloak
command: start
environment:
KC_HOSTNAME: ${KEYCLOAK_HOSTNAME}
KC_BOOTSTRAP_ADMIN_USERNAME: ${KC_BOOTSTRAP_ADMIN_USERNAME}
KC_BOOTSTRAP_ADMIN_PASSWORD: ${KC_BOOTSTRAP_ADMIN_PASSWORD}
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres/${POSTGRES_DB}
KC_DB_USERNAME: ${POSTGRES_USER}
KC_DB_PASSWORD: ${POSTGRES_PASSWORD}
KC_PROXY_HEADERS: "xforwarded"
KC_HTTP_ENABLED: true
KC_HEALTH_ENABLED: true
PROXY_ADDRESS_FORWARDING: "true"
healthcheck:
test:
- "CMD-SHELL"
- |
exec 3<>/dev/tcp/localhost/9000 &&
echo -e 'GET /health/ready HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n' >&3 &&
cat <&3 | tee /tmp/healthcheck.log | grep -q '200 OK'
interval: 10s
timeout: 5s
retries: 3
start_period: 90s
#ports:
# - 8080:8080
#expose:
# - 8080 # web ui http
# - 9000 # health endpoint
restart: always
depends_on:
postgres:
condition: service_healthy
networks:
- keycloak
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.keycloak.entrypoints=http"
- "traefik.http.routers.keycloak.rule=Host(`keycloak.domain.ru`)"
- "traefik.http.middlewares.keycloak-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.keycloak.middlewares=keycloak-https-redirect"
- "traefik.http.routers.keycloak-secure.entrypoints=https"
- "traefik.http.routers.keycloak-secure.rule=Host(`keycloak.domain.ru`)"
- "traefik.http.routers.keycloak-secure.tls=true"
- "traefik.http.routers.keycloak-secure.service=keycloak"
- "traefik.http.services.keycloak.loadbalancer.server.port=8080"
- "traefik.docker.network=proxy"
networks:
keycloak:
internal: true
proxy:
external: trueЗначения в файле переменных
# define FQDN hostname
KEYCLOAK_HOSTNAME=keycloak.stilicho.ru
# define login credentials
KC_BOOTSTRAP_ADMIN_USERNAME=admin
KC_BOOTSTRAP_ADMIN_PASSWORD=password
# define database credentials
POSTGRES_DB=keycloak_db
POSTGRES_USER=keycloak_db_user
POSTGRES_PASSWORD=keycloak_db_user_passwordПару слов про то, что здесь происходит, потому что бездумно копировать чужой compose-файл - плохая идея.
Сеть keycloak намеренно объявлена как internal: true - у базы данных нет и не должно быть прямого выхода наружу, к ней обращается только сам контейнер Keycloak внутри той же docker-сети. Наружу торчит только сеть proxy, через которую Traefik подхватывает контейнер по лейблам.
KC_PROXY_HEADERS: "xforwarded" и PROXY_ADDRESS_FORWARDING: "true" говорят Keycloak, что он стоит за обратным прокси и должен доверять заголовкам X-Forwarded-* - без этого он будет путаться в том, какой протокол и хост реально использует клиент, и генерировать неправильные redirect-ссылки. KC_HTTP_ENABLED: true разрешает Keycloak слушать по обычному HTTP внутри контейнера - TLS-терминацию в этой схеме на себя берёт Traefik, а не сам Keycloak.
Healthcheck заслуживает отдельного слова: с определённой версии Keycloak health-эндпоинты переехали на отдельный management-порт 9000, а не висят на основном 8080 вместе с остальным приложением. Именно поэтому в healthcheck используется чистый bash через /dev/tcp вместо curl - в образе Keycloak его попросту нет, а тащить дополнительный пакет ради одной проверки не хочется.
Первый запуск и создание realm#
Разворачиваем всё командой docker compose up -d, ждём, пока пройдёт healthcheck у базы и сам Keycloak поднимется - при первом старте это может занять заметно больше времени, чем последующие рестарты, так как сервис инициализирует внутренние схемы в PostgreSQL.
После этого заходим на https://keycloak.stilicho.ru (у вас, разумеется, будет свой домен) и логинимся под учёткой из KC_BOOTSTRAP_ADMIN_USERNAME/KC_BOOTSTRAP_ADMIN_PASSWORD. Дальше по порядку:
- Создаём отдельный realm. По умолчанию Keycloak предлагает работать в realm
master, но это плохая практика -masterпредназначен для администрирования самого Keycloak, а не для ваших приложений. В левом верхнем углу выбираем Create realm, даём ему осмысленное имя (например,homelab). - Создаём клиента. Внутри свежего realm идём в Clients → Create client, задаём Client ID (обычно совпадает с именем защищаемого сервиса), включаем нужный тип аутентификации (Standard flow для обычного веб-приложения через OIDC) и прописываем Valid redirect URIs - адрес, куда Keycloak будет возвращать пользователя после успешного входа.
- Заводим пользователей. В Users создаём нужные учётные записи, либо настраиваем интеграцию с внешним LDAP/Active Directory через User federation, если пользователи уже где-то есть и плодить их вручную не хочется.
- Настраиваем MFA при желании. В Authentication можно обязать конкретные группы пользователей проходить TOTP - это делается через flows, не требует правки конфигов и применяется сразу ко всем клиентам realm.
С этого момента любое приложение, поддерживающее OIDC или SAML, можно подключить к этому realm как отдельного клиента - и оно получит единый вход вместе со всеми остальными сервисами, подключёнными тем же способом.
Заключение#
Keycloak - не самый лёгкий вариант для домашней лаборатории, и если вам нужен просто быстрый forward-auth перед парой сервисов, скорее всего, хватит Authelia или Authentik - я разбирал оба варианта в соседних статьях. Но если вы хотите разобраться с тем самым инструментом, который реально используют в enterprise, потренироваться на реалмах, федерации и делегированном администрировании, или у вас уже есть LDAP/Active Directory, которые нужно подключить как есть - Keycloak оправдывает свой вес с лихвой. Полное сравнение всех четырёх решений (включая ZITADEL) - в отдельной статье.





