Mlaku Keycloak ing mode HA ing Kubernetes

Mlaku Keycloak ing mode HA ing Kubernetes

TL; DR: bakal ana katrangan babagan Keycloak, sistem kontrol akses sumber terbuka, analisis struktur internal, rincian konfigurasi.

Pambuka lan Gagasan Utama

Ing artikel iki, kita bakal weruh gagasan dhasar sing kudu dieling-eling nalika nggunakake kluster Keycloak ing ndhuwur Kubernetes.

Yen sampeyan pengin ngerti luwih akeh babagan Keycloak, deleng pranala ing pungkasan artikel. Supaya luwih nyemplungaken ing laku, sampeyan bisa sinau gudang kita kanthi modul sing ngetrapake gagasan utama artikel iki (panduan peluncuran ana, artikel iki bakal menehi ringkesan piranti lan setelan, kira-kira. penerjemah).

Keycloak minangka sistem lengkap sing ditulis ing Jawa lan dibangun ing ndhuwur server aplikasi Kelinci. Ing cendhak, iku framework kanggo wewenang sing menehi pangguna aplikasi federasi lan SSO (single sign-on) kapabilitas.

Kita ngajak sampeyan maca resmi situs web utawa Wikipedia kanggo pangerten rinci.

Nguripake Keycloak

Keycloak mbutuhake rong sumber data sing terus-terusan kanggo mbukak:

  • Basis data sing digunakake kanggo nyimpen data sing wis ditemtokake, kayata informasi pangguna
  • Cache Datagrid, sing digunakake kanggo cache data saka database, uga kanggo nyimpen sawetara metadata short-urip lan asring ngganti, kayata sesi panganggo. Dilaksanakake Infinispan, sing biasane luwih cepet tinimbang database. Nanging ing kasus apa wae, data sing disimpen ing Infinispan iku ephemeral - lan ora perlu disimpen ing ngendi wae nalika kluster diwiwiti maneh.

Keycloak dianggo ing papat mode beda:

  • biasa - siji lan mung siji proses, diatur liwat file mandiri.xml
  • Kluster biasa (pilihan kasedhiyan dhuwur) - kabeh pangolahan kudu nggunakake konfigurasi padha, kang kudu diselarasake kanthi manual. Setelan disimpen ing file mandiri-ha.xml, Kajaba iku, sampeyan kudu nggawe akses bareng menyang database lan load balancer.
  • Kluster domain - miwiti kluster ing mode normal cepet dadi rutin lan mboseni tugas minangka kluster mundak akeh, wiwit saben owah-owahan konfigurasi, kabeh owah-owahan kudu digawe ing saben simpul cluster. Mode operasi domain ngatasi masalah iki kanthi nyetel sawetara lokasi panyimpenan sing dienggo bareng lan nerbitake konfigurasi kasebut. Setelan iki disimpen ing file domain.xml
  • Replikasi antarane pusat data - yen sampeyan pengin mbukak Keycloak ing klompok sawetara pusat data, paling asring ing lokasi geografis beda. Ing pilihan iki, saben pusat data bakal duwe kluster server Keycloak dhewe.

Ing artikel iki, kita bakal nimbang kanthi rinci pilihan kapindho, yaiku kluster biasa, lan kita uga bakal nutul sethitik ing topik replikasi antarane pusat data, awit iku ndadekake pangertèn kanggo mbukak rong pilihan iki ing Kubernetes. Untunge, ing Kubernetes ora ana masalah karo nyinkronake setelan sawetara pod (node ​​Keycloak), dadi kluster domain Ora bakal angel ditindakake.

Uga elinga yen tembung kasebut kluster kanggo liyane saka artikel bakal aplikasi mung kanggo klompok kelenjar Keycloak makarya bebarengan, ana ora perlu kanggo deleng klompok Kubernetes.

Kluster Keycloak biasa

Kanggo mbukak Keycloak ing mode iki sampeyan kudu:

  • ngatur database sambungan eksternal
  • nginstal load balancer
  • duwe jaringan internal kanthi dhukungan multicast IP

Kita ora bakal ngrembug babagan nyetel database eksternal, amarga dudu tujuan artikel iki. Ayo nganggep yen ana database sing bisa digunakake ing endi wae - lan kita duwe titik sambungan. Kita mung bakal nambah data iki menyang variabel lingkungan.

Kanggo luwih ngerti carane Keycloak dianggo ing failover (HA) kluster, iku penting kanggo ngerti carane akeh iku kabeh gumantung Kapabilitas clustering Wildfly.

Wildfly nggunakake sawetara subsistem, sawetara digunakake minangka load balancer, sawetara kanggo toleransi fault. Load balancer njamin kasedhiyan aplikasi nalika simpul kluster kakehan, lan toleransi kesalahan njamin kasedhiyan aplikasi sanajan sawetara kelenjar kluster gagal. Sawetara subsistem kasebut:

  • mod_cluster: Works magepokan karo Apache minangka HTTP load balancer, gumantung ing TCP multicast kanggo nemokake host minangka standar. Bisa diganti karo imbangan njaba.

  • infinispan: A cache mbagekke nggunakake saluran JGroups minangka lapisan transportasi. Kajaba iku, bisa nggunakake protokol HotRod kanggo komunikasi karo kluster Infinispan eksternal kanggo nyinkronake isi cache.

  • jgroups: Nyedhiyani dhukungan komunikasi klompok kanggo layanan sing kasedhiya adhedhasar saluran JGroups. Pipa sing dijenengi ngidini conto aplikasi ing kluster disambungake menyang klompok supaya komunikasi nduweni sifat kayata linuwih, ketertiban, lan sensitivitas kanggo gagal.

Load Balancer

Nalika nginstal balancer minangka pengontrol ingress ing kluster Kubernetes, penting kanggo mbudidaya prekara ing ngisor iki:

Keycloak nganggep yen alamat remot klien sing nyambung liwat HTTP menyang server otentikasi minangka alamat IP nyata saka komputer klien. Setelan Balancer lan ingress kudu nyetel header HTTP kanthi bener X-Forwarded-For и X-Forwarded-Proto, lan uga nyimpen judhul asli HOST. Versi paling anyar ingress-nginx (>0.22.0) disables iki minangka standar

Ngaktifake gendera proxy-address-forwarding kanthi nyetel variabel lingkungan PROXY_ADDRESS_FORWARDING в true menehi Keycloak pangerten sing digunakake konco proxy.

Sampeyan uga kudu ngaktifake sesi caket ing mlebu. Keycloak nggunakake cache Infinispan sing disebarake kanggo nyimpen data sing ana gandhengane karo sesi otentikasi saiki lan sesi pangguna. Cache operate karo pemilik siji minangka standar, kanthi tembung liya, sesi tartamtu disimpen ing sawetara simpul ing kluster, lan simpul liyane kudu takon saka jarak jauh yen mbutuhake akses menyang sesi kasebut.

Khusus, bertentangan karo dokumentasi, nempelake sesi kanthi jeneng cookie ora bisa digunakake kanggo kita AUTH_SESSION_ID. Keycloak nduweni loop pangalihan, mula disaranake milih jeneng cookie sing beda kanggo sesi lengket.

Keycloak uga nempelake jeneng simpul sing nanggapi pisanan AUTH_SESSION_ID, lan amarga saben simpul ing versi sing kasedhiya banget nggunakake database sing padha, saben simpul kudu duwe pengenal simpul sing kapisah lan unik kanggo ngatur transaksi. Dianjurake kanggo nyelehake ing JAVA_OPTS paramèter jboss.node.name и jboss.tx.node.id unik kanggo saben simpul - sampeyan bisa, contone, sijine jeneng polong. Yen sampeyan sijine jeneng pod, aja lali babagan 23 watesan karakter kanggo variabel jboss, supaya luwih apik nggunakake StatefulSet tinimbang Deployment.

Rake liyane - yen polong dibusak utawa diwiwiti maneh, cache bakal ilang. Njupuk akun iki, iku worth nyetel nomer pamilik cache kanggo kabeh caches kanggo paling ora loro, supaya salinan cache bakal tetep. Solusi kanggo mbukak script kanggo Wildfly nalika miwiti pod, manggonke ing direktori /opt/jboss/startup-scripts ing wadhah:

Isi Skrip

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

banjur atur nilai variabel lingkungan CACHE_OWNERS menyang dibutuhake.

Jaringan pribadi kanthi dhukungan multicast IP

Yen sampeyan nggunakake Weavenet minangka CNI, multicast bakal langsung bisa - lan simpul Keycloak bakal weruh saben liyane sanalika padha dibukak.

Yen sampeyan ora duwe dhukungan multicast ip ing kluster Kubernetes, sampeyan bisa ngatur JGroups kanggo nggarap protokol liyane kanggo nemokake simpul.

Opsi pisanan yaiku nggunakake KUBE_DNSsing nggunakake headless service kanggo nemokake simpul Keycloak, sampeyan mung ngliwati JGroups jeneng layanan sing bakal digunakake kanggo nemokake simpul kasebut.

Pilihan liyane yaiku nggunakake metode kasebut KUBE_PING, sing dianggo karo API kanggo nggoleki simpul (sampeyan kudu ngatur serviceAccount kanthi hak list и get, banjur atur pods kanggo nggarap iki serviceAccount).

Cara JGroups nemokake simpul dikonfigurasi kanthi nyetel variabel lingkungan JGROUPS_DISCOVERY_PROTOCOL и JGROUPS_DISCOVERY_PROPERTIES. kanggo KUBE_PING sampeyan kudu milih pods kanthi takon namespace и labels.

️ Yen sampeyan nggunakake multicast lan mbukak loro utawa luwih kluster Keycloak ing siji kluster Kubernetes (kayata siji ing namespace production, sing nomer loro - staging) - simpul siji kluster Keycloak bisa gabung kluster liyane. Priksa manawa sampeyan nggunakake alamat multicast unik kanggo saben kluster kanthi nyetel variabeljboss.default.multicast.address и jboss.modcluster.multicast.address в JAVA_OPTS.

Replikasi antarane pusat data

Mlaku Keycloak ing mode HA ing Kubernetes

Konektivitas

Keycloak nggunakake macem-macem kluster cache Infinispan sing kapisah kanggo saben pusat data ing ngendi kluster Keycloack sing digawe saka simpul Keycloak dumunung. Nanging ora ana bedane antarane simpul Keycloak ing pusat data sing beda.

Kelenjar Keycloak nggunakake Grid Data Jawa eksternal (server Infinispan) kanggo komunikasi antarane pusat data. Komunikasi dianggo miturut protokol Infinispan HotRod.

Infinispan caches kudu diatur karo atribut remoteStore, supaya data bisa disimpen saka adoh (ing pusat data liyane, kira-kira. penerjemah) caches. Ana kluster infinispan sing kapisah ing antarane server JDG, supaya data disimpen ing JDG1 ing situs. site1 bakal ditiru menyang JDG2 ing situs site2.

Lan pungkasane, server JDG sing nampa menehi kabar marang server Keycloak kluster kasebut liwat sambungan klien, sing minangka fitur protokol HotRod. Node keycloak aktif site2 nganyari cache Infinispan lan sesi pangguna tartamtu uga kasedhiya ing kelenjar Keycloak ing site2.

Kanggo sawetara caches, iku uga bisa kanggo ora nggawe serep lan supaya data nulis liwat server Infinispan tanggung. Kanggo nindakake iki, sampeyan kudu mbusak setelan kasebut remote-store cache Infinispan tartamtu (ing file mandiri-ha.xml), sawise sawetara tartamtu replicated-cache uga ora perlu maneh ing sisih server Infinispan.

Nyetel caches

Ana rong jinis cache ing Keycloak:

  • lokal. Dumunung ing jejere database lan serves kanggo nyuda beban ing database, uga kanggo nyuda latensi respon. Jinis cache nyimpen realm, klien, peran, lan metadata pangguna. Jinis cache iki ora ditiru, sanajan cache minangka bagéan saka kluster Keycloak. Yen entri ing cache diganti, pesen babagan owah-owahan dikirim menyang server sing isih ana ing kluster, sawise entri kasebut ora kalebu saka cache. Waca katrangan work Deleng ing ngisor iki kanggo katrangan sing luwih rinci babagan prosedur kasebut.

  • Replika. Ngolah sesi pangguna, token offline, lan uga ngawasi kesalahan login kanggo ndeteksi upaya phishing sandi lan serangan liyane. Data sing disimpen ing cache iki sauntara, mung disimpen ing RAM, nanging bisa ditiru ing kluster.

Infinispan caches

Sesi - konsep ing Keycloak, caches kapisah disebut authenticationSessions, digunakake kanggo nyimpen data pangguna tartamtu. Panjaluk saka cache iki biasane dibutuhake dening browser lan server Keycloak, dudu dening aplikasi. Iki minangka katergantungan ing sesi lengket, lan cache kasebut ora perlu ditiru, sanajan ing mode Aktif-Aktif.

Token Tindakan. Konsep liyane, biasane digunakake kanggo macem-macem skenario nalika, contone, pangguna kudu nindakake soko asynchronously dening mail. Contone, sajrone prosedur forget password cache actionTokens digunakake kanggo nglacak metadata token sing gegandhengan - contone, token wis digunakake lan ora bisa diaktifake maneh. Jinis cache iki biasane kudu ditiru ing antarane pusat data.

Caching lan tuwa saka data sing disimpen dianggo kanggo ngredhakaké beban ing database. Caching jinis iki nambah kinerja, nanging nambah masalah sing jelas. Yen salah siji server Keycloak nganyari data, server liyane kudu diwenehi kabar supaya bisa nganyari data ing cache. Keycloak nggunakake cache lokal realms, users и authorization kanggo cache data saka database.

Ana uga cache sing kapisah work, sing ditiru ing kabeh pusat data. Iku dhewe ora nyimpen data saka database, nanging serves kanggo ngirim pesen bab tuwa data kanggo kluster kelenjar antarane pusat data. Ing tembung liya, sanalika data dianyari, simpul Keycloak ngirim pesen menyang simpul liyane ing pusat data, uga simpul ing pusat data liyane. Sawise nampa pesen kasebut, saben simpul mbusak data sing cocog ing cache lokal.

Sesi pangguna. Cache karo jeneng sessions, clientSessions, offlineSessions и offlineClientSessions, biasane ditiru ing antarane pusat data lan digunakake kanggo nyimpen data babagan sesi pangguna sing aktif nalika pangguna aktif ing browser. Cache iki bisa digunakake karo aplikasi ngolah panjalukan HTTP saka pangguna pungkasan, mula digandhengake karo sesi lengket lan kudu ditiru ing antarane pusat data.

pangayoman brute force. Cache loginFailures Digunakake kanggo nglacak data kesalahan login, kayata kaping pirang-pirang pangguna ngetik sandhi sing salah. Replikasi cache iki tanggung jawab administrator. Nanging kanggo pitungan sing akurat, kudu ngaktifake replikasi ing antarane pusat data. Nanging ing sisih liya, yen sampeyan ora niru data iki, sampeyan bakal nambah kinerja, lan yen masalah iki muncul, replikasi bisa uga ora diaktifake.

Nalika nggulung kluster Infinispan, sampeyan kudu nambah definisi cache menyang file setelan:

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

Sampeyan kudu ngatur lan miwiti kluster Infinispan sadurunge miwiti kluster Keycloak

Banjur sampeyan kudu ngatur remoteStore kanggo Keycloak caches. Kanggo nindakake iki, skrip cukup, sing ditindakake kanthi cara sing padha karo sing sadurunge, sing digunakake kanggo nyetel variabel CACHE_OWNERS, sampeyan kudu nyimpen menyang file lan sijine ing direktori /opt/jboss/startup-scripts:

Isi Skrip

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

Aja lali nginstal JAVA_OPTS kanggo simpul Keycloak kanggo mbukak HotRod: remote.cache.host, remote.cache.port lan jeneng layanan jboss.site.name.

Link lan dokumentasi tambahan

Artikel kasebut diterjemahake lan disiapake kanggo Habr dening karyawan Pusat pelatihan Slurm - kursus intensif, kursus video lan pelatihan perusahaan saka spesialis praktik (Kubernetes, DevOps, Docker, Ansible, Ceph, SRE)

Source: www.habr.com

Add a comment