Spusťte Keycloak v režimu HA na Kubernetes

Spusťte Keycloak v režimu HA na Kubernetes

TL, DR: bude zde popis Keycloaku, otevřeného systému řízení přístupu, analýza vnitřního zařízení, podrobnosti o konfiguraci.

Úvod a hlavní myšlenky

V tomto článku uvidíme hlavní myšlenky, které je třeba mít na paměti při nasazování clusteru Keycloak na Kubernetes.

Pokud se chcete o Keycloaku dozvědět více, podívejte se na odkazy na konci článku. Abyste se mohli hlouběji ponořit do praxe, můžete studovat naše úložiště s modulem, který implementuje hlavní myšlenky tohoto článku (je tam průvodce spuštěním, v tomto článku bude přehled zařízení a nastavení, Cca. překladatel).

Keycloak je komplexní systém napsaný v Javě a postavený na aplikačním serveru. divoká moucha. Stručně řečeno, jde o autorizační rámec, který uživatelům aplikací poskytuje federaci a možnost jednotného přihlášení (SSO).

Zveme vás k přečtení oficiálního сайт nebo Wikipedie pro podrobné pochopení.

Spusťte Keycloak

Keycloak potřebuje ke spuštění dva trvalé zdroje dat:

  • Databáze používaná k ukládání trvalých dat, jako jsou informace o uživatelích
  • Datagrid cache, která se používá k ukládání dat z databáze do mezipaměti a také k ukládání některých krátkodobých a často měněných metadat, jako jsou uživatelské relace. Vydáno Infinispan, která je obvykle výrazně rychlejší než databáze. Ale v každém případě jsou data uložená v Infinispanu pomíjivá – a není třeba je při restartu clusteru někam ukládat.

Keycloak funguje ve čtyřech různých režimech:

  • Normální - jeden a pouze jeden proces, konfigurovaný prostřednictvím souboru samostatný.xml
  • pravidelný shluk (volba vysoce dostupná) - Všechny procesy musí používat stejnou konfiguraci, která musí být synchronizována ručně. Nastavení jsou uložena v souboru standalone-ha.xml, navíc musíte udělat sdílený přístup k databázi a load balancer.
  • Cluster domén - spouštění clusteru v normálním režimu se rychle stává rutinním a nudným úkolem, protože cluster roste, protože pokaždé, když se změní konfigurace, musí být všechny změny provedeny na každém uzlu clusteru. Režim provozu domény řeší tento problém nastavením sdíleného úložiště a zveřejněním konfigurace. Tato nastavení jsou uložena v souboru doména.xml
  • Replikace mezi datovými centry - v případě, že chcete provozovat Keycloak v clusteru více datových center, nejčastěji v různých geografických lokalitách. V této možnosti bude mít každé datové centrum svůj vlastní cluster serverů Keycloak.

V tomto článku se blíže podíváme na druhou možnost, tzn. pravidelný shluk, stejně jako malý dotyk na téma replikace mezi datovými centry, protože má smysl spouštět tyto dvě možnosti v Kubernetes. Naštěstí Kubernetes nemá problém se synchronizací nastavení více podů (uzlů Keycloak), takže doménový cluster nebude to příliš těžké udělat.

Všimněte si také, že slovo cluster až do konce článku se bude vztahovat pouze na skupinu uzlů Keycloak spolupracujících, není třeba odkazovat na cluster Kubernetes.

Normální klastr klíčenek

Chcete-li spustit Keycloak v tomto režimu, potřebujete:

  • nastavit externí sdílenou databázi
  • nainstalujte load balancer
  • mít vnitřní síť s podporou IP multicast

Nebudeme analyzovat konfiguraci externí databáze, protože to není účelem tohoto článku. Předpokládejme, že někde existuje funkční databáze – a máme k ní přípojný bod. Tato data jednoduše přidáme do proměnných prostředí.

Abyste lépe porozuměli tomu, jak Keycloak funguje v clusteru s podporou převzetí služeb při selhání (HA), je důležité vědět, jak moc to všechno závisí na schopnostech shlukování Wildfly.

Wildfly používá několik subsystémů, některé z nich se používají jako load balancer, některé se používají pro převzetí služeb při selhání. Nástroj pro vyrovnávání zatížení zajišťuje dostupnost aplikace při přetížení uzlu clusteru a převzetí služeb při selhání zajišťuje dostupnost aplikace i v případě, že některé uzly clusteru selžou. Některé z těchto subsystémů jsou:

  • mod_cluster: funguje ve spojení s Apache jako nástroj pro vyrovnávání zatížení HTTP, závisí na TCP multicast pro výchozí zjišťování hostitele. Lze nahradit externím balancerem.

  • infinispan: distribuovaná mezipaměť využívající kanály JGroups jako transportní vrstvu. Volitelně může používat protokol HotRod pro komunikaci s externím clusterem Infinispan pro synchronizaci obsahu mezipaměti.

  • jgroups: Poskytuje podporu pro skupinové přidružení pro vysoce dostupné služby založené na kanálech JGroups. Pojmenované kanály umožňují připojení instancí aplikací v clusteru do skupin, takže připojení má vlastnosti, jako je spolehlivost, uspořádanost a citlivost na selhání.

vyvažovač zátěže

Při instalaci balanceru jako řadiče vstupu do clusteru Kubernetes je důležité mít na paměti následující věci:

Z práce Keycloaku vyplývá, že vzdálená adresa klienta připojujícího se přes HTTP k autentizačnímu serveru je skutečnou IP adresou klientského počítače. Nastavení balanceru a vstupu by měla správně nastavit hlavičky HTTP X-Forwarded-For и X-Forwarded-Protoa ponechte původní název HOST. Nejnovější verze ingress-nginx (> 0.22.0) ve výchozím nastavení jej zakáže

Aktivace příznaku proxy-address-forwarding nastavením proměnné prostředí PROXY_ADDRESS_FORWARDING в true dává Keycloak pochopení, že běží za proxy.

Musíte také povolit lepkavé relace vstupující. Keycloak používá distribuovanou mezipaměť Infinispanu k ukládání dat spojených s aktuální autentizační relací a uživatelskou relací. Mezipaměti jsou ve výchozím nastavení jedním vlastníkem, jinými slovy, že konkrétní relace je uložena v některém uzlu clusteru a ostatní uzly si ji musí vzdáleně vyžádat, pokud potřebují k této relaci přístup.

Konkrétně, v rozporu s dokumentací, připojení relace s názvem cookie pro nás nefungovalo AUTH_SESSION_ID. Keycloak zacyklil přesměrování, takže doporučujeme zvolit jiný název souboru cookie pro relaci s lepivým umístěním.

Keycloak také připojí jméno hostitele, který odpověděl jako první AUTH_SESSION_IDa protože každý uzel ve vysoce dostupné verzi používá stejnou databázi, každý z nich musí mít samostatné a jedinečné ID uzlu pro správu transakcí. Doporučuje se vložit JAVA_OPTS Volby jboss.node.name и jboss.tx.node.id jedinečný pro každý uzel – můžete například nastavit název podu. Pokud zadáte název podu - nezapomeňte na limit 23 znaků pro proměnné jboss, takže je lepší použít StatefulSet, ne Deployment.

Další rake - pokud je pod smazán nebo restartován, jeho mezipaměť je ztracena. S ohledem na to se vyplatí nastavit počet vlastníků keší u všech keší alespoň na dva, takže bude kopie keše. Řešením je běh scénář pro Wildfly při spouštění modulu ho umístíte do adresáře /opt/jboss/startup-scripts v kontejneru:

Obsah skriptu

embed-server --server-config=standalone-ha.xml --std-out=echo
batch

echo * Setting CACHE_OWNERS to "${env.CACHE_OWNERS}" in all cache-containers

/subsystem=infinispan/cache-container=keycloak/distributed-cache=sessions:write-attribute(name=owners, value=${env.CACHE_OWNERS:1})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=authenticationSessions:write-attribute(name=owners, value=${env.CACHE_OWNERS:1})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=actionTokens:write-attribute(name=owners, value=${env.CACHE_OWNERS:1})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineSessions:write-attribute(name=owners, value=${env.CACHE_OWNERS:1})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=clientSessions:write-attribute(name=owners, value=${env.CACHE_OWNERS:1})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineClientSessions:write-attribute(name=owners, value=${env.CACHE_OWNERS:1})
/subsystem=infinispan/cache-container=keycloak/distributed-cache=loginFailures:write-attribute(name=owners, value=${env.CACHE_OWNERS:1})

run-batch
stop-embedded-server

poté nastavte hodnotu proměnné prostředí CACHE_OWNERS k požadovanému.

Privátní síť s podporou IP multicast

Pokud jako CNI používáte Weavenet, bude multicast fungovat okamžitě – a vaše uzly Keycloak se navzájem uvidí, jakmile budou spuštěny.

Pokud ve svém clusteru Kubernetes nemáte podporu vícesměrového vysílání IP, můžete nakonfigurovat JGroups tak, aby při hledání uzlů spolupracovaly s jinými protokoly.

První možností je použít KUBE_DNSkterý používá headless service pro nalezení uzlů Keycloak jednoduše předáte JGroups název služby, která bude použita k nalezení uzlů.

Další možností je použít metodu KUBE_PING, který pracuje s API pro hledání uzlů (je třeba nakonfigurovat serviceAccount s právy list и geta poté nakonfigurujte pody tak, aby s tím pracovaly serviceAccount).

Způsob vyhledávání uzlů pro JGroups se konfiguruje nastavením proměnných prostředí JGROUPS_DISCOVERY_PROTOCOL и JGROUPS_DISCOVERY_PROPERTIES. Pro KUBE_PING musíte si vybrat lusky dotazem namespace и labels.

️ Pokud používáte multicast a provozujete dva nebo více clusterů Keycloak ve stejném clusteru Kubernetes (řekněme jeden v oboru názvů production, druhý - staging) - uzly z jednoho clusteru Keycloak se mohou připojit k jinému clusteru. Nastavením proměnných nezapomeňte pro každý cluster použít jedinečnou adresu vícesměrového vysíláníjboss.default.multicast.address и jboss.modcluster.multicast.address в JAVA_OPTS.

Replikace mezi datovými centry

Spusťte Keycloak v režimu HA na Kubernetes

Связь

Keycloak používá několik samostatných clusterů Infinispan Cache pro každé datové centrum hostující clustery Keycloack složené z uzlů Keycloak. Ale zároveň mezi uzly Keycloak v různých datových centrech není žádný rozdíl.

Uzly Keycloak používají ke komunikaci mezi datovými centry externí Java Data Grid (servery Infinispan). Komunikace funguje podle protokolu HotRod Infinispan.

Mezipaměti Infinispan musí být nakonfigurovány pomocí atributu remoteStore, takže data mohou být uložena vzdáleně (v jiném datovém centru, Cca. překladatel) cache. Mezi servery JDG jsou samostatné clustery infinispan, takže data jsou uložena na JDG1 na místě site1 budou replikovány do JDG2 na místě site2.

Nakonec přijímající server JDG informuje servery Keycloak o svém clusteru prostřednictvím klientských připojení, což je vlastnost protokolu HotRod. Uzly pro maskování zapnuty site2 aktualizujte jejich mezipaměti Infinispan a konkrétní uživatelská relace bude dostupná na uzlech Keycloak na site2.

Je také možné, že některé mezipaměti nebudou zálohovány a zcela odmítnou zapisovat data přes server Infinispan. Chcete-li to provést, musíte toto nastavení odstranit remote-store specifická mezipaměť Infinispan (v souboru standalone-ha.xml), načež některé konkrétní replicated-cache již také nebude potřeba na straně serveru Infinispan.

Nastavení mezipaměti

V Keycloak jsou dva typy keší:

  • Místní. Je umístěn vedle základny, slouží ke snížení zátěže databáze a také ke snížení latence odezvy. Tento typ mezipaměti ukládá sféru, klienty, role a uživatelská metadata. Tento typ mezipaměti se nereplikuje, i když je tato mezipaměť součástí clusteru Keycloak. Pokud se některá položka v mezipaměti změní, odešle se zpráva o změně na zbytek serverů v clusteru, načež je položka z mezipaměti vyloučena. viz popis work níže pro podrobnější popis postupu.

  • Replikovatelné. Zpracovává uživatelské relace, offline tokeny a monitoruje selhání přihlášení, aby zjistil pokusy o phishing hesel a další útoky. Data uložená v těchto mezipaměti jsou dočasná, jsou uložena pouze v paměti RAM, ale lze je replikovat v rámci clusteru.

Mezipaměti Infinispan

Relace - koncept v Keycloak, samostatné keše, které se nazývají authenticationSessions, slouží k ukládání dat konkrétních uživatelů. Požadavky z těchto mezipamětí obvykle potřebuje prohlížeč a servery Keycloak, nikoli aplikace. Zde se projevuje závislost na sticky sessions a takové cache samotné není potřeba replikovat ani v případě Active-Active módu.

Akční žetony. Další koncept, obvykle používaný pro různé scénáře, kdy například uživatel potřebuje něco vyřídit asynchronně poštou. Například během procedury forget password mezipaměti actionTokens slouží ke sledování metadat souvisejících tokenů – například token již byl použit a nelze jej znovu aktivovat. Tento typ mezipaměti by měl být typicky replikován mezi datovými centry.

Ukládání do mezipaměti a vypršení platnosti uložených dat pracuje na odstranění zátěže databáze. Toto ukládání do mezipaměti zlepšuje výkon, ale přináší zřejmý problém. Pokud jeden server Keycloak aktualizuje data, ostatní servery musí být upozorněny, aby mohly aktualizovat své mezipaměti. Keycloak používá místní mezipaměti realms, users и authorization pro ukládání dat z databáze do mezipaměti.

Je zde i samostatná cache work, který je replikován napříč všemi datovými centry. Ta sama o sobě neukládá žádná data z databáze, ale slouží k odesílání zpráv o stárnutí dat do uzlů clusteru mezi datovými centry. Jinými slovy, jakmile jsou data aktualizována, uzel Keycloak odešle zprávu ostatním uzlům ve svém datovém centru a také uzlům v jiných datových centrech. Po přijetí takové zprávy každý uzel vyčistí odpovídající data ve svých lokálních mezipaměti.

Uživatelské relace. Keše se jmény sessions, clientSessions, offlineSessions и offlineClientSessions, se obvykle replikují mezi datovými centry a slouží k ukládání dat o uživatelských relacích, které jsou aktivní, když je uživatel aktivní v prohlížeči. Tyto mezipaměti spolupracují s aplikací, která zpracovává požadavky HTTP od koncových uživatelů, takže jsou spojeny s pevnými relacemi a musí být replikovány mezi datovými centry.

ochrana hrubou silou. Mezipaměti loginFailures slouží ke sledování údajů o chybách přihlášení, například kolikrát uživatel zadal nesprávné heslo. Replikace této mezipaměti je na správci. Pro přesný výpočet se ale vyplatí aktivovat replikaci mezi datovými centry. Ale na druhou stranu, pokud tato data nereplikujete, budete moci zlepšit výkon, a pokud se objeví tato otázka, replikace nemusí být aktivována.

Při zavádění clusteru Infinispan musíte do souboru nastavení přidat definice mezipaměti:

<replicated-cache-configuration name="keycloak-sessions" mode="ASYNC" start="EAGER" batching="false">
</replicated-cache-configuration>

<replicated-cache name="work" configuration="keycloak-sessions" />
<replicated-cache name="sessions" configuration="keycloak-sessions" />
<replicated-cache name="offlineSessions" configuration="keycloak-sessions" />
<replicated-cache name="actionTokens" configuration="keycloak-sessions" />
<replicated-cache name="loginFailures" configuration="keycloak-sessions" />
<replicated-cache name="clientSessions" configuration="keycloak-sessions" />
<replicated-cache name="offlineClientSessions" configuration="keycloak-sessions" />

Před spuštěním clusteru Keycloak musíte nakonfigurovat a spustit cluster Infinispan

Pak je potřeba nastavit remoteStore pro Keycloak cache. K tomu stačí skript, který se provádí podobně jako předchozí, který slouží k nastavení proměnné CACHE_OWNERS, musíte jej uložit do souboru a vložit do adresáře /opt/jboss/startup-scripts:

Obsah skriptu

embed-server --server-config=standalone-ha.xml --std-out=echo
batch

echo *** Update infinispan subsystem ***
/subsystem=infinispan/cache-container=keycloak:write-attribute(name=module, value=org.keycloak.keycloak-model-infinispan)

echo ** Add remote socket binding to infinispan server **
/socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=remote-cache:add(host=${remote.cache.host:localhost}, port=${remote.cache.port:11222})

echo ** Update replicated-cache work element **
/subsystem=infinispan/cache-container=keycloak/replicated-cache=work/store=remote:add( 
    passivation=false, 
    fetch-state=false, 
    purge=false, 
    preload=false, 
    shared=true, 
    remote-servers=["remote-cache"], 
    cache=work, 
    properties={ 
        rawValues=true, 
        marshaller=org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory, 
        protocolVersion=${keycloak.connectionsInfinispan.hotrodProtocolVersion} 
    } 
)

/subsystem=infinispan/cache-container=keycloak/replicated-cache=work:write-attribute(name=statistics-enabled,value=true)

echo ** Update distributed-cache sessions element **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=sessions/store=remote:add( 
    passivation=false, 
    fetch-state=false, 
    purge=false, 
    preload=false, 
    shared=true, 
    remote-servers=["remote-cache"], 
    cache=sessions, 
    properties={ 
        rawValues=true, 
        marshaller=org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory, 
        protocolVersion=${keycloak.connectionsInfinispan.hotrodProtocolVersion} 
    } 
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=sessions:write-attribute(name=statistics-enabled,value=true)

echo ** Update distributed-cache offlineSessions element **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineSessions/store=remote:add( 
    passivation=false, 
    fetch-state=false, 
    purge=false, 
    preload=false, 
    shared=true, 
    remote-servers=["remote-cache"], 
    cache=offlineSessions, 
    properties={ 
        rawValues=true, 
        marshaller=org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory, 
        protocolVersion=${keycloak.connectionsInfinispan.hotrodProtocolVersion} 
    } 
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineSessions:write-attribute(name=statistics-enabled,value=true)

echo ** Update distributed-cache clientSessions element **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=clientSessions/store=remote:add( 
    passivation=false, 
    fetch-state=false, 
    purge=false, 
    preload=false, 
    shared=true, 
    remote-servers=["remote-cache"], 
    cache=clientSessions, 
    properties={ 
        rawValues=true, 
        marshaller=org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory, 
        protocolVersion=${keycloak.connectionsInfinispan.hotrodProtocolVersion} 
    } 
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=clientSessions:write-attribute(name=statistics-enabled,value=true)

echo ** Update distributed-cache offlineClientSessions element **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineClientSessions/store=remote:add( 
    passivation=false, 
    fetch-state=false, 
    purge=false, 
    preload=false, 
    shared=true, 
    remote-servers=["remote-cache"], 
    cache=offlineClientSessions, 
    properties={ 
        rawValues=true, 
        marshaller=org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory, 
        protocolVersion=${keycloak.connectionsInfinispan.hotrodProtocolVersion} 
    } 
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineClientSessions:write-attribute(name=statistics-enabled,value=true)

echo ** Update distributed-cache loginFailures element **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=loginFailures/store=remote:add( 
    passivation=false, 
    fetch-state=false, 
    purge=false, 
    preload=false, 
    shared=true, 
    remote-servers=["remote-cache"], 
    cache=loginFailures, 
    properties={ 
        rawValues=true, 
        marshaller=org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory, 
        protocolVersion=${keycloak.connectionsInfinispan.hotrodProtocolVersion} 
    } 
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=loginFailures:write-attribute(name=statistics-enabled,value=true)

echo ** Update distributed-cache actionTokens element **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=actionTokens/store=remote:add( 
    passivation=false, 
    fetch-state=false, 
    purge=false, 
    preload=false, 
    shared=true, 
    cache=actionTokens, 
    remote-servers=["remote-cache"], 
    properties={ 
        rawValues=true, 
        marshaller=org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory, 
        protocolVersion=${keycloak.connectionsInfinispan.hotrodProtocolVersion} 
    } 
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=actionTokens:write-attribute(name=statistics-enabled,value=true)

echo ** Update distributed-cache authenticationSessions element **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=authenticationSessions:write-attribute(name=statistics-enabled,value=true)

echo *** Update undertow subsystem ***
/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=proxy-address-forwarding,value=true)

run-batch
stop-embedded-server

Nezapomeňte nainstalovat JAVA_OPTS aby uzly Keycloak fungovaly HotRod: remote.cache.host, remote.cache.port a název služby jboss.site.name.

Odkazy a další dokumentace

Článek přeložili a pro Habra připravili zaměstnanci Tréninkové centrum slurmu — intenzivní, video kurzy a firemní školení od praktiků (Kubernetes, DevOps, Docker, Ansible, Ceph, SRE)

Zdroj: www.habr.com

Přidat komentář