W każdej dużej firmie, w tym również X5 Retail Group, wraz z rozwojem wzrasta liczba projektów, w których wymagana jest autoryzacja użytkowników. W miarę upływu czasu potrzebny jest płynny przeskok użytkowników z jednego aplikacji do drugiej, co rodzi konieczność wykorzystania jednego serwera Single-Sign-On (SSO). Jak jednak postąpić, gdy takie dostawcy tożsamości jak AD lub inne, nie posiadające dodatkowych atrybutów, już funkcjonują w różnych projektach? Z pomocą przychodzą klasy systemów nazywanych „brokerami tożsamości”. Najbardziej funkcjonalni w tej grupie to m.in. Keycloak, Gravitee Access Management itd. Scenariusze użycia mogą być zróżnicowane: interakcja maszynowa, udział użytkowników itd. Rozwiązanie powinno wspierać elastyczną i skalowalną funkcjonalność, która zjednoczy wszystkie wymagania w jednym – obecnie takim rozwiązaniem w naszej firmie jest broker tożsamości – Keycloak.

Keycloak to produkt o otwartym kodzie źródłowym, przeznaczony do identyfikacji i kontroli dostępu, wspierany przez firmę RedHat. Jest podstawą dla produktów firmy, które wykorzystują SSO – RH-SSO.
Podstawowe pojęcia
Zanim zaczniemy analizować rozwiązania i podejścia, należy zdefiniować terminy oraz kolejność procesów:

Identyfikacja — to procedura rozpoznawania podmiotu na podstawie jego identyfikatora (mówiąc prościej, jest to określenie imienia, loginu lub numeru).
Autoryzacja — to procedura weryfikacji autentyczności (użytkownik jest weryfikowany za pomocą hasła, e-mail jest sprawdzany za pomocą podpisu elektronicznego itd.)
Autoryzacja — to udzielenie dostępu do jakiegoś zasobu (na przykład do poczty elektronicznej).
Broker tożsamości Keycloak
Keycloak — to rozwiązanie do zarządzania tożsamością i dostępem o otwartym kodzie źródłowym, przeznaczone do stosowania w systemach informatycznych, w których mogą być wykorzystane wzorce architektury mikrousług.
Keycloak oferuje takie funkcje jak jednolite logowanie (SSO), brokered identity i logowanie za pomocą mediów społecznościowych, federacja użytkowników, adaptery klienckie, konsola administracyjna oraz konsola zarządzania kontami.
Podstawowa funkcjonalność wspierana w Keycloak:
- Single-Sign On i Single-Sign Out dla aplikacji przeglądarkowych.
- Wsparcie dla OpenID/OAuth 2.0/SAML.
- Identity Brokering – autoryzacja z wykorzystaniem zewnętrznych dostawców tożsamości OpenID Connect lub SAML.
- Social Login – wsparcie dla Google, GitHub, Facebook, Twitter w celu identyfikacji użytkowników.
- User Federation – synchronizacja użytkowników z serwerów LDAP i Active Directory oraz innych dostawców tożsamości.
- Kerberos bridge – użycie serwera Kerberos do automatycznej autoryzacji użytkowników.
- Admin Console — do centralnego zarządzania ustawieniami i parametrami rozwiązania przez Web.
- Account Management Console – do samodzielnego zarządzania profilem użytkowników.
- Dostosowanie rozwiązania w oparciu o firmowy styl.
- 2FA Authentication – wsparcie dla TOTP/HOTP z wykorzystaniem Google Authenticator lub FreeOTP.
- Login Flows – możliwość samodzielnej rejestracji użytkowników, odzyskiwania i resetowania hasła oraz inne.
- Session Management – administratorzy mogą zarządzać sesjami użytkowników z jednego miejsca.
- Token Mappers – mapowanie atrybutów użytkowników, ról i innych wymaganych atrybutów w tokenach.
- Elastyczne zarządzanie politykami przez realm, aplikacje i użytkowników.
- Wsparcie CORS – klientowe adaptery mają wbudowane wsparcie CORS.
- Service Provider Interfaces (SPI) – wiele SPI, które pozwalają na konfigurację różnych aspektów pracy serwera: strumieni autoryzacji, dostawców tożsamości, mapowania protokołów i innych.
- Klientowe adaptery dla aplikacji JavaScript, WildFly, JBoss EAP, Fuse, Tomcat, Jetty, Spring.
- Wsparcie dla pracy z różnymi aplikacjami wspierającymi OpenID Connect Relying Party library lub SAML 2.0 Service Provider Library.
- Możliwość rozbudowy z użyciem pluginów.
Dla procesów CI/CD, a także automatyzacji procesów zarządzania w Keycloak, można korzystać z REST API/JAVA API. Dokumentacja dostępna w formie elektronicznej:
REST API
JAVA API
Dostawcy tożsamości na poziomie przedsiębiorstwa (On-Premise)
Możliwość autoryzacji użytkowników przez usługi User Federation.

Można także wykorzystać autoryzację jednolitą – jeśli użytkownicy są autoryzowani na stacjach roboczych z Kerberos (LDAP lub AD), mogą być automatycznie autoryzowani w Keycloak bez potrzeby ponownego podawania swojej nazwy użytkownika i hasła.
Do uwierzytelniania i dalszej autoryzacji użytkowników można wykorzystać relacyjną bazę danych, co jest najbardziej przydatne w środowiskach deweloperskich, ponieważ nie wymaga długotrwałej konfiguracji i integracji na wczesnych etapach projektów. Domyślnie w Keycloak używana jest wbudowana baza danych do przechowywania ustawień i danych o użytkownikach.
Lista wspieranych baz danych jest obszerna i obejmuje: MS SQL, Oracle, PostgreSQL, MariaDB, Oracle i inne. Najbardziej przetestowane do tej pory są Oracle 12C Release1 RAC oraz klaster Galera 3.12 dla MariaDB 10.1.19.
Dostawcy identyfikacji — logowanie społecznościowe
Można korzystać z logowania z mediów społecznościowych. Aby aktywować możliwość uwierzytelniania użytkowników, używana jest konsola administratora Keycloak. Zmiany w kodzie aplikacji nie są wymagane, a ta funkcjonalność jest dostępna 'prosto z pudełka' i może być aktywowana na każdym etapie realizacji projektu.

Do uwierzytelniania użytkowników można wykorzystać dostawców OpenID/SAML Identity.
Typowe scenariusze autoryzacji z wykorzystaniem OAuth2 w Keycloak
Authorization Code Flow — używany z aplikacjami serwerowymi (server-side applications). Jeden z najczęściej stosowanych rodzajów zezwoleń na autoryzację, ponieważ dobrze nadaje się do aplikacji serwerowych, w których kod źródłowy aplikacji i dane klienta nie są dostępne dla osób trzecich. Proces w tym przypadku opiera się na przekierowaniu (redirection). Aplikacja musi być w stanie komunikować się z użytkownikami agentami (user-agent), takimi jak przeglądarka internetowa — otrzymywać kody autoryzacji API przekazywane przez użytkownika agenta.
Implicit Flow — używany w aplikacjach mobilnych lub internetowych (aplikacje działające na urządzeniu użytkownika).
Niejawny typ autoryzacji jest stosowany w aplikacjach mobilnych i internetowych, gdzie poufność klienta nie może być zagwarantowana. Niejawny typ uprawnień wykorzystuje także przekierowanie agenta użytkownika, przy czym token dostępu jest przekazywany agentowi użytkownika do dalszego wykorzystania w aplikacji. Dzięki temu token jest dostępny dla użytkownika i innych aplikacji na urządzeniu. W tym typie autoryzacji nie dokonuje się weryfikacji autentyczności aplikacji, a cały proces polega na URL przekierowania (wcześniej zarejestrowanym w serwisie).
Implicit Flow nie obsługuje tokenów odświeżania (refresh tokens).
Grant typu Client Credentials — jest używany, gdy aplikacja uzyskuje dostęp do API. Ten typ uprawnień zazwyczaj stosuje się w interakcjach 'serwer-serwer', które muszą przebiegać w tle bez bezpośredniego zaangażowania użytkownika. Strumień przyznawania danych uwierzytelniających klienta pozwala usłudze internetowej (poufnemu klientowi) na użycie własnych danych uwierzytelniających zamiast reprezentacji użytkownika do weryfikacji przy wywołaniu innej usługi internetowej. Dla wyższego poziomu bezpieczeństwa możliwe jest, aby wywołująca usługa korzystała z certyfikatu (zamiast ogólnego sekretu) jako danych uwierzytelniających.
Specyfikacja OAuth2 jest opisana w
Token JWT i jego zalety
JWT (JSON Web Token) to otwarty standard (), który definiuje zwarty i samodzielny sposób na zabezpieczoną wymianę informacji między stronami w postaci obiektu JSON.
Zgodnie z definicją token składa się z trzech części w formacie base-64, oddzielonych kropkami. Pierwsza część nazywa się nagłówkiem (header), w którym znajduje się typ tokena i nazwa algorytmu hash służącego do uzyskania podpisu cyfrowego. Druga część przechowuje podstawowe informacje (użytkownik, atrybuty itd.). Trzecia część to podpis cyfrowy.
..
Nigdy nie przechowuj tokenu w swojej bazie danych. Ponieważ ważny token jest równoważny hasłu, przechowywanie tokenu jest równoznaczne z przechowywaniem hasła w otwartej formie.
Access token — to token, który zapewnia dostęp jego właścicielowi do zabezpieczonych zasobów serwera. Zwykle ma krótki czas życia i może zawierać dodatkowe informacje, takie jak adres IP strony, która żąda tego tokena.
Token odświeżania — to token, który pozwala klientom żądać nowych tokenów dostępu po upływie ich czasu życia. Te tokeny są zazwyczaj wydawane na dłuższy okres.
Główne zalety stosowania w architekturze mikroserwisów:
- Możliwość dostępu do różnych aplikacji i usług za pomocą jednolitej autoryzacji.
- W przypadku braku szeregu wymaganych atrybutów w profilu użytkowników istnieje możliwość wzbogacenia danych, które mogą być dodane do ładunku, w tym automatycznie i "na bieżąco".
- Nie ma potrzeby przechowywania informacji o aktywnych sesjach, aplikacja serwerowa musi jedynie sprawdzić podpis.
- Bardziej elastyczne zarządzanie dostępem dzięki dodatkowym atrybutom w ładunku.
- Zastosowanie podpisu tokena dla nagłówka i ładunku zwiększa bezpieczeństwo rozwiązania jako całości.
Token JWT — składa się z
Nagłówek — domyślnie nagłówek zawiera tylko typ tokena i algorytm używany do szyfrowania.
Typ tokena jest przechowywany w kluczu "typ". Klucz "typ" jest ignorowany w JWT. Jeśli klucz "typ" jest obecny, jego wartość powinna być ustawiona na JWT, aby wskazać, że ten obiekt jest tokenem JSON Web.
Drugi klucz "alg" określa algorytm używany do szyfrowania tokena. Domyślnie powinien być ustawiony na HS256. Nagłówek jest kodowany w base64.
{ "alg": "HS256", "typ": "JWT"}
Ładunek (zawartość) — w ładunku przechowywane są wszelkie informacje, które muszą być zweryfikowane. Każdy klucz w ładunku jest znany jako „oświadczenie”. Na przykład, do aplikacji można się zalogować tylko na zaproszenie (zamknięta promocja). Kiedy chcemy zaprosić kogoś do udziału, wysyłamy mu e-mail z zaproszeniem. Ważne jest, aby sprawdzić, że adres e-mail należy do osoby, która przyjmuje zaproszenie, dlatego umieścimy ten adres w ładunku, zapisując go w kluczu "e-mail".
{ "email": "example@x5.ru" }
Klucze w ładunku mogą być dowolne. Niemniej jednak istnieje kilka zarezerwowanych:
- iss (Wydawca) — określa aplikację, z której wysyłany jest token.
- sub (Temat) — definiuje temat tokenu.
- aud (Odbiorca) – tablica wrażliwych na wielkość liter ciągów lub URI, stanowiąca listę odbiorców tego tokenu. Kiedy strona odbierająca otrzymuje JWT z tym kluczem, musi sprawdzić swoją obecność w tym zbiorze — w przeciwnym razie zignoruje token.
- exp (Czas wygaśnięcia) — wskazuje, kiedy token traci ważność. Standard JWT wymaga, aby we wszystkich jego implementacjach tokeny, których ważność wygasła, były odrzucane. Klucz Exp powinien być znacznikiem czasu w formacie unix.
- nbf (Nie wcześniej niż) — to czas w formacie unix, definiujący moment, w którym token stanie się ważny.
- iat (Data wydania) — ten klucz reprezentuje czas, kiedy token został wydany i może być użyty do określenia wieku JWT. Klucz iat powinien być znacznikiem czasu w formacie unix.
- Jti (ID JWT) — ciąg, który definiuje unikalny identyfikator danego tokenu z uwzględnieniem wielkości liter.
Ważne jest, aby zrozumieć, że ładunek użytkowy nie jest przesyłany w formie zaszyfrowanej (chociaż tokeny mogą być zagnieżdżone i wtedy można przesyłać zaszyfrowane dane). Dlatego nie należy w nim przechowywać żadnych informacji poufnych. Podobnie jak nagłówek, ładunek kodowany jest w base64.
Podpis — gdy mamy nagłówek i ładunek, możemy obliczyć podpis.
Wykorzystywane są zakodowane w base64: nagłówek i ładunek, łączone w ciąg za pomocą kropki. Następnie ten ciąg i tajny klucz są podawane do algorytmu szyfrowania, wskazanego w nagłówku (klucz „alg”). Klucz może być dowolnym ciągiem. Dłuższe ciągi będą bardziej preferowane, ponieważ wymagają więcej czasu na odgadnięcie.
{"alg":"RSA1_5",“payload":"A128CBC-HS256"}
Budowa architektury odpornego na awarie klastra Keycloak
Przy używaniu jednego klastra dla wszystkich projektów rosną wymagania dotyczące rozwiązania SSO. Gdy liczba projektów jest niewielka, wymagania te nie są tak odczuwalne dla wszystkich projektów, jednak w miarę wzrostu liczby użytkowników i integracji rosną wymagania dotyczące dostępności i wydajności.
Zwiększone ryzyko awarii jednego punktu SSO podnosi wymagania dotyczące architektury rozwiązania oraz metod rezerwacji komponentów, co prowadzi do bardzo restrykcyjnych SLA. W związku z tym, w trakcie projektowania lub wczesnych etapów wdrażania rozwiązań, projekty często mają własną, nienaawaryjną infrastrukturę. W miarę rozwoju konieczne jest uwzględnienie możliwości rozwoju i skalowania. Najbardziej elastycznym rozwiązaniem do budowy odpornego klastra jest zastosowanie wirtualizacji kontenerowej lub podejścia hybrydowego.
Aby działać w trybie Active/Active i Active/Passive klastra, należy zapewnić spójność danych w relacyjnej bazie danych — oba węzły bazy danych muszą być synchronizowane między różnymi geograficznie rozproszonymi centrami danych.
Najprostszy przykład instalacji odpornej na awarie.

Jakie korzyści daje wykorzystanie jednego klastra:
- Wysoka dostępność i wydajność.
- Wsparcie trybów pracy: Active/Active, Active/Passive.
- Możliwość dynamicznego skalowania — przy zastosowaniu wirtualizacji kontenerowej.
- Możliwość centralnego zarządzania i monitorowania.
- Jednolity approach do identyfikacji/uwierzytelniania/autoryzacji użytkowników w projektach.
- Bardziej przezroczysta współpraca między różnymi projektami bez zaangażowania użytkowników.
- Możliwość ponownego wykorzystania tokena JWT w różnych projektach.
- Jednolity punkt zaufania.
- Szybsze uruchamianie projektów z użyciem mikroserwisów/wirtualizacji kontenerowej (nie jest wymagane uruchamianie i konfiguracja dodatkowych komponentów).
- Możliwość zakupu wsparcia komercyjnego od dostawcy.
Na co zwrócić uwagę przy planowaniu klastra
DBMS
Keycloak wykorzystuje system zarządzania DBMS do przechowywania: realms, clients, users itp.
Wspiera szeroki zakres DBMS: MS SQL, Oracle, MySQL, PostgreSQL. Keycloak jest dostarczany z własną wbudowaną relacyjną bazą danych. Zaleca się użycie w środowiskach o niskim obciążeniu – takich jak środowiska deweloperskie.
Aby działać w trybie Active/Active i Active/Passive klastra, należy zapewnić spójność danych w relacyjnej bazie danych, a oba węzły klastra baz danych synchronizują się między centrami danych.
Rozproszona pamięć podręczna (Infinspan)
Aby klaster działał poprawnie, wymagana jest dodatkowa synchronizacja następujących typów pamięci podręcznej z użyciem JBoss Data Grid:
Sesje uwierzytelniania — używane do przechowywania danych podczas uwierzytelniania konkretnego użytkownika. Żądania z tej pamięci podręcznej zazwyczaj obejmują tylko przeglądarkę i serwer Keycloak, a nie aplikację.
Tokeny akcji — stosowane w scenariuszach, w których użytkownik musi potwierdzić działanie asynchronicznie (za pośrednictwem poczty elektronicznej). Na przykład w trakcie procesu zapomnienia hasła pamięć podręczna actionTokens Infinispan jest używana do śledzenia metadanych dotyczących powiązanych znaczników akcji, które zostały już wykorzystane, dlatego nie można ich użyć ponownie.
Pamięć podręczna i unieważnienie danych trwałych – używane do buforowania trwałych danych, aby uniknąć zbędnych zapytań do bazy danych. Kiedy jakikolwiek serwer Keycloak aktualizuje dane, wszystkie pozostałe serwery Keycloak we wszystkich centrach danych muszą o tym wiedzieć.
Praca — używana tylko do przesyłania wiadomości o unieważnieniu między węzłami klastra a centrami danych.
Sesje użytkowników — używane do przechowywania danych o sesjach użytkownika, które są ważne w trakcie trwania sesji przeglądarki użytkownika. Pamięć podręczna musi obsługiwać żądania HTTP od końcowego użytkownika i aplikacji.
Ochrona przed atakami typu brute force — używana do śledzenia danych o nieudanych próbach logowania.
Rozkład obciążenia
Serwer równoważenia obciążenia jest jedynym punktem dostępu do Keycloak i musi obsługiwać sesje sticky.
Serwery aplikacji
Używane do kontrolowania interakcji między komponentami i mogą być wirtualizowane lub konteneryzowane z użyciem istniejących narzędzi automatyzacji i dynamicznego skalowania infrastruktury. Najczęstsze scenariusze wdrożenia w OpenShift, Kubernetes, Rancher.
To koniec pierwszej części – teoretycznej. W kolejnych cyklach artykułów będą omawiane przykłady integracji z różnymi dostawcami tożsamości oraz przykłady konfiguracji.
Źródło: habr.com
