Keycloak í HA ham á Kubernetes

Keycloak í HA ham á Kubernetes

TL; DR: það verður lýsing á Keycloak, opnu aðgangsstýringarkerfi, greining á innri uppbyggingu, upplýsingar um stillingar.

Inngangur og lykilhugmyndir

Í þessari grein munum við sjá grunnhugmyndirnar sem þarf að muna þegar Keycloak þyrping er sett upp ofan á Kubernetes.

Ef þú vilt vita meira um Keycloak skaltu skoða krækjurnar í lok greinarinnar. Til þess að verða meira á kafi í æfingum geturðu lært geymsluna okkar með einingu sem útfærir helstu hugmyndir þessarar greinar (ræsingarhandbókin er til staðar, þessi grein mun veita yfirlit yfir tækið og stillingar, ca. þýðandi).

Keycloak er alhliða kerfi skrifað í Java og byggt ofan á forritaþjóni Villifluga. Í stuttu máli er það rammi fyrir heimildir sem gefur notendum forrita sambands- og SSO (single sign-on) möguleika.

Við bjóðum þér að lesa opinbera сайт eða Wikipedia fyrir nákvæman skilning.

Keycloak opnar

Keycloak krefst tveggja viðvarandi gagnagjafa til að keyra:

  • Gagnagrunnur sem notaður er til að geyma staðfest gögn, svo sem notendaupplýsingar
  • Datagrid skyndiminni, sem er notað til að vista gögn úr gagnagrunninum, sem og til að geyma nokkur skammvinn og breytileg lýsigögn, eins og notendalotur. Framkvæmt Infinispan, sem er venjulega verulega hraðari en gagnagrunnurinn. En hvað sem því líður eru gögnin sem eru vistuð í Infinispan skammvinn – og það þarf ekki að vista þau neins staðar þegar þyrpingin er endurræst.

Keycloak virkar í fjórum mismunandi stillingum:

  • Normal - eitt og eitt ferli, stillt í gegnum skrá standalone.xml
  • Venjulegur klasi (hátt framboð valkostur) - öll ferli verða að nota sömu stillingar, sem verður að samstilla handvirkt. Stillingar eru geymdar í skrá standalone-ha.xml, auk þess sem þú þarft að gera sameiginlegan aðgang að gagnagrunninum og álagsjafnara.
  • Lénsklasi — að ræsa klasa í venjulegum ham verður fljótt venjubundið og leiðinlegt verkefni eftir því sem klasinn stækkar, þar sem í hvert skipti sem uppsetningin breytist verður að gera allar breytingar á hverjum klasahnút. Rekstrarháttur léns leysir þetta mál með því að setja upp sameiginlega geymslustað og birta stillingarnar. Þessar stillingar eru geymdar í skránni lén.xml
  • Afritun milli gagnavera — ef þú vilt keyra Keycloak í þyrpingu nokkurra gagnavera, oftast á mismunandi landfræðilegum stöðum. Í þessum valkosti mun hver gagnaver hafa sinn eigin þyrping af Keycloak netþjónum.

Í þessari grein munum við íhuga í smáatriðum seinni valkostinn, það er venjulegur klasi, og við munum líka snerta svolítið á efni afritunar milli gagnavera, þar sem það er skynsamlegt að keyra þessa tvo valkosti í Kubernetes. Sem betur fer, í Kubernetes er ekkert vandamál með að samstilla stillingar nokkurra belg (Keycloak hnúta), svo lénaklasi Það verður ekki mjög erfitt að gera.

Athugið einnig að orðið þyrping þar sem restin af greininni mun eingöngu eiga við hóp Keycloak hnúta sem vinna saman, það er engin þörf á að vísa til Kubernetes klasa.

Venjulegur Keycloak klasi

Til að keyra Keycloak í þessum ham þarftu:

  • stilla ytri sameiginlegan gagnagrunn
  • setja upp hleðslujafnara
  • hafa innra netkerfi með IP multicast stuðningi

Við munum ekki ræða um að setja upp ytri gagnagrunn þar sem það er ekki tilgangur þessarar greinar. Gerum ráð fyrir að einhvers staðar sé starfandi gagnagrunnur - og við höfum tengipunkt við hann. Við munum einfaldlega bæta þessum gögnum við umhverfisbreyturnar.

Til að skilja betur hvernig Keycloak virkar í failover (HA) þyrpingu er mikilvægt að vita hversu mikið það veltur allt á þyrpingarmöguleikum Wildfly.

Wildfly notar nokkur undirkerfi, sum þeirra eru notuð sem álagsjafnari, sum fyrir bilanaþol. Álagsjafnari tryggir aðgengi að forritum þegar klasahnútur er ofhlaðinn og bilunarþol tryggir aðgengi að forritum jafnvel þótt sumir klasahnútar bili. Sum þessara undirkerfa:

  • mod_cluster: Virkar í tengslum við Apache sem HTTP hleðslujafnari, fer eftir TCP multicast til að finna vélar sjálfgefið. Hægt að skipta út fyrir ytri jafnvægisbúnað.

  • infinispan: Dreift skyndiminni sem notar JGroups rásir sem flutningslag. Að auki getur það notað HotRod samskiptareglur til að hafa samskipti við ytri Infinispan þyrping til að samstilla skyndiminni innihald.

  • jgroups: Veitir hópsamskiptastuðning fyrir mjög tiltæka þjónustu byggða á JGroups rásum. Nafngreind rör gera kleift að tengja forritatilvik í klasa í hópa þannig að samskiptin hafi eiginleika eins og áreiðanleika, reglusemi og næmni fyrir bilunum.

Hleðslujafnari

Þegar jafnvægisbúnaður er settur upp sem inngangsstýribúnaður í Kubernetes klasa er mikilvægt að hafa eftirfarandi atriði í huga:

Keycloak gerir ráð fyrir að fjarvistfang viðskiptavinarins sem tengist með HTTP við auðkenningarþjóninn sé raunverulegt IP-tala biðlaratölvunnar. Stillingar jafnvægis og inngangs ættu að stilla HTTP hausa rétt X-Forwarded-For и X-Forwarded-Proto, og vistaðu einnig upprunalega titilinn HOST. Nýjasta útgáfa ingress-nginx (>0.22.0) slekkur þetta sjálfgefið

Að virkja fánann proxy-address-forwarding með því að stilla umhverfisbreytu PROXY_ADDRESS_FORWARDING в true gefur Keycloak skilning á því að það sé að vinna á bak við umboð.

Þú þarft líka að virkja klístraðar lotur í inngöngu. Keycloak notar dreift Infinispan skyndiminni til að geyma gögn sem tengjast núverandi auðkenningarlotu og notendalotu. Skyndiminni starfa sjálfgefið með einum eiganda, með öðrum orðum, þessi tiltekna lota er geymd á einhverjum hnút í þyrpingunni og aðrir hnútar verða að spyrjast fyrir um það fjarstýrt ef þeir þurfa aðgang að þeirri lotu.

Nánar tiltekið, þvert á skjölin, virkaði það ekki fyrir okkur að hengja við fund með nafnkökunni AUTH_SESSION_ID. Keycloak er með tilvísunarlykkju, svo við mælum með því að velja annað kökuheiti fyrir klístraða lotuna.

Keycloak festir einnig nafn hnútsins sem svaraði fyrst AUTH_SESSION_ID, og þar sem hver hnútur í mjög fáanlegu útgáfunni notar sama gagnagrunn, hver þeirra verður að hafa sérstakt og einstakt hnútauðkenni til að stjórna viðskiptum. Mælt er með því að setja inn JAVA_OPTS breytur jboss.node.name и jboss.tx.node.id einstakt fyrir hvern hnút - þú getur til dæmis sett nafn belgsins. Ef þú setur inn fræbelgsnafn, ekki gleyma 23 stafa takmörkunum fyrir jboss breytur, svo það er betra að nota StatefulSet frekar en Deployment.

Önnur hrífa - ef belgnum er eytt eða endurræst tapast skyndiminni hans. Að teknu tilliti til þessa er þess virði að stilla fjölda skyndiminniseigenda fyrir öll skyndiminni á að minnsta kosti tvo, þannig að afrit af skyndiminni verði eftir. Lausnin er að hlaupa handrit að Wildfly þegar þú ræsir podinn skaltu setja hann í möppuna /opt/jboss/startup-scripts í ílátinu:

Innihald handrits

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

stilltu síðan gildi umhverfisbreytunnar CACHE_OWNERS til þess sem krafist er.

Einkanet með IP fjölvarpsstuðningi

Ef þú notar Weavenet sem CNI, mun fjölvarp virka strax - og Keycloak hnúðarnir þínir sjá hver annan um leið og þeir eru ræstir.

Ef þú ert ekki með ip multicast stuðning í Kubernetes klasanum þínum geturðu stillt JGroups til að vinna með öðrum samskiptareglum til að finna hnúta.

Fyrsti kosturinn er að nota KUBE_DNSsem notar headless service til að finna Keycloak hnúta sendirðu einfaldlega JGroups nafn þjónustunnar sem verður notuð til að finna hnútana.

Annar möguleiki er að nota aðferðina KUBE_PING, sem vinnur með API til að leita að hnútum (þú þarft að stilla serviceAccount með réttindum list и get, og stilltu síðan belgina til að vinna með þetta serviceAccount).

Hvernig JGroups finna hnúta er stillt með því að stilla umhverfisbreytur JGROUPS_DISCOVERY_PROTOCOL и JGROUPS_DISCOVERY_PROPERTIES. Fyrir KUBE_PING þú þarft að velja belg með því að spyrja namespace и labels.

️ Ef þú notar multicast og keyrir tvo eða fleiri Keycloak klasa í einum Kubernetes klasa (segjum einn í nafnarými production, sekúndan - staging) - hnútar eins Keycloak klasa geta sameinast öðrum klasa. Vertu viss um að nota einstakt fjölvarpsvistfang fyrir hvern klasa með því að stilla breyturjboss.default.multicast.address и jboss.modcluster.multicast.address в JAVA_OPTS.

Afritun milli gagnavera

Keycloak í HA ham á Kubernetes

Связь

Keycloak notar marga aðskilda Infinispan skyndiminniklasa fyrir hverja gagnaver þar sem Keycloack klasar sem samanstanda af Keycloak hnútum eru staðsettir. En það er enginn munur á Keycloak hnútum í mismunandi gagnaverum.

Keycloak hnútar nota utanaðkomandi Java Data Grid (Infinispan netþjóna) fyrir samskipti milli gagnavera. Samskipti vinna samkvæmt samskiptareglum Infinispan HotRod.

Infinispan skyndiminni verður að stilla með eigindinni remoteStore, svo að hægt sé að geyma gögnin fjarstýrt (í annarri gagnaver, ca. þýðandi) skyndiminni. Það eru aðskildir infinispan klasar meðal JDG netþjónanna, þannig að gögnin sem eru geymd á JDG1 á staðnum site1 verður afritað í JDG2 á staðnum site2.

Og að lokum, JDG-þjónninn sem tekur á móti lætur Keycloak netþjóna vita um klasann sinn í gegnum biðlaratengingar, sem er eiginleiki HotRod samskiptareglunnar. Keycloak hnútar á site2 uppfærðu Infinispan skyndiminni og tiltekna notendalotan verður einnig fáanleg á Keycloak hnútunum á site2.

Fyrir sum skyndiminni er líka mögulegt að taka ekki afrit og forðast að skrifa gögn í gegnum Infinispan netþjóninn. Til að gera þetta þarftu að fjarlægja stillinguna remote-store sérstakt Infinispan skyndiminni (í skránni standalone-ha.xml), eftir það nokkrar sérstakar replicated-cache verður heldur ekki lengur þörf á Infinispan miðlarahliðinni.

Að setja upp skyndiminni

Það eru tvær tegundir af skyndiminni í Keycloak:

  • Staðbundið. Hann er staðsettur við hliðina á gagnagrunninum og þjónar til að draga úr álagi á gagnagrunninn, sem og til að draga úr svarleynd. Þessi tegund af skyndiminni geymir ríki, viðskiptavini, hlutverk og lýsigögn notenda. Þessi tegund af skyndiminni er ekki endurtekin, jafnvel þótt skyndiminni sé hluti af Keycloak þyrping. Ef færsla í skyndiminni breytist eru skilaboð um breytinguna send til þeirra netþjóna sem eftir eru í þyrpingunni, eftir það er færslan útilokuð úr skyndiminni. Sjá lýsingu work Sjá nánari lýsingu á málsmeðferðinni hér að neðan.

  • Afritað. Vinnur úr notendalotum, ótengdum táknum og fylgist einnig með innskráningarvillum til að greina tilraunir til vefveiða með lykilorði og aðrar árásir. Gögnin sem eru geymd í þessum skyndiminni eru tímabundin, aðeins geymd í vinnsluminni, en hægt er að endurtaka þau yfir þyrpinguna.

Infinispan skyndiminni

Fundur - hugtak í Keycloak, aðskilin skyndiminni kallað authenticationSessions, eru notuð til að geyma gögn tiltekinna notenda. Beiðnir frá þessum skyndiminni eru venjulega nauðsynlegar fyrir vafra og Keycloak netþjóna, ekki af forritum. Þetta er þar sem ósjálfstæði á klístruðum fundum kemur við sögu og slík skyndiminni þarf ekki að endurtaka, jafnvel þegar um er að ræða Active-Active stillingu.

Aðgerðartákn. Annað hugtak, venjulega notað fyrir ýmsar aðstæður þegar notandinn þarf til dæmis að gera eitthvað ósamstillt með pósti. Til dæmis meðan á aðgerðinni stendur forget password skyndiminni actionTokens notað til að rekja lýsigögn tengdra tákna - til dæmis hefur auðkenni þegar verið notað og ekki hægt að virkja það aftur. Þessa tegund af skyndiminni þarf venjulega að endurtaka á milli gagnavera.

Skyndiminni og öldrun geymdra gagna vinnur að því að létta álagi á gagnagrunninn. Þessi tegund af skyndiminni bætir árangur, en bætir við augljósu vandamáli. Ef einn Keycloak netþjónn uppfærir gögn þarf að láta hina netþjónana vita svo þeir geti uppfært gögnin í skyndiminni sinni. Keycloak notar staðbundin skyndiminni realms, users и authorization til að vista gögn úr gagnagrunninum.

Það er líka sérstakt skyndiminni work, sem er endurtekið í öllum gagnaverum. Það sjálft geymir engin gögn úr gagnagrunninum, en þjónar til að senda skilaboð um öldrun gagna til þyrpingahnúta milli gagnavera. Með öðrum orðum, um leið og gögnin eru uppfærð sendir Keycloak hnúturinn skilaboð til annarra hnúta í gagnaveri sínu, sem og hnúta í öðrum gagnaverum. Eftir að hafa fengið slík skilaboð hreinsar hver hnútur samsvarandi gögn í staðbundnum skyndiminni.

Notendalotur. Skyndiminni með nöfnum sessions, clientSessions, offlineSessions и offlineClientSessions, eru venjulega afritaðar á milli gagnavera og þjóna til að geyma gögn um notendalotur sem eru virkar á meðan notandinn er virkur í vafranum. Þessar skyndiminni vinna með forritinu sem vinnur úr HTTP beiðnum frá endanlegum notendum, þannig að þær eru tengdar klístruðum lotum og þarf að endurtaka þær á milli gagnavera.

Hrottafenginn kraftur. Skyndiminni loginFailures Notað til að rekja innskráningarvillugögn, svo sem hversu oft notandi sló inn rangt lykilorð. Afritun þessa skyndiminni er á ábyrgð stjórnanda. En fyrir nákvæman útreikning er þess virði að virkja afritun á milli gagnavera. En á hinn bóginn, ef þú afritar ekki þessi gögn, muntu bæta árangur og ef þetta vandamál kemur upp gæti afritun ekki verið virkjuð.

Þegar þú setur út Infinispan klasa þarftu að bæta skyndiminni skilgreiningum við stillingaskrána:

<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" />

Þú verður að stilla og ræsa Infinispan klasann áður en þú byrjar Keycloak klasann

Þá þarftu að stilla remoteStore fyrir Keycloak skyndiminni. Til að gera þetta dugar smáforrit sem er gert svipað og það fyrra sem er notað til að stilla breytuna CACHE_OWNERS, þú þarft að vista það í skrá og setja það í möppu /opt/jboss/startup-scripts:

Innihald handrits

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

Ekki gleyma að setja upp JAVA_OPTS fyrir Keycloak hnúta til að keyra HotRod: remote.cache.host, remote.cache.port og nafn þjónustu jboss.site.name.

Tenglar og viðbótarskjöl

Greinin var þýdd og unnin fyrir Habr af starfsmönnum Slurm þjálfunarmiðstöð — ákafur námskeið, myndbandsnámskeið og fyrirtækjaþjálfun frá starfandi sérfræðingum (Kubernetes, DevOps, Docker, Ansible, Ceph, SRE)

Heimild: www.habr.com

Bæta við athugasemd