Dette dokument beskriver arkitekturen af de etablerede Keycloak instanser i NSP og hvorledes de sammen udgør et keycloak cluster i NSP.

Nedenstående tegning viser 1 instans af Keycloak (node) i clusteret. Noden består af en virtuel maskine hvorpå der afvikles en Keycloak server vha. Docker Compose. Dvs. clusteret vil bestå af f.eks. 3 tilsvarende virtuelle maskiner.

Databasen og NSP netværkskomponenten (LB) er fælles for det samlede Keycloak cluster. Databasen er en MariaDB.



Som det også fremgår på tegningen ovenfor, vil kald til Keycloak gå igennem en loadbalancer som ikke terminere TLS forbindelserne. Loadbalanceren foretager udelukkende loadbalancing og etablerer ”sticky” sessioner til de enkelte instanser baseret på klientens IP adresser.

På hver instans kører der en NGINX reverse proxy sammen med Keycloak. Formålet med denne NGINX er

NSP Keycloak image

Der anvendes et Keycloak image som indeholder specifikke komponenter specielt udviklet til NSP. Dette image er baseret på det officielle Keycloak Docker image (se https://quay.io/repository/keycloak/keycloak). Dvs. al konfiguration og drift af Keycloak som Docker container beskrevet på https://www.keycloak.org/ er stadig aktuel. Der er dog truffet specifikke konfigurationsvalg i NSP Keycloak, og de specialudviklede komponenter har ligeledes specifikke konfigurationsparametre. Disse er beskrevet i installationsvejledningen.

TLS og mTLS

Adgangen til Keycloak sker udelukkende via enten TLS eller mTLS. Server certifikaterne udstedes af generelt trustede CA'er som anvendes i NSP.

Validering af mTLS klientcertifikater

Opgaven med at validerer mTLS klientcertifikater er delt mellem NGINX (se diagram nedenfor) og Keycloak.




Validering af trust i NSP Netværkskomponenten

NGINX terminerer TLS forbindelse. Dette betyder at server certifikatet er installeret i denne komponent.

Der laves optionelt klient autentifikation hvis klienten sender certifikater med ved etablering at TLS forbindelsen. NGINX verificerer at klient certifikatet er trusted. Trust er konfigureret med OCES3 Rod certifikatet (produktion eller test) og det forventes at klienten medsender intermediate (udstedende) CA certifikat sammen med klient certifikatet. Hvis der ikke medsendes intermediate certifikat så der kan etableres en trusted kæde til rod CA'en skal NSP Netværkskomponenten afvise klienten.

Hvis der etables en mTLS forbindelse med et trusted klientcertifikat, indsætter NSP Netværkskomponenten klientcertifikatet som http headers i request til Keycloak. Navngivning af denne header er gjort i både NSP Netværkskomponentens konfigurationen og i konfigurationen af Keycloak.

Validering i Keycloak

Når en request skal autoriseres via klientcertifikater i Keycloak gøres det på følgende vis:

OCES 3 mTLS klientcertifikater

Klientcertifikater skal være OCES3 certifikater. 

Format af Subject på mTLS klientcertifikater

Ved registrering af klienter skal certifikat subject dn angives i format som specificeret i RFC4514 (se https://datatracker.ietf.org/doc/html/rfc8705#section-2.1.2).

Dette er beklageligvis ikke det format som vises af f.eks. openssl. Eksempelvis vises subject dn for et OCES 3 test certifikat som følgende tekst streng af openssl's x509 kommando:

openssl x509 -in system-1.crt -subject -nocert

subject=CN=System 1, serialNumber=UI:DK-O:G:7bd0d84a-c1f3-4650-a351-4235c482ebeb, O=Testorganisation nr. 96024140, organizationIdentifier=NTRDK-96024140, C=DK

Den korrekte repræsentation af dette DN er jf. RFC4514 :

C=DK,2.5.4.97=#0c0e4e5452444b2d3936303234313430,O=Testorganisation nr. 96024140,2.5.4.5=#132e55493a444b2d4f3a473a37626430643834612d633166332d343635302d613335312d343233356334383265626562,CN=System 1

Keycloak benytter Java metoden

X509Certificate.getSubjectX500Principal().getName(X500Principal.RFC2253, CUSTOM_OIDS)

hvor 

Map<String, String> CUSTOM_OIDS = new HashMap<>();
CUSTOM_OIDS
.put("2.5.4.5", "serialNumber".toUpperCase());
CUSTOM_OIDS.put("2.5.4.15", "businessCategory".toUpperCase());
CUSTOM_OIDS.put("1.3.6.1.4.1.311.60.2.1.3", "jurisdictionCountryName".toUpperCase());
CUSTOM_OIDS.put("1.2.840.113549.1.9.1", "emailAddress".toUpperCase());

til at finde en streng repræsentation af det anvendte klientcertifikat og benytter denne streng til at verificerer den specificerede tls_client_auth_subject_dn i metadata. 

Det betyder at Subject (fra openssl) 

CN=System 1, serialNumber=UI:DK-O:G:7bd0d84a-c1f3-4650-a351-4235c482ebeb, O=Testorganisation nr. 96024140, organizationIdentifier=NTRDK-96024140, C=DK

Skal angives i metadata filerne med følgende værdi:

"tls_client_auth_subject_dn": "C=DK,2.5.4.97=#0c0e4e5452444b2d3936303234313430,O=Testorganisation nr. 96024140,SERIALNUMBER=UI:DK-O:G:7bd0d84a-c1f3-4650-a351-4235c482ebeb,CN=System 1"

Forskellen er

NSP specifikke komponenter i Keycloak 

I dette afsnit er formål og funktionalitet i de forskellige NSP specfikke udvidelser af Keycloak dokumenteret.

NSP CRA Service

Integrationen til CRA er implementeret som en Keycloak SPI "NspCraSpi". Denne service loader en cachet version af CRA databasen i et memory map, og benytter dette til at lave revokeringscheck.

Indlæsning af CRA

Alle CRL'er i CRA databasen indlæses i et map fra CRL url til et sæt af serienumre.

Derefter indlæses alle ICA'er. For hver ICA verificeres det om ICA er spærret via de netop indlæste CRL'er. ICA's revokeringsstatus gennes i et map fra ICA subject DN til en boolean som indikerer om ICA er spærret eller ej.

Revokeringscheck

Revokeringscheck af et certifikat i servicen verificerer følgende:

  1. Findes certifikates crl distribution point i CRA
    1. Hvis ikke betragtes certifikat som spærret
  2. Check om certifikatets serienummer står på spærrelisten i CRA.
  3. Check om certifikatets issuer er kendt i CRA.
    1. Hvis ikke betragtes ICA som spærret.
  4. Check om  certifikatets issuer er spærret.

Revokeringscheck returnerer kun true hvis hverken certifikat eller ICA ikke er spærret.

Client authenticator OCES3

Dette er en variant af den indbyggede X509ClientAuthenticator i Keycloak. Den adskiller sig primært fra den indbyggede X509ClientAuthenticator på følgende vis:


EHMI DCR Client Registration provider

Dette client registration provider udvider den indbyggede provider i Keycloak med proprietære felter som defineret i EHMI klient registrerings metadata.

Der er følgende udvidelser i provideren:

FunktionBeskrivelse
Registrer whitelistede GLN/SOR koderDette gøres ved dynamisk at sætte tilladte "GLN:" og "SOR:" scopes fra klient metadata på klienten. Disse bruges senere af EHMI Client Policy Executor til at whiteliste forespurgte GLN/SOR scopes.
Sæt audience for klientenSætter den proprietære metadata attribut "audience" som en klient attribut. Denne kan senere bruges af EHMIAudienceMapper til at sætte audience på tokens for klienten.
Sæt default client scopeAfhængigt at om der i metadata forespørges grant type "client_credentials" eller "authorization_code" sættes et Keycloak client scope (enten "EHMI-systemklient" eller "EHMI-brugerklient") Disse client scopes bruges til at definerer de nødvendige mappers for hhv. system og brugerklienter.

EHMI Client Policy executor

Denne udfører whitelisting af visse requestede scopes (GLN og SOR koder). De for klienten (deviceid) tilladte GLN og SOR koder er registreret som attributter på klienten, og sættes ved oprettelse af klienten med den tilpasserede DCR Client registration provider.

Executoren betyder at autentifikations forespørgslen fejler med en "invalid_scope" OAuth2 fejl hvis klienten ikke tillader de forespurgte SOR/GLN koder i scopes.

OICD Protocol Mappers

Der er implementeret en række forskellige mappers i NSP Keycloak som benyttes til at indsætte claims i de udstedte access/ id tokens.

Java klasseNavn (ses i Keycloak UI)Beskrivelse
EHMIClaimMapper
EHMI Claim Mapper

Indsætter hhv. ehmi:eer:device_id og ehmi:org_context i access tokens. 

ehmi:eer:device_id kommer er gemt som en attribut på den klient hvortil der logges ind.

ehmi:org_context er generet af en policy executor som whitelister den requestede context, og gemmer den i en såkaldt AuthNote i Keycloak sessionen.

AgeAboveMapper
Above age mapper (*)

Denne mapper indsætter en claim med værdien true eller false afhængig af brugeren alder. Den kan f.eks. bruges til at indsætte claim "over_15" eller "over_18" som beskrevet i JTP-H profilen. Bemærk dog, at den ikke bruges i første deployment i EHMI.

EHMIAudienceMapper
 EHMI Audience Mapper

Opdaterer aud claim i tokens til det registrerede audience for klienten (Dette registreres via den proprietære attribut "audience" i klient registrerings metadata.)

SubjectTemplateUserNoteMapper
Usernote Subject Override 
Mapper

Opdaterer sub claims i tokens baseret på en template som udfyldes med de Keycloak Usernotes som er tilgængelige. Der sættes f.eks. en usernote i "Client authenticator OCES3" som indeholder brugeren MitID UUID.

UserAttributeTemplateMapper
User attribute template 
mapper (*)

Indsætter en navngiven claim med en værdi som udfyldes på baggrund af en template tekst hvor tags udfyldes med user attributes. Disse user attributter sættes normalt via identity provider mappers, og kan således være vilkårlige felter som kommer fra SEB SAML assertionen.

OIOBPPMapper
OIO Basic privileges mapper

Denne mapper indsætter en claim i tokens med brugeren privilegier.

Det antages af brugeren har en attribut med privilegier udtryk som beskrevet i ”OIO Basic Privilege Profile 1.2” (https://digst.dk/media/20999/oiosaml-basic-privilege-profile-1_2.pdf)

Disse privilegier konverteres til JSON som beskrevet i “OIO JWT Token profile 0.91”, (https://digst.dk/media/24668/oio-jwt-token-profile-091.pdf) og indsættes som en claim i tokens.