15 систем и 15 паролей: внедряем Keycloak SSO для IT-интегратора

Задача клиента: IT-компания, утонувшая в собственных паролях

В январе 2026 года в АйТи Фреш обратилась компания ДиджиталФлоу — IT-интегратор из Санкт-Петербурга. Штат — 200 сотрудников: разработчики, DevOps-инженеры, аналитики, проектные менеджеры и административный персонал. Компания реализует проекты цифровой трансформации для крупных заказчиков.

Парадокс ситуации: IT-компания, помогающая другим автоматизировать процессы, сама тонула в хаосе учётных записей. 15 внутренних систем — 15 разных логинов и паролей для каждого сотрудника: GitLab, Grafana, Nextcloud, Jira, Confluence, Jenkins, SonarQube, Vault, Mattermost, Wiki.js, Redmine, AWX, Zabbix, Portainer, pgAdmin.

«Новый сотрудник проводит первый рабочий день, создавая аккаунты в 15 системах. Уволившийся — оставляет активные учётки в половине из них, потому что никто не помнит полный список. Мы получили замечание на аудите безопасности: 23 активных аккаунта уволенных сотрудников в разных системах» — CISO ДиджиталФлоу.

Требования к решению были чёткими: единый логин для всех систем (SSO), централизованное управление пользователями, двухфакторная аутентификация, автоматическая деактивация при увольнении и интеграция с существующим LDAP.

Аудит текущей системы аутентификации

Мы провели аудит всех 15 систем и классифицировали их по типу поддерживаемой аутентификации:

СистемаТекущая аутентификацияПоддержка SSOПользователей
GitLabВстроеннаяOIDC, SAML180
GrafanaВстроеннаяOIDC, SAML50
NextcloudВстроенная + LDAPOIDC, SAML200
JiraВстроеннаяSAML, OIDC150
ConfluenceВстроеннаяSAML, OIDC150
JenkinsВстроеннаяOIDC60
SonarQubeВстроеннаяSAML, OIDC80
MattermostВстроеннаяOIDC, SAML200
Wiki.jsВстроеннаяOIDC200
ZabbixВстроеннаяSAML30

Хорошая новость: все критические системы поддерживают OIDC или SAML — стандартные протоколы SSO. Текущий LDAP-сервер (OpenLDAP на Ubuntu) содержит актуальную базу из 200 пользователей с группами по отделам.

Выбор решения: почему Keycloak

Мы рассмотрели четыре варианта IdP (Identity Provider):

РешениеЛицензияПротоколыLDAP2FAКастомизация
KeycloakApache 2.0OIDC, SAML 2.0FederationTOTP, WebAuthnТемы, SPI
AuthentikCustom open-sourceOIDC, SAML, LDAPFederationTOTP, WebAuthnFlows, policies
AutheliaApache 2.0OIDCBackendTOTP, WebAuthnОграничена
Azure ADПодпискаOIDC, SAMLAzure AD ConnectMicrosoft AuthПолная

Выбор пал на Keycloak: зрелый open-source проект от Red Hat с 10+ годами production-эксплуатации, полной поддержкой OIDC и SAML 2.0, встроенной LDAP-федерацией и обширными возможностями кастомизации. Отсутствие подписки и лицензионных ограничений — важный фактор для IT-компании с 200 сотрудниками.

Установка Keycloak в Docker с PostgreSQL

Мы развернули Keycloak в контейнерной среде для простоты обновления и масштабирования. В качестве хранилища — PostgreSQL, для кэширования — встроенный Infinispan.

Docker Compose для production

# /opt/keycloak/docker-compose.yml
version: '3.9'

services:
  postgres:
    image: postgres:16-alpine
    restart: always
    volumes:
      - /opt/keycloak/data/postgres:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak
      POSTGRES_PASSWORD: ${KC_DB_PASSWORD}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U keycloak"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - keycloak-net

  keycloak:
    image: quay.io/keycloak/keycloak:26.0
    restart: always
    command: start
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      # Database
      KC_DB: postgres
      KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
      KC_DB_USERNAME: keycloak
      KC_DB_PASSWORD: ${KC_DB_PASSWORD}

      # Hostname
      KC_HOSTNAME: auth.digitalflow.ru
      KC_HOSTNAME_STRICT: true
      KC_PROXY_HEADERS: xforwarded

      # HTTP
      KC_HTTP_ENABLED: true
      KC_HTTP_PORT: 8080
      KC_HEALTH_ENABLED: true
      KC_METRICS_ENABLED: true

      # Admin
      KC_BOOTSTRAP_ADMIN_USERNAME: ${KC_ADMIN_USER}
      KC_BOOTSTRAP_ADMIN_PASSWORD: ${KC_ADMIN_PASSWORD}

      # Features
      KC_FEATURES: token-exchange,admin-fine-grained-authz

      # Cache (Infinispan)
      KC_CACHE: ispn
      KC_CACHE_STACK: tcp

      # Logging
      KC_LOG_LEVEL: INFO
    ports:
      - "8080:8080"
    volumes:
      - /opt/keycloak/themes:/opt/keycloak/themes
      - /opt/keycloak/providers:/opt/keycloak/providers
    networks:
      - keycloak-net

  nginx:
    image: nginx:1.27-alpine
    restart: always
    ports:
      - "443:443"
      - "80:80"
    volumes:
      - /opt/keycloak/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - /etc/letsencrypt:/etc/letsencrypt:ro
    depends_on:
      - keycloak
    networks:
      - keycloak-net

networks:
  keycloak-net:
    driver: bridge

Nginx reverse proxy с SSL

# /opt/keycloak/nginx/nginx.conf
events {
    worker_connections 1024;
}

http {
    upstream keycloak_backend {
        server keycloak:8080;
    }

    # Redirect HTTP to HTTPS
    server {
        listen 80;
        server_name auth.digitalflow.ru;
        return 301 https://$server_name$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name auth.digitalflow.ru;

        ssl_certificate /etc/letsencrypt/live/auth.digitalflow.ru/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/auth.digitalflow.ru/privkey.pem;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;

        # Security headers
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
        add_header X-Content-Type-Options nosniff;
        add_header X-Frame-Options SAMEORIGIN;
        add_header X-XSS-Protection "1; mode=block";

        # Proxy settings
        proxy_buffer_size 128k;
        proxy_buffers 4 256k;
        proxy_busy_buffers_size 256k;

        location / {
            proxy_pass http://keycloak_backend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-Port $server_port;
        }
    }
}

После запуска контейнеров Keycloak доступен по адресу https://auth.digitalflow.ru. Первичная настройка — создание realm и подключение LDAP.

Настройка Realm и LDAP Federation

Realm в Keycloak — изолированное пространство с собственными пользователями, клиентами и настройками. Мы создали realm digitalflow для всей компании.

Создание Realm через Admin CLI

# Keycloak Admin CLI (kcadm.sh) — для автоматизации
# Авторизация
/opt/keycloak/bin/kcadm.sh config credentials \
    --server https://auth.digitalflow.ru \
    --realm master \
    --user admin \
    --password "${KC_ADMIN_PASSWORD}"

# Создание realm
/opt/keycloak/bin/kcadm.sh create realms -s realm=digitalflow \
    -s enabled=true \
    -s displayName="ДиджиталФлоу" \
    -s loginTheme=digitalflow-theme \
    -s accountTheme=digitalflow-theme \
    -s emailTheme=digitalflow-theme \
    -s internationalizationEnabled=true \
    -s supportedLocales='["en","ru"]' \
    -s defaultLocale=ru \
    -s bruteForceProtected=true \
    -s maxFailureWaitSeconds=900 \
    -s failureFactor=5 \
    -s permanentLockout=false

# Настройка email для отправки уведомлений
/opt/keycloak/bin/kcadm.sh update realms/digitalflow \
    -s 'smtpServer.host=smtp.digitalflow.ru' \
    -s 'smtpServer.port=587' \
    -s 'smtpServer.starttls=true' \
    -s 'smtpServer.auth=true' \
    -s 'smtpServer.user=keycloak@digitalflow.ru' \
    -s 'smtpServer.password=SMTP_Password!' \
    -s 'smtpServer.from=keycloak@digitalflow.ru' \
    -s 'smtpServer.fromDisplayName=ДиджиталФлоу SSO'

Подключение LDAP через User Federation

Существующий OpenLDAP-сервер содержит 200 пользователей с группами. Keycloak будет федерировать (импортировать) их, сохраняя LDAP как источник истины:

# Создание LDAP Federation Provider
/opt/keycloak/bin/kcadm.sh create components -r digitalflow \
    -s name="OpenLDAP" \
    -s providerId=ldap \
    -s providerType=org.keycloak.storage.UserStorageProvider \
    -s 'config.vendor=["other"]' \
    -s 'config.connectionUrl=["ldap://ldap.digitalflow.local:389"]' \
    -s 'config.bindDn=["cn=admin,dc=digitalflow,dc=local"]' \
    -s 'config.bindCredential=["LDAP_Bind_Pass!"]' \
    -s 'config.usersDn=["ou=People,dc=digitalflow,dc=local"]' \
    -s 'config.userObjectClasses=["inetOrgPerson"]' \
    -s 'config.usernameLDAPAttribute=["uid"]' \
    -s 'config.uuidLDAPAttribute=["entryUUID"]' \
    -s 'config.rdnLDAPAttribute=["uid"]' \
    -s 'config.editMode=["READ_ONLY"]' \
    -s 'config.syncRegistrations=["false"]' \
    -s 'config.importEnabled=["true"]' \
    -s 'config.batchSizeForSync=["100"]' \
    -s 'config.fullSyncPeriod=["3600"]' \
    -s 'config.changedSyncPeriod=["60"]' \
    -s 'config.pagination=["true"]'

# Маппинг групп LDAP -> Keycloak
# В LDAP группы: developers, devops, analysts, managers, admins
# Автоматически создаём маппинг через UI:
# User Federation -> OpenLDAP -> Mappers -> Add mapper
# Type: group-ldap-mapper
# LDAP Groups DN: ou=Groups,dc=digitalflow,dc=local
# Group Object Classes: groupOfNames
# Membership LDAP Attribute: member
# Mode: READ_ONLY

# Запускаем первичную синхронизацию
# Admin Console -> User Federation -> OpenLDAP -> Synchronize all users
# Result: 200 users imported, 5 groups mapped

Интеграция с корпоративными системами

Самый объёмный этап — подключение каждой из 15 систем к Keycloak. Мы использовали OIDC (OpenID Connect) как предпочтительный протокол — он проще в настройке и лучше поддерживается современными приложениями. SAML применяли только там, где OIDC недоступен.

GitLab: OIDC-интеграция

GitLab — главная система для разработчиков. 180 из 200 сотрудников используют его ежедневно:

# 1. Создаём OIDC-клиент в Keycloak
/opt/keycloak/bin/kcadm.sh create clients -r digitalflow \
    -s clientId=gitlab \
    -s name="GitLab" \
    -s enabled=true \
    -s protocol=openid-connect \
    -s publicClient=false \
    -s clientAuthenticatorType=client-secret \
    -s 'redirectUris=["https://gitlab.digitalflow.ru/users/auth/openid_connect/callback"]' \
    -s 'webOrigins=["https://gitlab.digitalflow.ru"]' \
    -s directAccessGrantsEnabled=false \
    -s standardFlowEnabled=true

# Получаем client secret
/opt/keycloak/bin/kcadm.sh get clients -r digitalflow -q clientId=gitlab --fields id,secret

# 2. Настраиваем GitLab (/etc/gitlab/gitlab.rb)
# gitlab.rb
gitlab_rails['omniauth_enabled'] = true
gitlab_rails['omniauth_allow_single_sign_on'] = ['openid_connect']
gitlab_rails['omniauth_sync_email_from_provider'] = 'openid_connect'
gitlab_rails['omniauth_sync_profile_from_provider'] = ['openid_connect']
gitlab_rails['omniauth_sync_profile_attributes'] = ['name', 'email']
gitlab_rails['omniauth_block_auto_created_users'] = false
gitlab_rails['omniauth_auto_link_ldap_user'] = true

gitlab_rails['omniauth_providers'] = [
  {
    name: "openid_connect",
    label: "Войти через SSO",
    args: {
      name: "openid_connect",
      scope: ["openid", "profile", "email"],
      response_type: "code",
      issuer: "https://auth.digitalflow.ru/realms/digitalflow",
      discovery: true,
      client_auth_method: "query",
      uid_field: "preferred_username",
      pkce: true,
      client_options: {
        identifier: "gitlab",
        secret: "GITLAB_CLIENT_SECRET_HERE",
        redirect_uri: "https://gitlab.digitalflow.ru/users/auth/openid_connect/callback"
      }
    }
  }
]

# Применяем конфигурацию
sudo gitlab-ctl reconfigure

Grafana: OIDC-интеграция

# 1. Создаём OIDC-клиент в Keycloak для Grafana
/opt/keycloak/bin/kcadm.sh create clients -r digitalflow \
    -s clientId=grafana \
    -s name="Grafana" \
    -s enabled=true \
    -s protocol=openid-connect \
    -s publicClient=false \
    -s 'redirectUris=["https://grafana.digitalflow.ru/login/generic_oauth"]' \
    -s 'webOrigins=["https://grafana.digitalflow.ru"]' \
    -s standardFlowEnabled=true

# 2. Настраиваем Grafana (grafana.ini)
# /etc/grafana/grafana.ini
[auth.generic_oauth]
enabled = true
name = ДиджиталФлоу SSO
allow_sign_up = true
auto_login = false
client_id = grafana
client_secret = GRAFANA_CLIENT_SECRET_HERE
scopes = openid profile email roles
auth_url = https://auth.digitalflow.ru/realms/digitalflow/protocol/openid-connect/auth
token_url = https://auth.digitalflow.ru/realms/digitalflow/protocol/openid-connect/token
api_url = https://auth.digitalflow.ru/realms/digitalflow/protocol/openid-connect/userinfo
role_attribute_path = contains(realm_access.roles[*], 'grafana-admin') && 'Admin' || contains(realm_access.roles[*], 'grafana-editor') && 'Editor' || 'Viewer'
allow_assign_grafana_admin = true

[auth]
oauth_auto_login = false
disable_login_form = false  # Оставляем локальный вход для admin

Обратите внимание на role_attribute_path — это JMESPath-выражение, которое маппит роли Keycloak на роли Grafana. Группа devops в LDAP автоматически получает роль grafana-admin в Keycloak, что транслируется в Admin-доступ в Grafana.

Nextcloud: OIDC-интеграция

# 1. Создаём OIDC-клиент в Keycloak для Nextcloud
/opt/keycloak/bin/kcadm.sh create clients -r digitalflow \
    -s clientId=nextcloud \
    -s name="Nextcloud" \
    -s enabled=true \
    -s protocol=openid-connect \
    -s publicClient=false \
    -s 'redirectUris=["https://cloud.digitalflow.ru/apps/oidc_login/oidc"]' \
    -s 'webOrigins=["https://cloud.digitalflow.ru"]' \
    -s standardFlowEnabled=true

# 2. Устанавливаем и настраиваем приложение oidc_login в Nextcloud
# Через occ:
sudo -u www-data php /var/www/nextcloud/occ app:install oidc_login

# config.php
'oidc_login_client_id' => 'nextcloud',
'oidc_login_client_secret' => 'NEXTCLOUD_CLIENT_SECRET',
'oidc_login_provider_url' => 'https://auth.digitalflow.ru/realms/digitalflow',
'oidc_login_auto_redirect' => false,
'oidc_login_logout_url' => 'https://auth.digitalflow.ru/realms/digitalflow/protocol/openid-connect/logout?client_id=nextcloud&post_logout_redirect_uri=https://cloud.digitalflow.ru',
'oidc_login_button_text' => 'Войти через SSO',
'oidc_login_hide_password_form' => false,
'oidc_login_attributes' => [
    'id' => 'preferred_username',
    'name' => 'name',
    'mail' => 'email',
    'groups' => 'groups',
],
'oidc_login_default_group' => 'oidc',
'oidc_create_groups' => true,

Двухфакторная аутентификация и защита от атак

SSO без 2FA — это удобство, которое одновременно создаёт единую точку компрометации. Если злоумышленник получает пароль от Keycloak — он получает доступ ко всем 15 системам. Двухфакторная аутентификация — обязательный компонент.

Настройка TOTP (Google Authenticator / FreeOTP)

# Включаем обязательную 2FA через Authentication Flow
/opt/keycloak/bin/kcadm.sh update realms/digitalflow \
    -s 'otpPolicyType=totp' \
    -s 'otpPolicyAlgorithm=HmacSHA256' \
    -s 'otpPolicyDigits=6' \
    -s 'otpPolicyPeriod=30' \
    -s 'otpPolicyCodeReusable=false' \
    -s 'otpPolicyInitialCounter=0' \
    -s 'otpPolicyLookAheadWindow=1'

# Создаём кастомный Authentication Flow с обязательным OTP
# Admin Console -> Authentication -> Flows -> Create flow
# Flow name: "Browser with Required OTP"
# Steps:
#   1. Cookie (Alternative)
#   2. Identity Provider Redirector (Alternative)
#   3. Forms (Alternative)
#      3.1 Username Password Form (Required)
#      3.2 OTP Form (Required)   <-- Ключевое отличие: Required, а не Conditional

# Назначаем новый flow как Browser Flow
/opt/keycloak/bin/kcadm.sh update realms/digitalflow \
    -s 'browserFlow=Browser with Required OTP'

# При первом входе пользователь увидит экран настройки TOTP:
# 1. Отсканировать QR-код через Google Authenticator / FreeOTP
# 2. Ввести 6-значный код для подтверждения
# 3. Сохранить recovery codes

Мы развернули 2FA поэтапно: первую неделю — необязательная (Conditional), давая сотрудникам время настроить. Со второй недели — обязательная для всех без исключения.

Brute Force Protection

# Настройка защиты от перебора паролей (уже включено при создании realm)
/opt/keycloak/bin/kcadm.sh update realms/digitalflow \
    -s bruteForceProtected=true \
    -s failureFactor=5 \
    -s maxDeltaTimeSeconds=43200 \
    -s maxFailureWaitSeconds=900 \
    -s minimumQuickLoginWaitSeconds=60 \
    -s waitIncrementSeconds=60 \
    -s quickLoginCheckMilliSeconds=1000 \
    -s permanentLockout=false

# Параметры:
# failureFactor=5 — блокировка после 5 неудачных попыток
# maxFailureWaitSeconds=900 — максимальное время блокировки 15 минут
# waitIncrementSeconds=60 — увеличение времени блокировки с каждой попыткой
# permanentLockout=false — не блокировать навсегда (иначе DoS)

# Дополнительно: настройка Content Security Policy
/opt/keycloak/bin/kcadm.sh update realms/digitalflow \
    -s 'browserSecurityHeaders.contentSecurityPolicy="frame-src '\''self'\''; frame-ancestors '\''self'\''; object-src '\''none'\'';"' \
    -s 'browserSecurityHeaders.xContentTypeOptions=nosniff' \
    -s 'browserSecurityHeaders.xRobotsTag=none' \
    -s 'browserSecurityHeaders.strictTransportSecurity=max-age=31536000; includeSubDomains'

Кастомная тема авторизации

Страница логина — «лицо» SSO. Мы разработали кастомную тему с логотипом и цветами ДиджиталФлоу:

# Структура темы Keycloak
/opt/keycloak/themes/digitalflow-theme/
├── login/
│   ├── theme.properties
│   ├── resources/
│   │   ├── css/
│   │   │   └── login.css
│   │   └── img/
│   │       ├── logo.svg
│   │       └── bg.jpg
│   └── messages/
│       └── messages_ru.properties
├── account/
│   └── theme.properties
└── email/
    ├── theme.properties
    └── messages/
        └── messages_ru.properties

# /opt/keycloak/themes/digitalflow-theme/login/theme.properties
parent=keycloak.v2
import=common/keycloak
styles=css/login.css
locales=en,ru

# /opt/keycloak/themes/digitalflow-theme/login/resources/css/login.css
:root {
    --pf-v5-global--primary-color--100: #2563eb;  /* Brand blue */
    --pf-v5-global--primary-color--200: #1d4ed8;
}

.login-pf body {
    background: url('../img/bg.jpg') no-repeat center center fixed;
    background-size: cover;
}

#kc-header-wrapper {
    font-family: 'Inter', sans-serif;
    font-size: 28px;
    color: #ffffff;
    text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}

/* Custom logo */
.kc-logo-text {
    background-image: url('../img/logo.svg');
    background-size: contain;
    width: 200px;
    height: 60px;
}

# Русификация кнопки логина
# messages_ru.properties
loginAccountTitle=Вход в систему ДиджиталФлоу
loginTitle=Единый вход (SSO)
doLogIn=Войти
usernameOrEmail=Имя пользователя или email

High Availability и резервное копирование

SSO-сервер — критический компонент инфраструктуры. Если Keycloak недоступен, ни один сотрудник не может войти ни в одну систему. Мы обеспечили высокую доступность и надёжное резервное копирование.

Кластер Keycloak с PostgreSQL

Для HA мы развернули два экземпляра Keycloak за load balancer с общей базой PostgreSQL (которая, в свою очередь, работает в режиме streaming replication):

# docker-compose.ha.yml — расширение для HA
version: '3.9'

services:
  keycloak-1:
    image: quay.io/keycloak/keycloak:26.0
    command: start
    environment:
      # ... (общие переменные из основного compose)
      KC_CACHE: ispn
      KC_CACHE_STACK: tcp
      JAVA_OPTS_APPEND: >-
        -Djgroups.dns.query=keycloak-headless
        -Djgroups.dns.record=A
    networks:
      - keycloak-net

  keycloak-2:
    image: quay.io/keycloak/keycloak:26.0
    command: start
    environment:
      # ... (идентичные переменные)
      KC_CACHE: ispn
      KC_CACHE_STACK: tcp
      JAVA_OPTS_APPEND: >-
        -Djgroups.dns.query=keycloak-headless
        -Djgroups.dns.record=A
    networks:
      - keycloak-net

  nginx:
    # Load balancer между keycloak-1 и keycloak-2
    volumes:
      - ./nginx-ha.conf:/etc/nginx/nginx.conf:ro

# nginx-ha.conf — upstream с обоими экземплярами
# upstream keycloak_backend {
#     least_conn;
#     server keycloak-1:8080;
#     server keycloak-2:8080;
# }

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

Резервное копирование и disaster recovery

#!/bin/bash
# /opt/keycloak/scripts/backup.sh
# Ежедневный бэкап Keycloak (БД + конфигурация + темы)

DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backup/keycloak/${DATE}"
mkdir -p "${BACKUP_DIR}"

# 1. Дамп PostgreSQL
docker compose -f /opt/keycloak/docker-compose.yml exec -T postgres \
    pg_dump -U keycloak -Fc keycloak > "${BACKUP_DIR}/keycloak_db.dump"

# 2. Экспорт realm через Keycloak CLI
docker compose -f /opt/keycloak/docker-compose.yml exec -T keycloak \
    /opt/keycloak/bin/kc.sh export --dir /tmp/export --realm digitalflow
docker compose -f /opt/keycloak/docker-compose.yml cp keycloak:/tmp/export "${BACKUP_DIR}/realm-export/"

# 3. Копия кастомных тем и провайдеров
cp -r /opt/keycloak/themes "${BACKUP_DIR}/themes/"
cp -r /opt/keycloak/providers "${BACKUP_DIR}/providers/"

# 4. Docker Compose файлы
cp /opt/keycloak/docker-compose.yml "${BACKUP_DIR}/"
cp /opt/keycloak/.env "${BACKUP_DIR}/"

# 5. Сжимаем
tar czf "/backup/keycloak/keycloak_${DATE}.tar.gz" -C "${BACKUP_DIR}" .
rm -rf "${BACKUP_DIR}"

# 6. Удаляем бэкапы старше 30 дней
find /backup/keycloak -name '*.tar.gz' -mtime +30 -delete

echo "Backup completed: keycloak_${DATE}.tar.gz ($(du -h /backup/keycloak/keycloak_${DATE}.tar.gz | awk '{print $1}'))"

# Crontab: 0 3 * * * /opt/keycloak/scripts/backup.sh >> /var/log/keycloak-backup.log 2>&1

Автоматизация жизненного цикла пользователей

Ключевая боль клиента — уволенные сотрудники с активными аккаунтами. С Keycloak эта проблема решается централизованно: деактивация в LDAP автоматически блокирует доступ ко всем 15 системам.

Onboarding: подключение нового сотрудника

#!/bin/bash
# /opt/scripts/onboard_user.sh
# Создание пользователя в LDAP (автоматически синхронизируется в Keycloak)

USERNAME=$1
FULLNAME=$2
EMAIL=$3
DEPARTMENT=$4  # developers, devops, analysts, managers

# 1. Создаём пользователя в LDAP
ldapadd -x -D "cn=admin,dc=digitalflow,dc=local" -W <

Offboarding: блокировка уволенного сотрудника

#!/bin/bash
# /opt/scripts/offboard_user.sh
# Блокировка пользователя — одна команда закрывает доступ ко ВСЕМ системам

USERNAME=$1

# 1. Блокируем в LDAP
ldapmodify -x -D "cn=admin,dc=digitalflow,dc=local" -W <

Ключевой момент: одна команда блокирует доступ сотрудника ко всем 15 системам одновременно. Никаких забытых аккаунтов — проблема, которая мучила ДиджиталФлоу годами, решена архитектурно.

Результаты внедрения: один пароль — пятнадцать систем

Проект занял 3 недели: одна неделя на развёртывание Keycloak и LDAP-федерацию, две недели на последовательную интеграцию 15 систем и тестирование. Результаты через 2 месяца эксплуатации:

МетрикаДо (локальные учётки)После (Keycloak SSO)
Время onboarding нового сотрудника4–6 часов (ручное создание аккаунтов)15 минут (1 учётка в LDAP)
Время offboarding1–3 дня (забывали системы)2 минуты (1 команда)
Активные аккаунты уволенных23 обнаружено на аудите0 (автоматическая блокировка)
Запросы «забыл пароль» в IT-поддержку30–40 в неделю3–5 в неделю
Количество паролей на сотрудника15 (по одному на систему)1 + TOTP
Двухфакторная аутентификацияНе использовалась100% сотрудников
Среднее время входа в систему15–30 сек (вспомнить пароль)5 сек (SSO + TOTP)
«Новый разработчик открывает ноутбук, входит один раз — и у него доступ к GitLab, Grafana, Mattermost, Jenkins. Раньше он первый день создавал аккаунты, второй — спрашивал пароли у коллег. Теперь — сразу к работе» — CISO ДиджиталФлоу.

Помимо удобства, значительно улучшилась безопасность: 100% покрытие 2FA, нулевой остаточный доступ уволенных, централизованный аудит-лог всех аутентификаций через Keycloak Events.

Рекомендации при внедрении SSO

  • Начните с инвентаризации — составьте полный список систем и проверьте поддержку OIDC/SAML до выбора IdP
  • OIDC предпочтительнее SAML — проще в настройке, лучше документирован, лучше поддерживается современными приложениями
  • 2FA с первого дня — SSO без двухфакторной аутентификации создаёт единую точку компрометации
  • Не отключайте локальный вход сразу — оставьте возможность локального входа для admin-аккаунтов на случай недоступности Keycloak
  • Тестируйте offboarding — заблокируйте тестового пользователя и проверьте, что доступ пропадает во всех 15 системах
  • HA обязательна — SSO-сервер нельзя терять: его недоступность блокирует всю компанию

Развитие проекта

Следующие шаги, согласованные с ДиджиталФлоу:

  • Q2 2026 — WebAuthn (аппаратные ключи YubiKey) для администраторов и DevOps
  • Q3 2026 — Conditional Access Policies: ограничение входа по геолокации и доверенным устройствам
  • Q4 2026 — интеграция с HR-системой для полной автоматизации onboarding/offboarding (создание учётки при оформлении трудового договора)
  • 2027 — переход на Passkeys (FIDO2) для полного отказа от паролей

Часто задаваемые вопросы

Active Directory — это служба каталогов и аутентификации Microsoft, работающая по протоколам Kerberos и LDAP, ориентированная на Windows-инфраструктуру. Keycloak — Identity Provider (IdP), который работает по протоколам OIDC и SAML 2.0, ориентированным на веб-приложения. Keycloak не заменяет AD, а дополняет: он федерирует пользователей из LDAP/AD и предоставляет SSO для веб-приложений, которые AD напрямую не поддерживает. Идеальная связка — AD/LDAP как источник пользователей, Keycloak как IdP для веб-приложений.

Если Keycloak недоступен, новые входы в подключённые системы будут невозможны — пользователи увидят ошибку при попытке аутентификации. Однако уже авторизованные сессии (с действующими токенами) продолжат работать до истечения срока токена (обычно 5–30 минут). Именно поэтому HA для Keycloak обязательна: два и более экземпляра за балансировщиком, PostgreSQL с репликацией. Дополнительно рекомендуется сохранить локальный вход для администраторов в критических системах.

Один экземпляр Keycloak на сервере с 4 ГБ RAM и 2 vCPU обрабатывает около 500–1000 аутентификаций в минуту. Для компании на 200 сотрудников этого более чем достаточно: утренний пик — когда все приходят на работу и входят в системы — это максимум 200 аутентификаций за 30 минут. Для крупных организаций (тысячи пользователей) Keycloak масштабируется горизонтально: несколько экземпляров с общей БД и репликацией кэша через Infinispan.

Да. Keycloak распространяется под лицензией Apache License 2.0 — полностью бесплатен для коммерческого использования без ограничений по числу пользователей, realm или клиентов. Red Hat предлагает коммерческую версию — Red Hat build of Keycloak (ранее Red Hat SSO / RH-SSO) — с официальной поддержкой, SLA и сертификацией. Для большинства компаний community-версии достаточно, а support можно получить от сообщества и специализированных интеграторов.

Keycloak поддерживает Identity Brokering — возможность делегировать аутентификацию внешнему IdP. Это позволяет мигрировать постепенно: Keycloak выступает «зонтичным» IdP, а существующий провайдер подключается как Identity Provider. Пользователи входят через Keycloak, который перенаправляет их на старый IdP для аутентификации. По мере переноса систем на Keycloak зависимость от старого IdP уменьшается, и в итоге его можно полностью отключить.

Нужна помощь с настройкой?

Специалисты АйТи Фреш помогут с внедрением и настройкой — 15+ лет опыта, обслуживание от 15 000 ₽/мес

📞 Связаться с нами
#Keycloak SSO настройка#Keycloak Docker установка#Keycloak OIDC SAML#Keycloak LDAP federation#Keycloak 2FA TOTP#Keycloak brute force protection#Keycloak GitLab интеграция#Keycloak Grafana SSO