Déploiement de Keycloak sur EC2
By BAUM Stephan
14 mars 2023
- Catégories
- Cloud computing
- Data Engineering
- Infrastructure
- Tags
- EC2
- sécurité
- Authentification
- AWS
- Docker
- Keycloak
- SSL/TLS
- SSO [plus][moins]
Ne ratez pas nos articles sur l'open source, le big data et les systèmes distribués, fréquence faible d’un email tous les deux mois.
Pourquoi utiliser Keycloak
Keycloak est un fournisseur d’identité open source (IdP) utilisant l’authentification unique SSO. Un IdP est un outil permettant de créer, de maintenir et de gérer les informations d’identité des utilisateurs (“principals” en anglais) et de fournir des services d’authentification pour les applications dans un réseau distribué. Keycloak vous permet de créer plusieurs politique de sécurité appelés domaines (“realm” en anglais) pour gérer des objets tels que des utilisateurs, des applications, des rôles et des groupes. Il vous permet également d’enregistrer plusieurs utilisateurs pour la même application. Keycloak est soit configuré via une interface utilisateur appelée Admin Console ou avec des commandes CLI.
Une liste non exhaustive de cas d’utilisation inclue :
- Intégration dans un cluster Kubernetes pour l’authentification
- Configurer Keycloak pour permettre la connexion avec les réseaux sociaux
- Configurer Keycloak en tant que courtier d’identité (“identity broker” en anglais) pour un autre fournisseur d’identité
Cet article explique comment configurer Keycloak dans une instance AWS EC2 et comment rendre le fournisseur d’identité accessible publiquement sur Internet.
1 Configurer l’instance EC2
L’objectif principal de cet article est de savoir comment configurer Keycloak dans une instance AWS EC2 et non comment lancer une instance EC2 sur AWS. Cependant, trois méthodes différentes de configuration et de lancement de l’instance EC2 sont décrites dans cet article afin de s’adapter au confort des lecteurs et de montrer spécifiquement quelles ressources sont nécessaires. Si vous souhaitez uniquement configurer les ressources le plus rapidement possible et obtenir les scripts pour une reproduction idempotente, nous vous recommandons de sauter les parties 1.1 et 1.2 et de passer directement à la partie 1.3.
1.1 Utilisation de l’interface Web
1.1.1 Création de l’instance EC2
Le lancement de l’instance EC2 via l’interface Web est la solution la plus conviviale.
Vous pouvez également suivre la documentation officielle sur la façon de créer une instance AWS EC2. Cependant, les points suivants fournissent les étapes de configuration de l’instance.
-
Connectez-vous à votre compte AWS.
-
Rendez-vous dans la région qui vous convient le mieux, normalement la plus proche de vous.
-
Dans la barre des tâches supérieure, tapez EC2 et accédez à ce service.
-
Cliquez sur
Launch Instance
. -
Choisissez à nouveau
Launch Instance
.Keycloak dans un conteneur Docker ne nécessite pas beaucoup de ressources. Par conséquent, nous choisissons une micro-instance T2 avec l’espace disque minimum. L’installation de Docker sur une Amazon Linux AMI est très simple et nous l’utilisons donc.
-
Donnez un nom à l’instance.
-
Depuis
Application and OS Images (Amazon Machine Image)
, choisissez l’offre gratuiteAmazon Linux 2 Kernel 5.10 AMI 2.0.20221103.3 x86_64 HVM gp2
AMI. -
Choisissez l’offre gratuite
t2.micro
depuis la section “Instance type”. -
Si vous avez déjà une paire de clés choisissez la dans l’interface sinon créez en une et cliquez sur le type
RSA
. -
Dans les paramètres réseau, le port SSH 22 qui est là par défaut nous permet de nous connecter à l’instance depuis une autre machine. Cependant, Keycloak hébergé sur notre instance EC2 a besoin d’un accès à l’internet public, nous ouvrons donc soit le port 8080 et/ou le port 8443 avec le protocole TCP. Définissez la source sur
Anywhere
; cela permet à tous les utilisateurs extérieurs au réseau privé virtuel (VPC) d’accéder à l’instance EC2. Cliquez surEdit
, puis surAdd security group rule
et ajoutez les détails mentionnés précédemment.
- Laissez le stockage tel quel à 8 Go.
- Dans
Advanced details
, il est possible de demander une instance ponctuelle pour réduire les coûts, mais gardez à l’esprit qu’AWS peut résilier l’instance à tout moment. Dans cette même section sousUser data
, ajoutez le code suivant pour installer Docker et Postgres au lancement. La raison pour laquelle nous installons Postgres sera expliquée plus tard.
#!/bin/bash
sudo yum update -y
sudo amazon-linux-extras install docker
sudo service docker start
sudo amazon-linux-extras enable postgresql13
sudo yum install postgresql postgresql-server -y
sudo postgresql-setup initdb
sudo systemctl start postgresql
sudo systemctl enable postgresql
Si vous oubliez de coller ce code dans User data
avant de lancer l’instance, vous pourrez toujours exécuter chaque ligne de code individuellement dans l’instance EC2 créée par la suite.
1.1.2 Création et utilisation d’un modèle de lancement
Créez un modèle de lancement (“launch template” en anglais) à partir de l’instance précédemment créée pour reproduire aisément la configuration.
-
Comme indiqué dans l’image, cliquez sur l’instance.
-
Cliquez ensuite sur
Actions
. -
Et enfin, cliquez sur
Create Template from Instance
.
Le modèle de lancement a été créé et la prochaine fois, lancez l’instance à partir de ce modèle en cliquant sur Launch instance from template
dans la page du tableau de bord EC2, comme indiqué sur la deuxième image de l’article.
1.2 Utilisation des commandes de l’AWS CLI
Si AWS CLI est installé sur votre PC et que vous maîtrisez les commandes CLI, vous pouvez les utiliser pour configurer l’instance.
1.2.1 Première configureration
-
Connectez-vous à votre compte AWS avec la commande suivante, puis indiquez vos informations d’identification comme expliqué dans la documentation officielle
aws configure
Donnez votre clé d’accès et votre clé d’accès privée, puis définissez votre région par défaut et choisissez
json
comme format de sortie par défaut. -
Créez une clé pour l’instance EC2 dans votre région par défaut si vous n’en avez pas encore.
aws ec2 create-key-pair \ --key-name <your_key_name> \ --query 'KeyMaterial' \ --output text > your_key_name.pem
-
Obtenez votre VPC Id.
aws ec2 describe-vpcs | grep VpcId
-
Créer un groupe de securité.
aws ec2 create-security-group \ --group-name <security-group-name> \ --description "test the cli security group" \ --vpc-id <your-vpc-id>
-
Ouvrez les ports 22 et effectuez la même commande pour le port 8080 et/ou le port 8443 en remplaçant simplement le numéro de port.
aws ec2 authorize-security-group-ingress \ --group-id <sg-id> \ --protocol tcp --port 22 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress \ --group-id <sg-id> \ --protocol tcp --port 8080 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress \ --group-id <sg-id> \ --protocol tcp --port 8443 --cidr 0.0.0.0/0
-
Si vous avez déjà un groupe de sécurité avec ces règles d’entrée, recherchez-le comme suit :
aws ec2 describe-security-groups
-
Lancez une instance EC2 de type T2 micro avec une Amazon Linux AMI et avec le script bash d’installation Docker. Collez le code d’installation de Docker dans un script bash et nommez-le de la même manière que dans
user-data
de la commanderun-instance
.aws ec2 run-instances --image-id ami-01cae1550c0adea9c \ --count 1 --instance-type t2.micro \ --key-name <your-keyname> \ --security-group-ids <your-sg-id> \ --user-data file://<docker-install-file-name>
-
La commande suivante crée une balise pour l’instance même si elle n’est pas obligatoire :
aws ec2 create-tags --resources <InstanceID> --tags Key=Name,Value=Keycloak
Pour résilier l’instance, utilisez la commande suivante :
aws ec2 terminate-instances --instance-ids <instance-id>
1.2.2 Utilisation d’un modèle de lancement pour la reproductibilité
Mettons dans un fichier modèle tous ces paramètres de l’instance existante qui a été créée pour reproduire la même configuration à chaque fois que nous lançons l’instance.
-
Obtenez d’abord l’ID d’instance avec la commande suivante :
aws ec2 describe-instances | grep "InstanceId"
Notez que si vous avez plusieurs instances en cours d’exécution en même temps, vous aurez plusieurs identifiants. Vous devez donc exclure le
| grep "InstanceId"
de la commande et, dans la description longue, regardez quelle instance est concernée. -
Extrayez maintenant toutes les informations dans un fichier json en remplaçant le
instance-id
.aws ec2 get-launch-template-data \ --instance-id <your-instance-id> \ --query "LaunchTemplateData" >> instance-data.json
-
Avec le fichier obtenu, créez un modèle de lancement.
aws ec2 create-launch-template \ --launch-template-name TemplateForWebServer \ --version-description Version1 \ --tag-specifications 'ResourceType=launch- template,Tags=[{Key=purpose,Value=Keycloak}]' \ --launch-template-data file://instance-data.json
Le texte au format json apparaîtra sur la console avec l’ID du modèle de lancement.
Si le modèle de lancement a déjà été créé, récupérez son Id avec la commande suivante
aws ec2 describe-launch-template-versions \ --versions "$Latest,$Default"
-
Une fois que nous avons le modèle de lancement et son identifiant, lancez l’instance EC2 comme suit :
aws ec2 run-instances \ --launch-template LaunchTemplateId=<launch-template-id>
1.3 Création d’une instance EC2 avec Terraform
Une autre façon de créer toutes les ressources à partir de zéro consiste à utiliser Terraform. Terraform détruit toutes les ressources créées avec une simple commande. Dans ce cas, il supprime non seulement l’instance EC2, mais également le groupe de sécurité. Le plus des scripts Terraform ci-dessous est qu’ils s’appliquent à tous les utilisateurs AWS et ne sont donc pas personnalisés pour un utilisateur spécifique.
Gardez à l’esprit que le seul élément que les scripts ci-dessous ne créent pas est une nouvelle clé AWS SSH pour l’instance. Si vous n’en avez pas encore, veuillez vous référer à la commande AWS CLI précédente ou allez dans l’interface web pour en créer une et assurez-vous qu’elle est créée dans la même région où vous souhaitez lancer l’instance EC2.
-
Vérifiez si Terraform est installé, sinon, trouvez les instructions sur le site web de hashicorp et vérifiez que la version est supérieure à 1.2.8 avec la commande
terraform version
sur la ligne de commande. -
Créez un fichier
main.tf
et collez le code suivant :# terraform for ec2 type t2 micro, ami amazon-linux, Docker installed terraform { required_version = ">= 1.2.8" } # Get the default VPC resource "aws_default_vpc" "default" { tags = { Name = "Default VPC" } } # Create a security group that allows inbound traffic on port 8080 and 8443 resource "aws_security_group" "sg" { name = var.security_group_name description = "Allow inbound traffic on port 8080 and 8443" vpc_id = aws_default_vpc.default.id ingress { description = "open ssh port" from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] ipv6_cidr_blocks = ["::/0"] } ingress { description = "open port 8080" from_port = 8080 to_port = 8080 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] ipv6_cidr_blocks = ["::/0"] } ingress { description = "open port 8443" from_port = 8443 to_port = 8443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] ipv6_cidr_blocks = ["::/0"] } # Allows all outbound traffic egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] ipv6_cidr_blocks = ["::/0"] } tags = { Name = var.security_group_name } } # Create a t2 micro instance with amazon-linux resource "aws_instance" "ec2" { ami = "ami-01cae1550c0adea9c" instance_type = "t2.micro" key_name=var.keyname vpc_security_group_ids = [aws_security_group.sg.id] user_data = <<-EOF #!/bin/bash sudo yum update -y sudo amazon-linux-extras install docker sudo service docker start sudo amazon-linux-extras enable postgresql13 sudo yum install postgresql postgresql-server -y sudo postgresql-setup initdb sudo systemctl start postgresql sudo systemctl enable postgresql EOF tags = { Name = var.aws_instance_name } } # Output the public ip output "instance_ip" { value = "${aws_instance.ec2.public_ip}" description = "Public IP address" } output "instance_dns" { value = "${aws_instance.ec2.public_dns}" description = "Public DNS" }
-
Créez un fichier
providers.tf
et collez le code suivant. Tapez la région AWS où les ressources doivent être créées et où se trouve la clé SSH.provider "aws" { region = "<aws-region>" }
-
Enfin, créez un fichier
variables.tf
, collez le code suivant et remplacez les noms des variablesvariable "keyname" { type = string default = "<your-keyname>" } variable "security_group_name" { type = string default = "<your-security-group-name>" } variable "aws_instance_name" { type = string default = "<your-instance-name>" }
-
Une fois les 3 fichiers créés, initialisez l’environnement.
terraform init
-
Vérifions qu’aucune erreur n’a été écrite dans les fichiers.
terraform plan
-
Lancez désormais le deploiement.
terraform apply
Notes :
- Utilisez la commande
terraform refresh
pour récupérer à nouveau les informations des ressources créées. - Appliquez la commande
terraform destroy
pour détruire toutes les ressources créées par terraform pour l’environnement.
2 Connectez-vous à l’instance EC2
-
Nous obtenons soit le nom DNS public, soit l’adresse IP publique de l’instance générée par le script terraform. Vous pouvez également appliquer la commande suivante pour obtenir le DNS public.
aws ec2 describe-instances | grep "PublicDnsName"
Si vous avez plusieurs instances ec2, omettez le | grep "PublicDnsName"
et recherchez les informations correspondant à votre instance EC2 dans le long script json qui s’affiche à l’écran.
-
Si nécessaire, assurez-vous que la clé SSH n’est pas visible publiquement.
chmod 400 <key-name>
-
Connectez-vous à l’instance via SSH, le lancement de l’instance peut prendre quelques minutes.
ssh -i "<key-name>" ec2-user@<Public-DNS-Name or Public-IP>
3 Créer un conteneur Docker avec Keycloak
3.1 Exemple de démonstration en mode développement
Nous créons maintenant un conteneur Docker exécutant Keycloak publiquement à des fins de démonstration.
-
Pour éviter la commande
sudo
pour Docker, tapez le code ci-dessous, quittez votre instance et reconnectez-vous.sudo usermod -aG docker $USER
-
Maintenant, extrayons l’image. Au moment de la rédaction, la dernière version est la 20.0.3.
docker pull quay.io/keycloak/keycloak:latest
-
Exécutez le conteneur en activant le port 8080 à l’intérieur du conteneur et sur l’instance.
# Set a password for admin user export KEYCLOAK_DEV_ADMIN_PASSWORD=<your password> # Run the container docker run -d \ --name keycloak-dev \ -p 8080:8080 \ -e KEYCLOAK_ADMIN=admin \ -e KEYCLOAK_ADMIN_PASSWORD=$KEYCLOAK_DEV_ADMIN_PASSWORD \ quay.io/keycloak/keycloak:latest \ start-dev
-
Si nous tapons
docker ps
, nous voyons que le conteneur s’exécute sur le port 8080.
- Ouvrez le navigateur Web avec [http://ec2-public-ip:8080] pour accéder à la page ci-dessous.
Cependant, si nous cliquons sur Administration Console
, nous ne pouvons pas nous connecter car le flux de données entre votre instance EC2 et l’Internet public est protégé par défaut par le cryptage SSL dans Keycloak.
Et ajouter [https://] devant l’adresse IP publique ne donne qu’une erreur comme suit.
Si nous nous connectons avec une machine à l’intérieur de notre VPC, nous aurons accès à la console. Dans cet exemple, nous désactivons l’exigence SSL/TLS pour avoir accès à Keycloak via l’Internet public.
-
Pour désactiver SSL/TLS entrons dans le conteneur en mode interactif.
docker exec -it keycloak-dev bash
-
Dans le conteneur, définissez le chemin pour utiliser le script
kcadm.sh
.export PATH=$PATH:/opt/keycloak/bin
-
Exécutez ensuite la commande suivante pour définir le serveur et l’utilisateur du domaine maître.
kcadm.sh config credentials --server http://localhost:8080/ \ --realm master \ --user admin --password <your password>
-
En tapant la commande suivante, nous obtenons les détails du domaine au format json et nous voyons que la valeur de
sslRequired
est définie surexternal
au bas de l’image. Cela indique que SSL/TLS est requis en dehors de notre VPC.kcadm.sh get realms/master
-
Désactivez l’exigence SSL/TLS pour le domaine maître.
kcadm.sh update realms/master -s enabled=true -s sslRequired=none
-
Maintenant, sur le navigateur, cliquez à nouveau sur “Administration Console” et cette fois la page de connexion apparaît.
- Renseignez les informations d’identification et obtenez la page suivante.
- Si nous allons dans le domaine maître dans
Realm settings
, l’ongletRequire SSL
est maintenant défini surNone
.
Gardez à l’esprit que la désactivation de l’exigence SSL/TLS n’est pas recommandée en mode production et/ou si vous traitez des données sensibles.
Avant de passer à la section suivante, arrêtez le conteneur avec la commande docker stop keycloak-dev
car le nouveau conteneur nécessitera le même port hôte. Supprimez-le avec docker rm keycloak-dev
car il n’est plus utilisé.
3.2 Déployez Keycloak en mode production avec un certificat SSL/TLS auto-signé
Vous vous demandez peut-être pourquoi nous avons installé Postgres avec les données utilisateur puisque nous ne l’avons pas encore utilisé. Keycloak est livré avec une base de données en mémoire appelée H2. Cependant, il est insuffisant pour les données volumineuses et donc déconseillé pour une utilisation en mode production. C’est la raison pour laquelle nous avons installé une base de données externe pour se connecter à Keycloak. Dans ce cas nous utilisons Postgres, cependant vous avez le choix de connecter d’autres bases de données comme Oracle ou MySQL.
Si vous n’avez pas fait l’exemple de démonstration en mode développement, effectuez les étapes 1 et 2 de cette section et continuez à partir de là.
-
Vérifiez que Postgres est opérationnel.
sudo systemctl status postgresql
-
Postgres a déjà créé un utilisateur appelé
postgres
. Définissons le mot de passe de la base de données, puis taponsexit
pour quitter.# Change to postgres user sudo su - postgres # Set DB password psql -c "ALTER USER postgres WITH PASSWORD '<your password>';"
-
Ouvrez le fichier
/var/lib/pgsql/data/pg_hba.conf
avecnano
ouvim
en tant qu’utilisateurroot
. Dans la section# IPv4 local connections:
commentezhost all all 127.0.0.1/32 ident
et ajoutezhost all postgres 127.0.0.1/32 md5
. Cette action permet uniquement à l’utilisateur postgres sur l’hôte local d’accéder à la base de données avec un mot de passe. Dans notre cas, Postgres n’a pas d’autre objectif que d’être utilisé par Keycloak. Vous pouvez en savoir plus sur les méthodes d’authentification sur le site Web Postgres. -
Redémarrez Postgres.
sudo systemctl restart postgresql
-
Créez un dossier pour les certificats SSL.
mkdir certificates cd certificates
-
Créez le certificat auto-signé et la clé au format pem.
openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
-
Définissez les mots de passe et le nom d’hôte. Le mot de passe de la base de données doit être le même que celui que vous avez défini précédemment dans Postgres.
export KEYCLOAK_ADMIN_PASSWORD=<your keycloak admin password> export DB_PASSWORD=<your db password> export KEYCLOAK_HOSTNAME=<your public ip>:8443
-
Créez le conteneur avec la commande suivante.
docker run -d \ --name keycloak-prod \ -v /home/ec2-user/certificates:/certificates \ --network=host \ -e KEYCLOAK_ADMIN=admin \ -e KEYCLOAK_ADMIN_PASSWORD=$KEYCLOAK_ADMIN_PASSWORD \ quay.io/keycloak/keycloak:latest \ start \ --features=token-exchange \ --https-certificate-file=/certificates/cert.pem \ --https-certificate-key-file=/certificates/key.pem \ --hostname=$KEYCLOAK_HOSTNAME \ --proxy=edge \ --db=postgres \ --db-url=jdbc:postgres://localhost:5432/postgres \ --db-username=postgres \ --db-password=$DB_PASSWORD
Ici, nous montons un volume avec les certificats sur le conteneur. Keycloak les stocke ensuite dans un keystore avec les options
--https-certificate-file
et--https-certificate-key
. Pour en savoir plus sur la configuration de TLS, consultez le site Web de Keycoak.Nous ordonnons au conteneur d’utiliser le même réseau que l’hôte avec
--network=host
. Par conséquent, nous n’avons pas à faire de configuration réseau sur le conteneur. Keycloak utilise par défaut les ports 8080 et 8443 pour respectivement http et https. Postgres est connecté via son port par défaut 5432.Ici, nous définissons l’adresse IP publique comme nom d’hôte car nous voulons que la console d’administration soit visible sur l’Internet public. Avec l’option
--proxy=edge
, notre serveur s’exécute derrière un proxy de terminaison TLS. Lisez la documentation officielle pour plus d’informations sur ce sujet.Les dernières options de la commande sont obligatoires pour connecter la base de données Postgres installée sur l’instance EC2 au conteneur.
-
Après environ 30 secondes, ouvrez le navigateur Web avec [https://ec2-public-ip:8443] pour accéder à la page ci-dessous dans Firefox.
-
Comme nous avons utilisé un certificat auto-signé, nous recevons un message d’avertissement. Dans Firefox, cliquez sur
Advanced
et acceptez le risque, le navigateur vous redirige alors vers la même console vue ci-dessus.
Maintenant que nous avons accès à la console d’administration, nous pouvons l’utiliser pour toute autre opération telle que la création de clients ou d’utilisateurs, ce qui est expliqué dans la [documentation Keycloak](https://www.keycloak.org/docs/latest/server_admin /#_account-service).
Utilisation des commandes CLI
L’utilisation des commandes CLI nécessite d’abord la configuration du truststore.
-
Par conséquent, entrez le conteneur comme dans la section précédente.
docker exec -it keycloak-prod bash
-
Définissez le chemin des fichiers exécutables.
export PATH=$PATH:/opt/keycloak/bin
-
Créez un fichier
truststore.jks
avec votre certificat pem puis choisissez un mot de passe.cd /opt/keycloak keytool -import -alias root -keystore truststore.jks -file /certificates/cert.pem
-
Configurez le truststore pour utiliser le fichier
truststore.jks
.kcadm.sh config truststore --trustpass <trustsore password> ~/truststore.jks
Désormais, l’utilisation d’autres commandes CLI ne diffère pas de l’exemple de démonstration en mode développement. Vous pouvez trouver plus de commandes CLI dans la documentation officielle.
Nous avons enfin configuré Keycloak dans un conteneur Docker sur une instance EC2 et il est prêt pour toute autre opération.
N’oubliez pas de mettre fin à toutes vos ressources créées une fois qu’elles ne sont plus nécessaires.