Guide pour déployer Keycloak sur Scalingo

4 octobre 2022 - 10 min de lecture
Guide pour déployer Keycloak sur Scalingo

Qu'est-ce que Keycloak ?

Keycloak est une solution open-source de gestion des identités et des accès (IAM) pour les applications et services web modernes. Les solutions IAM garantissent que les individus et les entités possédant une identité numérique disposent du bon niveau d'accès aux ressources de l'entreprise.

Cette solution offre un grand nombre de fonctionnalités, telles que l'authentification unique (SSO), la fédération d'utilisateurs, le courtage d'identité, la connexion sociale, l'authentification à deux facteurs,...

Keycloak est basé sur des protocoles standards et offre un support pour OpenID Connect, OAuth 2.0 et SAML (Security Assertion Markup Language).

Il est également personnalisable et extensible, ce qui en fait un produit très intéressant pour tout ce qui concerne la gestion des identités et des accès.

Cet article décrit les quelques étapes nécessaires au déploiement de Keycloak sur Scalingo. Il n'explique pas comment configurer votre (vos) realm(s) Keycloak. La configuration de Keycloak n'entre pas dans le cadre de cet article. Veuillez noter que même si nous ferons probablement de notre mieux pour vous aider avec Keycloak, nous ne fournissons pas d'instances Keycloak gérées.

Comment Keycloak peut-il être utilisé ?

La nature de Keycloak en tant que solution IAM lui permet d'être utilisé dans de multiples cas d'utilisation en fonction de vos besoins et de votre type d'organisation.

Attention cependant à une limite connue : pour l'heure, il n'est malheureusement pas possible de faire tourner Keycloak en mode Haute Disponibilité (HA) sur Scalingo. La principale conséquence est que l'ensemble des utilisateurs seront déconnectés à chaque redémarrage du container.

Déploiement de Keycloak sur Scalingo

Planification du déploiement

Avant de plonger dans les lignes de commande et les fichiers de configuration, je prends généralement le temps de réfléchir et de planifier un peu mon déploiement. Quels sont les logiciels requis ? Sont-ils disponibles ? Comment vais-je procéder ?

Dans le cas de Keycloak, voici quelques exigences à prendre en compte :

  • Tout d'abord, Keycloak est une application web Java, et elle nécessite Java 8 JRE ou Java 11 JRE.
  • Elle nécessite au moins 512 Mo de RAM.
  • Elle nécessite une base de données externe telle que PostgreSQL, MySQL, MariaDB, Oracle...
  • Il peut utiliser des variables d'environnement pour se configurer.

La liste officielle des exigences est disponible sur Keycloak documentation.

Ces quelques points nous amènent aux hypothèses suivantes :

  • Nous voulons déployer Keycloak 19.0.1, sorti le 29 juillet 2022.
  • Il existe une documentation expliquant [comment exécuter une application Java sur Scalingo, ce qui constitue un bon point de départ.
  • Nous aurons très probablement besoin d'un buildpack lié à Java. Plus précisément, en lisant la documentation mentionnée précédemment et en ne voyant aucune mention de Maven dans la documentation de Keycloak, nous devrons utiliser le buildpack buildpack-jvm-common à un moment donné.
  • Nous aurons besoin d'un conteneur web de taille M.
  • Nous aurons besoin d'un addon pour la base de données PostgreSQL. Un plan sandbox devrait être suffisant pour nos premiers tests.

Très bien, il est maintenant temps de se plonger dans le code !

Démarrage

Tout d'abord, et depuis le répertoire de travail de votre choix, téléchargez Keycloak et extrayez l'archive :

% curl -L -O https://github.com/keycloak/keycloak/releases/download/19.0.1/keycloak-19.0.1.tar.gz
% tar xvzf keycloak-19.0.1.tar.gz

Regardons ce que nous avons :

% tree -L 1 keycloak-19.0.1
keycloak-19.0.1
├── bin
├── conf
├── lib
├── LICENSE.txt
├── providers
├── README.md
├── themes
└── version.txt

5 directories, 3 files

Rien d'extraordinaire ici, mais nous pouvons quand même remarquer qu'il n'y a pas de fichier pom.xml dans le répertoire, ni de dossier .m2. Cela nous donne un autre indice que nous sommes très probablement dans le cas "Installation of JDK only (no Maven)".

OK, en gardant cela à l'esprit, continuons et créons notre application !

Création de l'application

Nous avons d'abord besoin d'un dépôt git pour suivre nos changements et les pousser vers Scalingo. Occupons-nous de cela :

# In the keycloak-19.0.1 directory:
% git init

# Add everything:
% git add .

# Create a first commit:
% git commit -m "First commit"

Ensuite, nous pouvons créer notre application. Nous allons utiliser la ligne de commande de Scalingo pour le faire :

# Create the application:
% scalingo create my-app

# Scale the web container to size M:
% scalingo --app my-app scale web:1:M

# Create the PostgreSQL database addon:
% scalingo --app my-app addons-add postgresql postgresl-sandbox

Notez que nous aurions pu utiliser notre tableau de bord pour faire la même chose.

Scalingo détecte automatiquement que nous sommes dans un dépôt git et, par conséquent, ajoute un remote git nommé scalingo.

Lier Keycloak aux ressources créées

Dans l'étape précédente, nous avons demandé à Scalingo de créer un addon de base de données pour Keycloak. Cet addon de base de données devrait maintenant être provisionné et prêt à être utilisé. Voyons donc comment lier cette base de données à notre future instance de Keycloak.

Parmi les dizaines de variables d'environnement disponibles pour configurer Keycloak, nous allons utiliser les suivantes :

  • KC_DB
  • KC_DB_URL
  • KC_DB_USERNAME
  • KC_DB_PASSWORD

Nous devons encore déterminer les valeurs à mettre. Pour KC_DB, c'est assez facile : nous avons choisi une base de données PostgreSQL, donc la valeur à fournir est postgres.

Les autres valeurs peuvent être déduites de la variable d'environnement SCALINGO_POSTGRESQL_URL qui a été provisionnée avec l'addon base de données. Nous devrons la décrypter, ce qui n'est pas si compliqué.

L'URL est, en fait, composée de 7 parties principales :

<protocol>://<username>:<password>@<host>:<port>/<database>?<parameters>

Nous allons utiliser ces parties pour définir les valeurs des variables d'environnement avec le mappage suivant :

  • KC_DB_USERNAME : <username>
  • KC_DB_PASSWORD : <password>
  • KC_DB_URL : jdbc:postgresql://<host>:<port>/<database>

Remarquez que nous avons ajouté le préfixe jdbc:postgresql:// à la valeur KC_DB_URL. Cette mise en forme est obligatoire et due au fait que Keycloak utilise une technologie appelée JDBC pour interagir avec la base de données.

Il y a encore un autre élément à prendre en compte. Bien que cela soit extrêmement improbable, la valeur SCALINGO_POSTGRESQL_URL pourrait encore changer dans le futur. Pour éviter les erreurs et les pannes de service dues à une telle situation, l'idéal serait de créer ces variables d'environnement automatiquement.

Créez un fichier nommé [create-env.sh](http://create-env.sh/) à la racine du répertoire keycloak-19.0.1 avec le contenu suivant, qui crée essentiellement les variables d'environnement requises à partir de la chaîne de connexion donnée :

#!/usr/bin/env bash

host=$( echo $SCALINGO_POSTGRESQL_URL | cut -d "@" -f2 | cut -d ":" -f1 )
username=$( echo $SCALINGO_POSTGRESQL_URL | cut -d "/" -f3 | cut -d ":" -f1 )
port=$( echo $SCALINGO_POSTGRESQL_URL | cut -d ":" -f4 | cut -d "/" -f1 )
password=$( echo $SCALINGO_POSTGRESQL_URL | cut -d "@" -f1 | cut -d ":" -f3 )
database=$( echo $SCALINGO_POSTGRESQL_URL | cut -d "?" -f1 | cut -d "/" -f4 )

export KC_DB="postgres"
export KC_DB_USERNAME="${username}"
export KC_DB_PASSWORD="${password}"
export KC_DB_URL="jdbc:postgresql://${host}:${port}/${database}"

Dire à Scalingo comment faire fonctionner Keycloak

Enfin, nous devons indiquer à Scalingo comment lancer Keycloak. Sans cette étape, et même si notre déploiement est réussi, Scalingo ne saura pas comment démarrer l'instance de Keycloak !

Heureusement, Scalingo prend en charge Procfile, ce qui nous permet de spécifier comment les conteneurs doivent démarrer.

Dans notre cas, le démarrage de Keycloak signifie deux choses :

  1. Créer les variables d'environnement nécessaires. Ceci est fait dans le script create-env.sh.
  2. Démarrer réellement Keycloak. Pour ce faire, Keycloak fournit un script bin/kc.sh (en fait, puisque l'application est déployée dans /app, la commande est /app/bin/kc.sh start-dev).

Demandons donc à notre conteneur web de lancer ces scripts quand il sera prêt ! Créez un fichier nommé Procfile à la racine du répertoire keycloak-19.0.1 avec le contenu suivant :

web: bash /app/create-env.sh && /app/bin/kc.sh start-dev

Validez les changements :

% git add Procfile
% git commit -m "Create Procfile"

Création de l'utilisateur admin.

Il y a encore une chose que nous devons régler avant d'essayer notre premier déploiement. Keycloak nécessite la création d'un utilisateur admin. Encore une fois, nous pouvons utiliser certaines variables d'environnement pour définir cet utilisateur. Keycloak prendra automatiquement ces valeurs et créera l'utilisateur (s'il n'existe pas encore) :

# These values are obviously not suitable for a production setup,
# please change them:
% scalingo --app my-app env-set KEYCLOAK_ADMIN=admin
% scalingo --app my-app env-set KEYCLOAK_ADMIN_PASSWORD=keycloak

Déploiement

Maintenant que tout semble prêt, il est temps d'essayer le premier déploiement ! Avec Scalingo, cela représente très peu d'efforts :

% git push scalingo master

Après un certain temps, vous verrez que le déploiement échoue :

Your deployment has been queued and is going to start…
<-- Start deployment of my-app -->
Fetching source code
Fetching deployment cache
!     We didn't find the type of technology you are using...
We're sorry this build is failing!

Le message d'erreur est assez simple et logique : dans ce cas particulier, et malgré tous ses efforts, Scalingo ne peut pas savoir quelle technologie est utilisée. C'est quelque chose que nous avons déjà considéré un peu plus tôt. Vous vous souvenez que nous devions probablement indiquer à Scalingo quel pack de construction utiliser ? Il semble que cette erreur le confirme, alors réparons-la !

Une fois de plus, nous allons le faire en définissant la variable d'environnement BUILDPACK_URL :

% scalingo --app my-app env-set BUILDPACK_URL="https://github.com/Scalingo/buildpack-jvm-common"

Nous pouvons maintenant déclencher un nouveau déploiement pour voir si les choses s'améliorent :

% git push scalingo master

Sélection de la version d'OpenJDK

Malheureusement, ce déploiement échoue à nouveau... mais sans le même message d'erreur, ce que nous pouvons considérer comme un bon point : nous allons de l'avant. Cette fois, la trace Java nous donne un bon indice de ce qui ne va pas :

-- Start deployment of my-app -->
Fetching source code
Fetching deployment cache
-----> Cloning custom buildpack: <https://github.com/Scalingo/buildpack-jvm-common#master>
-----> Installing OpenJDK 1.8... done
 Build complete, shipping your container...
 Waiting for your application to boot...
 !   Error deploying the application
!   → Your application has stopped unexpectedly with the following logs:

======== BEGIN APP LOGS ========
2022-07-29 15:04:50.425626192 +0000 UTC [web-1] Setting JAVA_TOOL_OPTIONS defaults based on dyno size. Custom settings will override them.
2022-07-29 15:04:50.703613309 +0000 UTC [web-1] JAVA_OPTS already set in environment; overriding default settings with values: -Xmx300m -Xss512k -XX:CICompilerCount=2 -Dfile.encoding=UTF-8
2022-07-29 15:04:50.707620930 +0000 UTC [web-1] Picked up JAVA_TOOL_OPTIONS: -Xmx300m -Xss512k -XX:CICompilerCount=2 -Dfile.encoding=UTF-8
2022-07-29 15:04:50.757674453 +0000 UTC [web-1] Error: A JNI error has occurred, please check your installation and try again
2022-07-29 15:04:50.757986378 +0000 UTC [web-1] Exception in thread "main" java.lang.UnsupportedClassVersionError: io/quarkus/bootstrap/runner/QuarkusEntryPoint has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0
2022-07-29 15:04:50.757990030 +0000 UTC [web-1]     at java.lang.ClassLoader.defineClass1(Native Method)
2022-07-29 15:04:50.758047467 +0000 UTC [web-1]     at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
2022-07-29 15:04:50.758170298 +0000 UTC [web-1]     at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
2022-07-29 15:04:50.758173712 +0000 UTC [web-1]     at java.net.URLClassLoader.defineClass(URLClassLoader.java:473)
2022-07-29 15:04:50.758174559 +0000 UTC [web-1]     at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
2022-07-29 15:04:50.758296556 +0000 UTC [web-1]     at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
2022-07-29 15:04:50.758300075 +0000 UTC [web-1]     at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
2022-07-29 15:04:50.758300786 +0000 UTC [web-1]     at java.security.AccessController.doPrivileged(Native Method)
2022-07-29 15:04:50.758301241 +0000 UTC [web-1]     at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
2022-07-29 15:04:50.758431236 +0000 UTC [web-1]     at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
2022-07-29 15:04:50.758433815 +0000 UTC [web-1]     at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
2022-07-29 15:04:50.758457787 +0000 UTC [web-1]     at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
2022-07-29 15:04:50.758460279 +0000 UTC [web-1]     at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:601)
======== END APP LOGS ========

Il y a deux éléments principaux qui vont nous aider ici :

  • Premièrement, le message d'exception Java semble nous avertir d'une version obsolète du Runtime Java.
  • Deuxièmement, le journal indique qu'OpenJDK 1.8 a été déployé.

Or, nous avons vu précédemment que Keycloak nécessite le JRE Java 8 ou Java 11 !

Déployons en utilisant une version plus récente d'OpenJDK. Pour ce faire, créez un fichier nommé system.properties à la racine de votre répertoire keycloak-19.0.1 et mettez-y le contenu suivant :

java.runtime.version=17

Validez les changements et lancez un nouveau déploiement :

% git add system.properties
% git commit -m "Add system.properties"
% git push scalingo master

Cette fois, le déploiement est réussi, félicitations !

Your deployment has been queued and is going to start…
<-- Start deployment of my-app -->
Fetching source code
Fetching deployment cache
-----> Cloning custom buildpack: <https://github.com/Scalingo/buildpack-jvm-common#master>
-----> Installing OpenJDK 17... done
 Build complete, shipping your container...
 Waiting for your application to boot...
<-- <https://my-app.osc-fr1.scalingo.io> -->

Traitement de la politique de sécurité du contenu

Malheureusement, bien que nous soyons maintenant en mesure de voir l'écran de bienvenue de Keycloak, nous sommes également confrontés à un nouveau problème : le chargement de la console d'administration est bloqué.

Ceci est dû au fait que notre instance Keycloak fonctionne derrière un reverse proxy, et, par conséquent, certaines requêtes sont bloquées par une fonction de sécurité de votre navigateur web appelée Content Security Policy.

Heureusement, Keycloak fournit quelques directives de configuration pour contourner ce problème. Nous allons donc régler ce problème, encore une fois, en définissant quelques variables d'environnement :

% scalingo --app my-app env-set KC_PROXY=edge
% scalingo --app my-app env-set KC_HTTP_PORT=\\$PORT
% scalingo --app my-app env-set KC_HTTPS_PORT=443

Et déclencher un nouveau déploiement :

% git commit --allow-empty -m "Add reverse proxy env vars"
% git push scalingo master

Cette fois, nous sommes prêts ! Bien joué !

Aller plus loin

Changer le mot de passe du compte admin

La toute première chose à faire après ce premier déploiement est de changer le mot de passe du compte admin pour quelque chose de fort et sécurisé. Une fois fait, les variables d'environnement correspondantes sont inutiles et peuvent être supprimées :

% scalingo --app my-app env-unset KEYCLOAK_ADMIN
% scalingo --app my-app env-unset KEYCLOAK_ADMIN_PASSWORD
% scalingo --app my-app restart

Externaliser les logs

Keycloak étant un logiciel IAM, l'externalisation des logs qu'il produit semble être une idée raisonnable, si vous souhaitez détecter des comportements étranges, analyser des requêtes à des fins de débogage ou les conserver (les logs) pendant un certain temps pour des raisons légales.

Un excellent moyen d'atteindre ces objectifs est de déployer une pile ELK pour collecter ces journaux. Là encore, nous sommes là pour vous !

Une fois que votre pile ELK est prête, n'oubliez pas d'ajouter un log-drain à votre instance Keycloak.

Et plus encore

  • Configuration de votre/vos realm(s) : ceci est hors de portée de ce blog, mais Keycloak a une bonne documentation pour vous aider.
  • Passage en production : cela impliquera probablement quelques étapes comme le passage à un plan d'affaires pour votre base de données, la mise à jour de votre Procfile et peut-être la mise à jour de la configuration de Keycloak.
Partager l'article
François Kubler
François Kubler
François est Solution Engineer chez Scalingo. Il aime automatiser et garder les choses simples. Ses diverses expériences dans le domaine de l'informatique l'ont amené à croire fermement en l'open-source et plus important encore, à la force d'un cloud européen.

Essayez gratuitement Scalingo

30 jours d'essai gratuit / Pas de CB nécessaire / Hébergé en France