Привет всем! В предыдущей статье мы подробно рассмотрели реализацию непрерывной доставки CD в платформе Gitorion на базе Jenkins. В данной статье мы подробно рассмотрим тонкости внедрения системы единого входа Single Sign-On (SSO) во все сервисы платформы Gitorion при помощи Keycloak.

Обоснование необходимости внедрения

Платформа Gitorion состоит из сервисов, реализующих CI/CD, мониторинг и управление базами данных:

  • Gitea/Forgejo - легковесный хостинг кода и система контроля версий на базе Git;

  • Jenkins - непрерывная доставка CD;

  • Grafana - мониторинг и визуализация метрик Prometheus;

  • phpMyAdmin - управление базой данных MySQL;

  • pgAdmin - управление базой данных PostgreSQL.

Итого, базовый набор из 5-ти сервисов, каждый из которых имеет собственную систему аутентификации и базу данных пользователей. При небольшом числе участников проекта можно создавать логины пользователей в каждом из пяти сервисов отдельно. При большом количестве пользователей, задача станет невыполнимой. Требуется единая система аутентификации и база данных пользователей. Приняли решение реализовать единый вход Single Sign-On (SSO) при помощи Keycloak.

Принцип работы Keycloak

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

Область (Realm)

Адаптеры разных сервисов (в нашем случае все пять сервисов платформы Gitorion) объединяются в одну область (Realm). Залогинившись в Web-интерфейсе любого из сервисов, подключенного в область Realm, пользователь получает от Keycloak токен, который записывается в Cookie браузера. В Web-интерфейсы всех остальных сервисов, чьи адаптеры подключены в ту же область, пользователь ходит токеном, без необходимости повторно вводить логин и пароль. Так и реализуется механизм бесшовной аутентификации и единого входа SSO.

Залогиньтесь в консоль администратора Keycloak Administration Console.

Главное окно Keycloak
Главное окно Keycloak

В селекторе выбора областей вверху слева нажмите кнопку "Create realm".

Список областей в Keycloak
Список областей в Keycloak

В минимуме достаточно задать только имя области "Realm name" и нажать кнопку Create.

Создайте область Realm в Keycloak
Создайте область Realm в Keycloak

Подключаем клиент (адаптер) приложения к Keycloak

Адаптерами оснащены из коробки 4 сервиса из 5ти - Gitea/Forgejo, Jenkins, Grafana и pgAdmin. Ниже мы рассмотрим для примера подключение адаптера Gitea/Forgejo к Keycloak. Адаптеры остальных сервисов хорошо документированы и подключаются аналогично. phpMyAdmin не имеет под капотом адаптера Keycloak. Подключение приложений, не имеющих адаптера Keycloak или вообще не защищенных окном аутентификации, мы рассмотрим ниже.

Выберите созданную выше область, перейдите в меню Clients и нажмите кнопку "Create client".

Создайте клиент Gitea/Forgeo в Keycloak
Создайте клиент Gitea/Forgeo в Keycloak

Задайте "Client ID" – это уникальный идентификатор клиента (адаптера). Нажмите кнопку Next.

Параметры клиента (адаптера) Gitea/Forgejo
Параметры клиента (адаптера) Gitea/Forgejo

В следующем окне включите "Client authentication" и нажмите кнопку Next.

Включите аутентификацию в настройках клиента (адаптера) Keycloak
Включите аутентификацию в настройках клиента (адаптера) Keycloak

В "Root URL" задайте URL приложения, на который пользователь будет перенаправлен в случае удачной аутентификации в Keycloak. Нажмите кнопку Save.

Задайте URL приложения для обратного перенаправления из Keycloak
Задайте URL приложения для обратного перенаправления из Keycloak

После того, как будет создан клиент, перейдите на вкладу Credentials и скопируйте "Client Secret", который потребуется ниже при настройке Gitea/Forgejo. Данным ключом клиент Gitea/Forgejo будет подтверждать свою подлинность при подключении к Keycloak.

Ключ доступа клиента (адаптера) Gitea/Forgejo к Keycloak
Ключ доступа клиента (адаптера) Gitea/Forgejo к Keycloak

Переходим к настройке Gitea/Forgejo. Залогиньтесь в Gitea/Forgejo пользователем с административными правами и перейдите в панель управления.

Меню администратора в Gitea/Forgejo
Меню администратора в Gitea/Forgejo

Перейдите в "Identity & Access" подменю Аутентификация и нажмите кнопку "Добавить новый источник".

Добавьте новый источник аутентификации в Gitea/Forgejo
Добавьте новый источник аутентификации в Gitea/Forgejo

В поле "ID клиента (ключ)" задайте значение, которое ввели выше при настройке клиента в Keycloak в поле "Client ID". В поле "Клиентский ключ" задайте значение "Client Secret", скопированное выше из вкладки Credentials настроек клиента в Keycloak. В поле "URL иконки" задайте пиктограмму, которая будет отображаться на окне аутентификации Gitea/Forgejo напротив кнопки "Войти с помощью keycloak".

Параметры источника аутентификации Keycloak в Gitea/Forgejo
Параметры источника аутентификации Keycloak в Gitea/Forgejo

"Open ID Connect URL для автоматизации входа" возьмите в меню настроек "Realm Settings", скопировав ссылку "Open ID Endpoint Configuration" в Keycloak.

Ссылка на параметры Endpoint Keycloak
Ссылка на параметры Endpoint Keycloak

Нажмите кнопку "Добавить новый источник" в Gitea/Forgejo и будет создан новый источник аутентификации, привязанный к Keycloak. На странице аутентификации Gitea/Forgejo появится кнопка "Войти с помощью keycloak".

Кнопка входа через Keycloak на интерфейсе Gitea/Forgejo
Кнопка входа через Keycloak на интерфейсе Gitea/Forgejo

Пользователь нажимает на кнопку "Войти с помощью keycloak", и его перенаправляет на окно аутентификации Keycloak.

Окно аутентификации в Keycloak
Окно аутентификации в Keycloak

Пользователь вводит логин и пароль, и в случае удачной аутентификации Keycloak перенаправляет пользователя в его личный кабинет в Gitea/Forgejo.

Личный кабинет пользователя в Gitea/Forgejo
Личный кабинет пользователя в Gitea/Forgejo

А в Keycloak появится сессия пользователя.

Активная сессия пользователя в Keycloak
Активная сессия пользователя в Keycloak

База данных логинов и групп пользователей

Keycloak может как самостоятельно хранить в собственной базе данных логины, пароли и прочую информацию о пользователях, так и выступать в качестве провайдера к внешним источникам аутентификации, вроде Microsoft Active Directory, LDAP и т.д. В нашем случае внешний источник аутентификации не потребовался, и мы создали логины и группы пользователей прямо в Keycloak.

Зайдите в консоль администратора Keycloak, выберите область и перейдите в меню Groups. В нашем случае мы разделили всех пользователей на две группы:

  • admins - пользователи с административными правами во всех сервисах (для тимлидов);

  • devs - пользователи с правами только на чтение (для разработчиков).

Группы пользователей в Keycloak
Группы пользователей в Keycloak

Нажмите кнопку "Create group" и введите имя группы.

Создайте группу пользователей в Keycloak
Создайте группу пользователей в Keycloak

Нажмите кнопку Create. Повторите те же действия и создайте группу devs.

Далее, для примера создадим пользователя owneruser и добавим его в группу admins. А также пользователя user1 и добавим его в группу devs. Перейдите в меню Users и нажмите кнопку "Add users".

Пользователи в Keycloak
Пользователи в Keycloak

Введите данные пользователя. Обязательно задайте e-mail (Grafana использует e-mail пользователя вместо логина для аутентификации).

Параметры пользователя
Параметры пользователя

Нажмите кнопку "Join Groups", добавьте пользователя в группу admins и нажмите кнопку Join.

Добавьте пользователя в группу
Добавьте пользователя в группу

Нажмите кнопку Create, чтобы создать пользователя. Аналогично создайте пользователя user1 и добавьте его в группу devs.

Авторизация на базе ролей Roles

Авторизация и разграничение полномочий потребовалась в Jenkins и Grafana. Тимлидам нужно было предоставить полный доступ, чтобы они могли создавать пайплайны в Jenkins и дашборды в Grafana. А разработчикам дать права только на чтение, чтобы они могли наблюдать за своими пайплайнами и мониторить нагрузку по дашбордам в Grafana.

Залогиньтесь в консоль администратора Keycloak, перейдите в меню "Realm roles".

Список ролей Roles области
Список ролей Roles области

Нажмите кнопку "Create role". В следующем окне задайте имя роли и нажмите кнопку Save.

Параметры создаваемой роли
Параметры создаваемой роли

Перейдите в меню Groups, выберите группу admins и перейдите на вкладку "Role mapping".

Вкладка ролей группы
Вкладка ролей группы

Нажмите кнопку "Assign role", выберите роль admins и нажмите кнопку Assign.

Ассоциируйте роль с группой
Ассоциируйте роль с группой

Аналогично ассоциируйте группу devs с ролью devs. Теперь в случае удачной авторизации Keycloak среди прочей информации о пользователе передаст еще и роль пользователя в сервис, из которого пришел аутентифицироваться пользователь. И сервис сможет выполнить авторизацию пользователя и назначить полномочия в соответствии с его ролью. Информацию о клиенте Keycloak передает в Scopes, список которых можно посмотреть в меню "Client scopes".

Список Scopes области
Список Scopes области

Среди прочих Scopes по умолчанию есть roles.

Настройте разграничение полномочий на основе ролей в Jenkins. Перейдите в настройках Jenkins в раздел "Manage and Assign Roles" и выберите подпункт "Maname Roles". В появившемся окне в поле "Role to add" введите имя роли admins и нажмите кнопку Add. Аналогично добавьте роль devs. В матрице доступа установите для роли admins галочку Administer в столбце Полные, а для роли devs галочки Read в столбцах Полные и Задача.

Настройка ролей в Jenkins
Настройка ролей в Jenkins

Залогиньтесь в Jenkins пользователем owneruser из группы admins, и вам будет доступен пункт добавления пайплайнов "+ Создать Item" и пункт настроек "Настроить Jenkins".

Личный кабинет пользователя с административными правами в Jenkins
Личный кабинет пользователя с административными правами в Jenkins

Залогиньтесь пользователем user1, и пункты создания пайплайнов и настроек Jenkins исчезнут. Останется возможность только посмотреть информацию о пайплайнах.

Личный кабинет пользователя с правами только на чтение в Jenkins
Личный кабинет пользователя с правами только на чтение в Jenkins

Для Grafana нужно в файле конфигурации grafana.ini ассоциировать роли Keycloak со встроенными ролями Grafana.

role_attribute_path: contains(realm_access.roles[], 'admins') && 'Admin' || contains(realm_access.roles[], 'editor') && 'Editor' || 'Viewer'

Роль admins из Keycloak ассоциируйте с ролью Admin из Grafana. Все остальные роли ассоциируются с ролью Viewer в Grafana.

Залогиньтесь в Grafana через Keycloak пользователем owneruser из группы admins, и вы получите полный доступ к настройкам Grafana.

Личный кабинет пользователя с административными правами в Grafana
Личный кабинет пользователя с административными правами в Grafana

У пользователя user1 из группы devs права только на чтение, а пункт Administration в меню отсутствует.

Личный кабинет пользователя с правами только на чтение в Grafana
Личный кабинет пользователя с правами только на чтение в Grafana

Аутентификация приложений без адаптера

Некоторые приложения не имеют под капотом адаптера Keycloak, а порой и вообще не защищены окном аутентификации. Закрыть такие приложения логином и паролем и настроить для них аутентификацию через Keycloak можно с помощью модуля mod_auth_openidc в составе apache2. В этом случае с Keycloak взаимодействует сервер apache2 и реализует аутентификацию для Location, в котором и нужно расположить приложение, требующее аутентификации. Таким приложением в нашем случае оказался phpMyAdmin, который имеет собственную аутентификацию, но не имеет клиента Keycloak. Разработчики предлагают реализовать SSO самостоятельно, используя данный скрипт.

В конфигурационном файле config.inc.php для phpMyAdmin переключите стандартную аутентификацию с помощью логина и пароля на аутентификацию с помощью скрипта signon.php

$cfg['Servers'][$i]['auth_type']     = 'signon';
$cfg['Servers'][$i]['SignonSession'] = 'SignonSession';
$cfg['Servers'][$i]['SignonURL']     = 'examples/signon.php';

И настройте Location для phpMyAdmin в apache2

LoadModule auth_openidc_module modules/mod_auth_openidc.so

ServerName gitrion.ru

<VirtualHost *:80>

    ServerName phpmyadmin
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html/
    DirectoryIndex examples/signon.php

    OIDCProviderMetadataURL https://auth.gitorion.ru/realms/gitrion/.well-known/openid-configuration
    OIDCRedirectURI /redirect_uri
    OIDCDefaultURL https://phpmyadmin.staging.gitorion.ru:443/
    OIDCCryptoPassphrase 0123456789
    OIDCClientID phpmyadmin
    OIDCClientSecret 2jb0IUaoAfYUxPpAuJSwtcF2EEMEMdOb

    OIDCRemoteUserClaim preferred_username

    OIDCXForwardedHeaders X-Forwarded-Host
    OIDCXForwardedHeaders X-Forwarded-Port
    OIDCXForwardedHeaders X-Forwarded-Proto

    <Location />
    FallbackResource index.php
    DirectoryIndex index.php
        AuthType openid-connect
        Require valid-user
    </Location>

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>

При переходе на Web-интерфейс phpMyAdmin пользователь перенаправляется на окно аутентификации Keycloak. В случае удачной аутентификации Keycloak перенаправит пользователя в личный кабинет phpMyAdmin.

Личный кабинет пользователя в phpMyAdmin
Личный кабинет пользователя в phpMyAdmin

Browser Flow и ограничение доступа в пределах области на базе ролей Roles

Адаптеры Web-интерфейсов Gitea/Forgejo, Jenkins, Grafana и Web-интерфейсов баз данных phpMyAdmin и pgAdmin для контуров development, staging и production находятся в одной области. Разработчик, залогинившись в любом из Web-интерфейсов платформы, получит доступ к Web-интерфейсам управления базами данных в контуре development, а так же в контурах staging и production. Что недопустимо! Закрыть доступ разработчикам к Web-интерфейсам баз данных в контурах staging и production удалось, добавив в Browser Flow для клиентов (адаптеров) phpMyAdmin и pgAdmin проверку доступа на базе ролей Roles. Browser Flow задает порядок проверки параметров доступа клиента. По умолчанию, сначала проверяется наличие токена в Cookei. Если пользователь ранее залогинился и у него есть токен, то пользователю предоставляется доступ к сервису. Если нет, то предлагается ввести логин и пароль. Мы создали кастомный Browser Flow на базе дефолтного, который после проверки токена в Cookie и логина с паролем, проверяет еще и роль Role пользователя и запрещает доступ пользователям с ролью devs к Web-интерфейсам баз данных в контурах staging и production.

Залогиньтесь в административную консоль Keycloak, выберите область, перейдите в меню Configure, подменю Authentication, нажмите пиктограмму с тремя точками справа от Flow с именем browser и нажмите кнопку Duplicate.

Список Flows области
Список Flows области

Задайте имя кастомного Flow и нажмите кнопку Dupliacate.

Продублируйте browser Flow
Продублируйте browser Flow

Перейдите в Flow browser-custom и добавьте Sub-flow с именем RBAC в browser-custom forms.

Добавьте Sub-flow RBAC проверки доступа на базе ролей Roles
Добавьте Sub-flow RBAC проверки доступа на базе ролей Roles

В Sub-flow RBAC добавьте Condition user-role.

Добавьте Condition user role
Добавьте Condition user role

Нажмите на шестеренку справа от Condition user-role, задайте Alias и свяжите с ролью devs.

Свяжите Condition user role с ролью devs
Свяжите Condition user role с ролью devs

Добавьте Step Deny Access

Step Deny Access
Step Deny Access

Нажмите шестеренку справа от Step Deny Access, задайте Alias и текст сообщения, которое будет выдано пользователю из группы devs при попытке доступа к базам данных в контурах staging и production.

Сообщение об ошибке
Сообщение об ошибке

Подключите кастомный Flow browser-custom к клиентам (адаптерам) phpMyAdmin и pgAdmin в контурах staging и production. Перейдите в настройках клиента на вкладку Advanced, спуститесь в самый низ и в поле Browser Flow задайте browser-custom.

Задайте кастомный Browser Flow
Задайте кастомный Browser Flow

При попытке доступа пользователя с ролью devs к Web-интерфейсу базы данных в контурах staging или production появится предупреждение.

Сообщение об ошибке доступа
Сообщение об ошибке доступа

Заключение

В данной статье мы осветили свой опыт реализации единого входа Single Sign-On (SSO) во все сервисы платформы Gitorion при помощи Keycloak. Будем рады обратной связи, замечаниям и конструктивной критике. Спасибо.

Комментарии (0)