OpenID Connect: autorizace interních aplikací od vlastních řešení po standard

Před několika měsíci jsem se zabýval implementací serveru OpenID Connect pro správu přístupu k desítkám našich interních aplikací. Přešli jsme od vlastních řešení, která byla přizpůsobena menším měřítkům, ke standardizovanému řešení. Přístup přes centrální službu výrazně zjednodušuje monotónní operace, snižuje náklady na implementaci autorizací, umožňuje najít řadu hotových řešení a usnadňuje vývoj nových. V tomto článku se podělím o tento přechod a o problémy, které jsme na cestě potkali.

OpenID Connect: autorizace interních aplikací od vlastních řešení po standard

Kdysi dávno… Jak to všechno začalo

Před několika lety, kdy bylo interních aplikací příliš mnoho na ruční správu, jsme napsali aplikaci pro kontrolu přístupů uvnitř firmy. Byla to jednoduchá aplikace v Rails, která se připojovala k databázi se záznamy o zaměstnancích, kde se nastavoval přístup k různým funkcím. Tehdy jsme také zprovoznili první SSO, které se zakládalo na kontrole tokenů z klienta a serveru autorizace; token byl předáván v šifrované podobě s několika parametry a ověřoval se na serveru autorizace. Nebyl to nejpohodlnější variant, protože na každé interní aplikaci bylo potřeba definovat značné množství logiky, a databáze zaměstnanců se vůbec nesynchronizovaly se serverem autorizace.

Po nějaké době jsme se rozhodli zjednodušit úlohu centralizované autorizace. SSO jsme převedli na load balancer. S pomocí OpenResty na Lua jsme přidali šablonu, která kontrolovala tokeny, věděla, do jaké aplikace směřuje požadavek, a mohla zkontrolovat, zda je tam přístup. Tento přístup výrazně zjednodušil správu přístupů v interních aplikacích — v kódu každé aplikace už nebylo potřeba popisovat další logiku. Nakonec jsme uzavřeli externí provoz, a samotná aplikace nic nevěděla o autorizaci.

Jedním z problémů však zůstává nevyřešen. Jak naložit s aplikacemi, které potřebují informace o zaměstnancích? Mohli bychom napsat API pro autorizační službu, ale to by znamenalo přidat další logiku pro každou takovou aplikaci. Navíc jsme chtěli odstranit závislost na našem vlastním řešení, které plánujeme převedení do OpenSource, od našeho interního serveru pro autorizaci. O tom se zmíníme někdy jindy. Řešením obou problémů se stal OAuth.

Obvyklé standardy

OAuth je přehledný, běžně uznávaný standard pro autorizaci, ale protože jeho funkcionalita nestačila, začali jsme zvažovat také OpenID Connect (OIDC). OIDC je třetí implementací otevřeného autentizačního standardu, která navazuje na protokol OAuth 2.0 (otevřený autorizační protokol). Toto řešení uzavírá problém nedostatku dat o koncovém uživateli a také umožňuje změnu poskytovatele autorizace.

Nestanovili jsme však konkrétního poskytovatele a rozhodli se přidat integraci OIDC k našemu stávajícímu serveru autorizace. Tento výběr podpořila flexibilita OIDC v oblasti autorizace koncového uživatele. Tak jsme měli možnost implementovat podporu OIDC na našem aktuálním serveru autorizace.

OpenID Connect: autorizace interních aplikací od vlastních řešení po standard

Naše cesta k realizaci vlastního OIDC serveru

1) Připravili jsme data do požadovaného formátu

Pro integraci OIDC je nutné upravit aktuální data o uživatelích do formátu pochopitelného pro standard. V OIDC se tomu říká Claims. Claims jsou vlastně konečná pole v databázi o uživatelích (jméno, email, telefon atd.). Existuje standardní seznam claimů, a vše, co do tohoto seznamu nepatří, se považuje za vlastní. Proto první věcí, na kterou je třeba se zaměřit, pokud se rozhodnete vybrat existujícího OIDC poskytovatele – je možnost pohodlné přizpůsobení nových claimů.

Skupina claimů se spojuje do následující podmnožiny – Scope. Při autorizaci se žádá o přístup nikoli k jednotlivým claimům, ale právě k scope, i když část claimů ze scope není potřeba.

2) Implementovali jsme potřebné granty

Další část integrace OIDC zahrnuje výběr a implementaci typů autorizace, tzv. grantů. Na základě zvoleného grantu bude záviset další scénář interakce vybrané aplikace s autorizacním serverem. Příkladná schéma výběru potřebného grantu je uvedena na obrázku níže.

OpenID Connect: autorizace interních aplikací od vlastních řešení po standard

Pro naši první aplikaci jsme použili nejrozšířenější grant – Authorization Code. Jeho rozdíl od ostatních spočívá v tom, že je tříkrokový, tj. prochází dodatečnou kontrolou. Nejprve uživatel požaduje povolení autorizace, získá token – Authorization Code a poté s tímto tokenem, jako s jízdenkou, požaduje přístupový token. Veškerá hlavní interakce tohoto scénáře autorizace je založena na přesměrováních mezi aplikací a autorizacním serverem. Více o tomto grantu se můžete dočíst zde.

OAuth se drží konceptu, že přístupové tokeny získané po autorizaci by měly být dočasné a měnily by se ideálně zhruba každých 10 minut. Grant Authorization Code představuje tříkrokovou kontrolu přes přesměrování, provádět tento krok každých 10 minut, upřímně řečeno, není právě nejpříjemnější činnost pro oči. Pro řešení tohoto problému existuje další grant – Refresh Token, který jsme také použili. Tady je to jednodušší. Během kontroly s jiného grantu, kromě hlavního přístupového tokenu, se vydává ještě jeden – Refresh Token, který lze použít pouze jednou a jeho životnost je obvykle výrazně delší. S tímto Refresh Tokenem, když skončí TTL (Time to Live) hlavního přístupového tokenu, přijde požadavek na nový přístupový token na endpoint již jiného grantu. Použitý Refresh Token se okamžitě nulován. Tato kontrola je dvoukroková a může být provedena na pozadí, nepozorovaně pro uživatele.

3) Nastavili jsme formáty výstupu uživatelských dat

Poté, co jsou vybrané granty realizovány a autorizace funguje, je dobré zmínit se o získání dat o koncovém uživateli. V OIDC existuje samostatný endpoint pro toto, na kterém lze se svým aktuálním přístupovým tokenem a při jeho platnosti požádat o uživatelská data. Pokud se data uživatele nemění příliš často a je potřeba je získávat opakovaně, může se přistoupit k řešení, jako jsou JWT tokeny. Tyto tokeny jsou také podporovány standardem. Samotný JWT token se skládá ze tří částí: header (informace o tokenu), payload (jakákoliv potřebná data) a signature (podpis, token je podepsán serverem a později lze ověřit zdroj jeho podpisu).

V implementaci OIDC se JWT token nazývá id_token. Může být požadován spolu s běžným přístupovým tokenem a stačí ověřit podpis. Pro to má server autorizace samostatný endpoint se sadou veřejných klíčů ve formátu JWK. A mluvíme-li o tom, je dobré zmínit, že existuje ještě jeden endpoint, který na základě standardu RFC5785 odráží aktuální konfiguraci OIDC serveru. Obsahuje všechny adresy endpointů (včetně adresy sady veřejných klíčů používaných k podpisu), podporované klamstvy a scope, používané šifrovací algoritmy, podporované granty atd.

Například v Google:

{
 "issuer": "https://accounts.google.com",
 "authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
 "device_authorization_endpoint": "https://oauth2.googleapis.com/device/code",
 "token_endpoint": "https://oauth2.googleapis.com/token",
 "userinfo_endpoint": "https://openidconnect.googleapis.com/v1/userinfo",
 "revocation_endpoint": "https://oauth2.googleapis.com/revoke",
 "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
 "response_types_supported": [
  "code",
  "token",
  "id_token",
  "code token",
  "code id_token",
  "token id_token",
  "code token id_token",
  "none"
 ],
 "subject_types_supported": [
  "public"
 ],
 "id_token_signing_alg_values_supported": [
  "RS256"
 ],
 "scopes_supported": [
  "openid",
  "email",
  "profile"
 ],
 "token_endpoint_auth_methods_supported": [
  "client_secret_post",
  "client_secret_basic"
 ],
 "claims_supported": [
  "aud",
  "email",
  "email_verified",
  "exp",
  "family_name",
  "given_name",
  "iat",
  "iss",
  "locale",
  "name",
  "picture",
  "sub"
 ],
 "code_challenge_methods_supported": [
  "plain",
  "S256"
 ],
 "grant_types_supported": [
  "authorization_code",
  "refresh_token",
  "urn:ietf:params:oauth:grant-type:device_code",
  "urn:ietf:params:oauth:grant-type:jwt-bearer"
 ]
}

Takže pomocí id_tokenu lze předávat všechny potřebné nároky v payloadu tokenu a nemusíte se vždy obracet na server autorizace pro dotaz na údaje o uživateli. Nevýhodou tohoto přístupu je, že změny uživatelských dat ze serveru přicházejí hned, ale až s novým přístupovým tokenem.

Závěry implementace

Takže po implementaci vlastního OIDC serveru a nastavení připojení k němu na straně aplikací jsme vyřešili problém s předáváním informací o uživatelích.
Jelikož OIDC je otevřený standard, získali jsme možnost výběru existujícího poskytovatele nebo implementace serveru. Zkoušeli jsme Keycloak, který se ukázal jako velmi pohodlný na konfiguraci, po nastavení a změně konfiguračních připojení na straně aplikací je připraven k použití. Na straně aplikací zbývá pouze změnit konfigurační připojení.

Pokud jde o existující řešení

V rámci naší organizace jsme jako první OIDC server sestavili vlastním způsobem, který se doplňoval podle potřeby. Po podrobném zkoumání dalších hotových řešení lze říci, že je to sporný moment. V prospěch rozhodnutí implementovat vlastní server hrály roli obavy ze strany poskytovatelů z nedostatku potřebné funkčnosti a také skutečnost, že stávající systém měl různé customizované autorizační mechanismy pro některé služby a uchovával již poměrně mnoho dat o zaměstnancích. Nicméně v hotových realizacích jsou přítomny výhody pro integraci. Například v Keycloak je vlastní systém správy uživatelů a data jsou uchovávána přímo v něm, a převést své uživatele tam není velký problém. K tomu má Keycloak API, které umožní provést všechny potřebné akce pro migraci.

Dalším příkladem certifikované, zajímavé implementace, podle mého názoru, je Ory Hydra. Je zajímavá tím, že se skládá z různých komponent. Pro integraci budete potřebovat propojit svůj uživatelský manažerský systém s jejich autorizacním servisem a rozšiřovat podle potřeby.

Keycloak a Ory Hydra nejsou jediná hotová řešení. Nejlepší je vybírat certifikovanou implementaci od OpenID Foundation. Obvykle mají taková řešení značku OpenID Certification.

OpenID Connect: autorizace interních aplikací od vlastních řešení po standard

Nezapomínejte na dostupné placené poskytovatele, pokud nechcete provozovat svůj OIDC server. Dnes existuje mnoho dobrých možností.

Co dál

V nejbližší době plánujeme jiný způsob, jak omezit provoz na interní služby. Máme v úmyslu převést naši aktuální SSO na vyvažovači zátěže pomocí OpenResty na proxy, která je postavena na OAuth. I zde už existuje mnoho hotových řešení, například:
github.com/bitly/oauth2_proxy
github.com/ory/oathkeeper
github.com/keycloak/keycloak-gatekeeper

Další materiály

jwt.io – skvělá služba pro ověřování JWT tokenů
openid.net/developers/certified — seznam certifikovaných implementací OIDC

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster