Toen we hoorden dat JIDOKA een Hackathon organiseerde, wisten we meteen welke uitdaging we wilden aangaan. Die uitdaging bleef zich voordoen tijdens interne projecten:
- “Wie ben je en wat mag je doen?”
Context
Elke interne JIDOKA app had zijn eigen Identity en Access Managementsysteem, de een al wat geavanceerder dan de ander. Het doel van ons team was om deze systemen te vereenvoudigen en te standaardiseren door ze te migreren naar één enkele bron van waarheid die ze allemaal zou beheersen.
Tijdens onze voorbereiding zochten we naar mogelijke kandidaten voor het Identity en Access Management framework. We hebben vrij snel gekozen voor Keycloak omdat het:
- Goed onderhouden is
- Gratis is
- Self-hosted is
- Open-source is
Vervolgens moesten we een project kiezen dat zou dienen als ons offer aan de hackathon-codeergoden. Onze voorkeur ging uit naar de interne cv-app die samengevat kon worden als:
- Geschreven in Angular
- Gebruikt een self-rolled Identity en Access Managementsysteem
- Ondersteund door een Spring Boot backend
- Één van de hackathon-teamleden had deze aanvraag oorspronkelijk meegeschreven, wat een pluspunt was
Doordat JIDOKA gebruik maakt van LDAP voor onze interne Atlassian stack, kwam er een extra vereiste naar voren. We wilden deze gegevensbron blijven gebruiken na de migratie naar Keycloak. Dit zou ertoe leiden dat bestaande gebruikers kunnen inloggen op Keycloak met behulp van hun LDAP-referenties en dat nieuw aangemaakte gebruikers worden gesynchroniseerd met de LDAP.
Samengevat was ons doel om een standalone Keycloak instance op te zetten, deze te integreren met de LDAP en de cv-app aan te passen om Keycloak te gebruiken.
En dan begint het…
… met lezen?
Onze aanpak bestond vooral uit documentatie lezen… Belachelijk veel documentatie…
Eerst moesten we ons vertrouwd maken met de basisprincipes van Keycloak:
- de vele mogelijke functies die het biedt
- de beste manier om een instantie in onze architectuur aan de praat te krijgen
- hoe het past in het oauth2-ecosysteem
- de vele verschillende termen van Keycloak
- hoe de instantie daadwerkelijk configureren
Een ontwikkelingsomgeving op gang brengen
Voor de infrastructuur op gang te brengen gingen we voor de mainstreamaanpak, we creëerden docker containers voor:
- opendj
- Keycloak
- postgresql-databank
De exacte configuratie voor deze infrastructuur vindt is hieronder te vinden. De JIDOKA-ldap-afbeelding is een op maat gemaakte dockerimage die we hebben gemaakt, omdat er op dat moment geen publieke image was die wij geschikt vonden. Deze image levert een volledig geconfigureerde instantie op zonder enige gebruikersinteractie, ready to rock and roll.
Al de rest is meestal standaard. We wilden voorbereid zijn op het moment dat deze POC ooit in PRODUCTIE zou landen, dus hebben we enkele standaardinstellingen aangepast. Eén daarvan is de standaard Keycloak-databank, een in-memory H2-databank, die meestal nuttig is om er wat mee te spelen. In plaats daarvan zijn we overgestapt op een PostgreSQL-databank, met een eenvoudige toekomstige back-up in het achterhoofd. Om te voorkomen dat de ontwikkelaars teveel setup-gedoe hebben, zal Keycloak een configuratiebestand (.json) laden, dat resulteert in een volledig geconfigureerd REALM. Deze configuratie bevat:
- user federation (LDAP-verbinding)
- identity provider (LinkedIn-verbinding)
- realm roles
- client
version: "3.7"
services:
jidoka-ldap:
image: nexus.jidoka.be:3000/jidoka-ldap:0.0.2
container_name: jidoka-ldap
ports:
- 1389:1389
jidoka-keycloak-db:
image: postgres:12.1
container_name: jidoka-keycloak-db
ports:
- 5499:5432
environment:
- POSTGRES_PASSWORD=
- POSTGRES_USER=
- POSTGRES_DB=keycloak
jidoka-keycloak:
image: jboss/keycloak:8.0.1
container_name: jidoka-keycloak
ports:
- 8484:8080
environment:
- DB_ADDR=jidoka-keycloak-db
- DB_PORT=5432
- DB_USER=
- DB_PASSWORD=
- DB_VENDOR=postgres
- KEYCLOAK_USER=
- KEYCLOAK_PASSWORD=
- KEYCLOAK_IMPORT=/opt/jidoka/config/jidoka-realm.json
volumes:
- ./jidoka-keycloak/config:/opt/jidoka/config:ro
depends_on:
- jidoka-ldap
- jidoka-keycloak-db
De frontend migreren
Volgende: cv-app migratie.
Men zou meestal gebruik maken van keycloak-js, maar in plaats daarvan we hebben gekozen voor Keycloak-Angular. Deze bibliotheek behandelt automatisch het beheer van de token, wat onze zakelijke logica een stuk vereenvoudigt.
We hebben een Angular app initializer toegevoegd die de applicatie zou blokkeren totdat de keycloak het inlogproces heeft opgelost. Zodra deze fase voorbij is, wordt de gebruiker ingelogd, de laadstatus verdwijnt en is de applicatie klaar om gebruikt te worden. Eventuele Authenticatie-headers tijdens http-calls en het vernieuwen van token shenanigans worden automatisch opgelost door Keycloak-Angular. Uitloggen is ook zo eenvoudig als het opvragen van een methode op de keycloak instance.
Vergeet de backend niet
De authenticatie en autorisatie in de cv-app was vrij eenvoudig te verwijderen. Zodat we uiteindelijk een schone lei kregen en een wereld van mogelijkheden om authenticatie en autorisatie op een nieuwe manier in te voeren.
Met behulp van Spring was de migratie naar Keycloak niet het moeilijkste om te doen. De ontwerpers van Keycloak hebben een Spring Boot starter (keycloak-spring-boot-2-starter) gemaakt die wat magie en gemak van integratie toevoegt.
Slechts met een paar regels van de configuratie
keycloak:
auth-server-url: http://localhost:8484/auth
realm: <realm>
resource: <client_id>
bearer-only: true
En het verstrekken van een bean die de KeycloakWebSecurityConfigurerAdapter implementeert
@KeycloakConfiguration
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
web.ignoring()
.antMatchers(OPTIONS)
.antMatchers(GET, "/info");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests().anyRequest().authenticated();
}
@Autowired
void configureGlobal(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(super.keycloakAuthenticationProvider());
}
@Bean
@Override
@ConditionalOnMissingBean(HttpSessionManager.class)
protected HttpSessionManager httpSessionManager() {
return new HttpSessionManager();
}
@Bean
KeycloakConfigResolver keycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new NullAuthenticatedSessionStrategy();
}
}
De achterkant was volledig geconfigureerd. Toch was dit niet het einde voor deze migratie. Er zijn natuurlijk bedrijfsstromen die moesten veranderen en die namen de rest van de tijd in de hackathon in beslag.
Toen was er nog wat cultuur
Op slechts enkele kilometers van onze weekendlocatie was er een goede plaats die Belgium Peak Beer heet. Met een verplichte pauze was dit het ideale moment om in de auto te stappen voor wat hapjes (maar vooral om wat biertjes te proeven). Als je in de buurt bent, raden we je ten zeerste aan om daar even langs te gaan.
Het resultaat
Uiteindelijk hebben we onze doelstellingen bereikt om de cv-app te integreren met een Identity en Access Managementsysteem. Het kunnen demonstreren van alle functionele stromen die de applicatie bevatte. Zelfs het kunnen toevoegen van enkele extra features die op het verlanglijstje van onze HR-manager stonden, om een indicatie te geven van wat er mogelijk is.
Wat is het volgende?
Omdat de context was om het te laten werken, niet om het mooi te maken (of te testen), moet er nog veel opruiming gebeuren voordat we het naar PRODUCTIE kunnen verzenden. Ook zou de JIDOKA-infrastructuur een Keycloak instance moeten inzetten, die door de huidige migratie van de infrastructuur naar K8S enigszins wordt verstoord. Eenmaal voltooid, blijft er slechts één taak over… Het herschrijven van de andere interne applicaties om Keycloak te gebruiken.