CI/CD Kubernetes платформа Gitorion. Единый вход Single Sign-On (SSO) во все сервисы платформы при помощи Keycloak

Привет всем! В предыдущей статье мы подробно рассмотрели реализацию непрерывной доставки 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



    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

    
    FallbackResource index.php
    DirectoryIndex index.php
        AuthType openid-connect
        Require valid-user
    

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


При переходе на 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. Будем рады обратной связи, замечаниям и конструктивной критике. Спасибо.

© Habrahabr.ru