Как я KeyCloak побеждал

в 12:34, , рубрики: ActiveDirectory, devops, keycloak, tutorial
Как я себя чувствовал

Как я себя чувствовал

Привет! Меня зову Амир и я хотел бы сегодня поделиться с Вами своим опытом поднятия сервиса SSO на базе решения KeyCloak.

Вводные:

Требования со стороны бизнеса:

  • Для внутренних сервисов компании требуется единая точка входа с подключением пользователей из существующей Active Directory.

  • Требуется что бы пользователь мог иметь доступ к одному или нескольким сервисам (в каждом из сервисов имел одну или несколько ролей). Если доступ к тому или иному сервису отсутствует, сообщать ему об этом.

Требования взаимодействия с КС

  • KC должен работать по https.

  • На стороне фронта будет использоваться пакет от KC https://www.npmjs.com/package/keycloak-js.

  • Возможность отправлять события в Kafka

Требования развертки

  • KC должен быть развернут в Docker с помощью Docker compose

Версия KC: 25.0.2, так же проверял на версии 26.0.0 (тоже норм)

Ну вот с вводными разобрались, теперь приступим к реализации.

Build and deploy

Dockerfile

FROM keycloak/keycloak:25.0.2
COPY keycloak-kafka-1.1.5.jar /opt/keycloak/providers/

ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]

Для подключения Kafka к CK используем keycloak-kafka-1.1.5

Dokcer-compose.yaml

version: "3.9"

services:
  keycloak:
    image: my_docker_hub/keycloak:latest
    volumes:
      - ./themes:/opt/keycloak/themes
      - ./cert/cert.jks:/etc/x509/https/truststore.jks
    container_name: keycloak
    ports:
      - "8443:8443"
    env_file: ./.env
    command: start
    depends_on:
      keycloak-postgres:
        condition: service_healthy
    healthcheck:
      test:
        [
          "CMD-SHELL",
          "exec 3<>/dev/tcp/127.0.0.1/9000;echo -e 'GET /health/ready HTTP/1.1rnhost: http://localhostrnConnection: closernrn' >&3;if [ $? -eq 0 ]; then echo 'Healthcheck Successful';exit 0;else echo 'Healthcheck Failed';exit 1;fi;",
        ]
      start_period: 10s
      interval: 30s
      retries: 3
      timeout: 5s

  keycloak-postgres:
    container_name: keycloak-postgres
    image: postgres
    volumes:
      - ./db/data:/var/lib/postgresql/data
    env_file: ./.env
    healthcheck:
      test: pg_isready -d postgres
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 5s

.env

KC_FEATURES: preview
KC_HEALTH_ENABLED: true
KC_METRICS_ENABLED: true

KC_HOSTNAME: host_keycloak
KC_HTTPS_PORT: 8443
KC_HTTPS_KEY_STORE_PASSWORD=STORE_PASSWORD
KC_HTTPS_KEY_STORE_FILE=/etc/x509/https/truststore.jks
KC_PROXY_HEADERS: xforwarded

KEYCLOAK_ADMIN: admin 
KEYCLOAK_ADMIN_PASSWORD: admin

KAFKA_TOPIC: user.event.user
KAFKA_ADMIN_TOPIC: user.event.admin
KAFKA_CLIENT_ID: keycloak
KAFKA_BOOTSTRAP_SERVERS: BOOTSTRAP_SERVERS
KAFKA_EVENTS: LOGIN,LOGOUT

KC_DB: postgres
KC_DB_URL: jdbc:postgresql://keycloak-postgres:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: keycloak
KC_DB_SCHEMA: public

POSTGRES_DB: keycloak
PGUSER: keycloak
POSTGRES_USER : keycloak
POSTGRES_PASSWORD : keycloak
PGPASSWORD: password

Процесс сборки и развертывания опускаю, т.к. там ничего интересного нет.

Настраиваем HTTPS (В моем случае у меня есть root cert)

На этом моменте я прям залип знатно, т.к. в интернетах приводятся вагон вариаций исполнения, но к сожалению много устаревших либо не подходящих по типу сертификата

  1. Копируем root сертификат в /opt/keycloak/cert

  2. Выполняем команды

    keytool -importkeystore -srckeystore cert.pfx -srcstoretype pkcs12 -destkeystore ./cert.jks -deststoretype pkcs12
    cd /opt/keycloak/cert

    Указываем пароль от сертификата cert.pfx и назначаем пароль для keystore

  1. В docker-compose прокидываем cert.jks

volumes:
      - ./cert/cert.jks:/etc/x509/https/truststore.jks
  1. В файле .env

    Прописываем следующие переменные

KC_HOSTNAME: host_keycloak
KC_HTTPS_PORT: 8443
KC_HTTPS_KEY_STORE_PASSWORD=STORE_PASSWORD
KC_HTTPS_KEY_STORE_FILE=/etc/x509/https/truststore.jks
KC_PROXY_HEADERS: xforwarded

После развертывания через Docker compose, можем открывать KC.
https://host_name:8443/

Стартовая страница KC

Стартовая страница KC

Заходим под admin / admin

Подключаем AD

Создаем свой Realm
Идем в User federation и создаем Ldap providers

Как я KeyCloak побеждал - 3

Далее действовал по описанию в статье

https://habr.com/ru/companies/swordfish_security/articles/533264/

Ребятам и Swordfish Security огромное спасибо за статью

По обычаю, принимаясь за задачу по KC хотел уже потратить день другой на блогах и форумах в поисках решения/гайда, как тут уже все написано :-)

Подключаем Kafka

Заходим в Realm settings, переходим в Events, в селекте выбираем kafka

Как я KeyCloak побеждал - 4

Теперь все события произведенные в админе будут отправляться в топик указанный в .env admin, а пользовательские события login/logout в топик user

Настройка Client

Создаем Client

Как я KeyCloak побеждал - 5
Оставляем все настройки как есть

Оставляем все настройки как есть

После создания в настройках обязательно указываем разрешенные URL откуда можем обращаться и т.д.

Как я KeyCloak побеждал - 7

Создаем client scope audience, что бы добавить аудиенцию клиента в токен.

add client scope

add client scope
create client scope

create client scope

Переходим на вкладку Mappers, жмём на Configure a new mapper

Audience

Audience
add mapper

add mapper

Name - указываете как удобно
Included Client Audience - выбираем нашего клиента

Сохраняем.

Добавляем наш scope нашему клиенту

Переходим в меню Clients - вкладка Client scopes - Add client scope

Add client scope

Add client scope

Выбираем наш scope и добавляем с признаком Default

Создание роли доступа для нашего client

Realm roles

Realm roles

Меню - Realm roles - Create role

Можно заполнить подобным образом

Можно заполнить подобным образом

Создание группы пользователей для доступа в наш client

Groups

Groups

Меню - Groups - Create group

Название я предпочитаю задавать для групп доступа = client id

Role mapping

Role mapping

Связываем роль доступа с нашей группой на вкладке Role mapping

Assign roles to my-client account

Assign roles to my-client account

Создание Flow для аутентификации через браузер для нашего клиента

Меню - authentication - Flows - дублируем browser

Как я KeyCloak побеждал - 18
Как я KeyCloak побеждал - 19

Далее формируем следующую структуру

Странно, но не думал что ситуация которую мне нужно было разрешить, настолько редкая и по этой тепе в интернете было совсем мало инфы (нуууу очень мало). Решение нашел на stackoverflow, которое было представлено в виде скрина, которое в итоге было модифицировано :-)

Flow - Required: {  
    name: Login: <Название клиента> 
}
Step - Alternative: Cookie
Step - Alternative: Identity Provider Redirector config 
Flow - Alternative: {  
    name: gated browser form: <Название клиента> 
}

Step - Required: Username Form
Flow - Conditional: {  
    name: gated browser form - Conditional OTP Form config: <Название клиента> 
}
Condition - Required: Condition - user configured
Step - Required: OTP Form
Flow: {  
    name: RBA - Conditiona: <Название клиента> 
}
Condition - Required: Condition - user role
{
    Alias: user role <Название клиента>,
    User role: Выбираем роль созданную для нашего Client,
    Negate output: On
}
Step - Required: Deny access  
{
    Alias: Deny access config <Название клиента>,
    Error message: Доступ в приложение <Название приложения> запрещен
}
Condition - user role config

Condition - user role config
Deny access config

Deny access config
Должно получиться так

Должно получиться так

Далее, указываем наш созданный Flow как основной для Client

advanced

advanced
Как я KeyCloak побеждал - 24

Если сейчас мы попробуем пройти авторизацию в KC через адаптер keycloak-js получим следующий результат

У Вас нет доступа в my-client

У Вас нет доступа в my-client

Добавление пользователя в группу доступа к my-client

Меню - members - Add member - выбираем пользователя из локальной базы или импортированного из AD

Как я KeyCloak побеждал - 26

Далее пробуем пройти авторизацию через адаптер keycloak-js, получим результат "Успешная авторизация" с получением токена и редиректа на страницу указанную в настройках Client.

Итог

В этой мы рассмотрели реализацию авторизации в нашем приложении через популярное SSO ПО KeyCloak. Надеюсь было написано исчерпывающе, т.к. во время настройки всего я испытал много боли и может это кому то поможет.

Спасибо за прочтение.

Автор: AmirALM

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js