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.
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.
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 :
Ces quelques points nous amènent aux hypothèses suivantes :
buildpack-jvm-common
à un moment donné.Très bien, il est maintenant temps de se plonger dans le code !
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 !
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 postgresql-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
.
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}"
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 :
create-env.sh
.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"
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
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
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 :
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> -->
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é !
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
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.
Procfile
et peut-être la mise à jour de la configuration de Keycloak.Chez Scalingo (avec nos partenaires), nous utilisons des traceurs sur notre site.
Certains, essentiels et fonctionnels, sont nécessaires au bon fonctionnement du site et ne peuvent pas être refusés.
D'autres sont utilisés pour mesurer notre audience, entretenir notre relation avec vous et vous adresser de temps à autre du contenu qualitatif ainsi que de la publicité.