Déploiement de Keycloak sur EC2

Déploiement de Keycloak sur EC2

Vous appréciez notre travail......nous recrutons !

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.

  1. Connectez-vous à votre compte AWS.

  2. Rendez-vous dans la région qui vous convient le mieux, normalement la plus proche de vous.

  3. Dans la barre des tâches supérieure, tapez EC2 et accédez à ce service.

  4. Cliquez sur Launch Instance.

  5. Choisissez à nouveau Launch Instance.

    EC2 Dashboard

    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.

  6. Donnez un nom à l’instance.

  7. Depuis Application and OS Images (Amazon Machine Image), choisissez l’offre gratuite Amazon Linux 2 Kernel 5.10 AMI 2.0.20221103.3 x86_64 HVM gp2 AMI.

    EC2 launch instance

  8. Choisissez l’offre gratuite t2.micro depuis la section “Instance type”.

  9. 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.

  10. 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 sur Edit, puis sur Add security group rule et ajoutez les détails mentionnés précédemment.

EC2 network settings

EC2 add security group

EC2 configure port

  1. Laissez le stockage tel quel à 8 Go.
  2. 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 sous User 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

EC2 add user data

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.

  1. Comme indiqué dans l’image, cliquez sur l’instance.

  2. Cliquez ensuite sur Actions.

  3. Et enfin, cliquez sur Create Template from Instance.

    Create launch template

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

  1. 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.

  2. 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
  3. Obtenez votre VPC Id.

    aws ec2 describe-vpcs | grep VpcId
  4. 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>
  5. 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
  1. 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 commande run-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>
  2. 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.

  1. 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.

  2. 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
  3. 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"
  4. 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.

  1. 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.

  2. 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"
    }
  3. 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>"
    }
  4. Enfin, créez un fichier variables.tf, collez le code suivant et remplacez les noms des variables

    variable "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>"
    }
  5. Une fois les 3 fichiers créés, initialisez l’environnement.

    terraform init
  6. Vérifions qu’aucune erreur n’a été écrite dans les fichiers.

    terraform plan
  7. 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

  1. 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.

  1. Si nécessaire, assurez-vous que la clé SSH n’est pas visible publiquement.

    chmod 400 <key-name>
  2. 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.

  1. Pour éviter la commande sudo pour Docker, tapez le code ci-dessous, quittez votre instance et reconnectez-vous.

    sudo usermod -aG docker $USER
  2. 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
  3. 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
  4. Si nous tapons docker ps, nous voyons que le conteneur s’exécute sur le port 8080.

Docker running container

  1. Ouvrez le navigateur Web avec [http://ec2-public-ip:8080] pour accéder à la page ci-dessous.

Keycloak entry page

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.

Keycloak HTTPS required

Et ajouter [https://] devant l’adresse IP publique ne donne qu’une erreur comme suit.

Keycloak secure connection failed

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.

  1. Pour désactiver SSL/TLS entrons dans le conteneur en mode interactif.

    docker exec -it keycloak-dev bash 
  2. Dans le conteneur, définissez le chemin pour utiliser le script kcadm.sh.

    export PATH=$PATH:/opt/keycloak/bin
  3. 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>
  4. 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 sur external au bas de l’image. Cela indique que SSL/TLS est requis en dehors de notre VPC.

    kcadm.sh get realms/master

Realm details

  1. Désactivez l’exigence SSL/TLS pour le domaine maître.

    kcadm.sh update realms/master -s enabled=true -s sslRequired=none
  2. Maintenant, sur le navigateur, cliquez à nouveau sur “Administration Console” et cette fois la page de connexion apparaît.

Keycloak login page

  1. Renseignez les informations d’identification et obtenez la page suivante.

Keycloak master realm UI

  1. Si nous allons dans le domaine maître dans Realm settings, l’onglet Require SSL est maintenant défini sur None.

Keycloak realm settings

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à.

  1. Vérifiez que Postgres est opérationnel.

    sudo systemctl status postgresql

Postgres status check

  1. Postgres a déjà créé un utilisateur appelé postgres. Définissons le mot de passe de la base de données, puis tapons exit pour quitter.

    # Change to postgres user 
    sudo su - postgres
    # Set DB password
    psql -c "ALTER USER postgres WITH PASSWORD '<your password>';"
  2. Ouvrez le fichier /var/lib/pgsql/data/pg_hba.conf avec nano ou vim en tant qu’utilisateur root. Dans la section # IPv4 local connections: commentez host all all 127.0.0.1/32 ident et ajoutez host 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.

    Postgress configuration file

  3. Redémarrez Postgres.

    sudo systemctl restart postgresql
  4. Créez un dossier pour les certificats SSL.

    mkdir certificates
    cd certificates
  5. 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
  6. 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
  7. 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.

  8. Après environ 30 secondes, ouvrez le navigateur Web avec [https://ec2-public-ip:8443] pour accéder à la page ci-dessous dans Firefox.

    Browser security warning for HTTPS

  9. 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.

Accept self-signed certificate

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.

  1. Par conséquent, entrez le conteneur comme dans la section précédente.

    docker exec -it keycloak-prod bash 
  2. Définissez le chemin des fichiers exécutables.

    export PATH=$PATH:/opt/keycloak/bin
  3. 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
  4. 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.

Partagez cet article

Canada - Maroc - France

Nous sommes une équipe passionnée par l'Open Source, le Big Data et les technologies associées telles que le Cloud, le Data Engineering, la Data Science le DevOps…

Nous fournissons à nos clients un savoir faire reconnu sur la manière d'utiliser les technologies pour convertir leurs cas d'usage en projets exploités en production, sur la façon de réduire les coûts et d'accélérer les livraisons de nouvelles fonctionnalités.

Si vous appréciez la qualité de nos publications, nous vous invitons à nous contacter en vue de coopérer ensemble.

Support Ukrain