Introduction
Cela fait maintenant depuis 2018 que je m’occupe de la plateforme hypothécaire en ligne de CA next bank, un projet qui reste, encore aujourd’hui, l’un des plus passionnants sur lesquels j’ai eu la chance de travailler.
À l’origine, la plateforme avait été développée sous Symfony 3.4 LTS, une version dont la fin de vie était atteinte fin 2021. Autant dire qu’il était grand temps de passer à la dernière version LTS. Or, en 2023 la banque a décidé de ne pas faire les choses à moitié : en plus de la migration vers la nouvelle version de Symfony, elle a opté pour un changement d’hébergeur et quelques ajustements bienvenus sur la plateforme. Autant dire que cette migration, déjà suffisamment technique, s’est révélée bien plus complexe (et pleine de surprises) que prévu ! C’est d’ailleurs ce défi qui m’a donné envie de rédiger un article à ce sujet.
Pour des raisons évidentes de confidentialité, je m’abstiendrai de dévoiler les noms des deux hébergeurs – que nous appellerons simplement “ancien hébergeur” et “nouvel hébergeur” – ainsi que toute information un peu trop sensible à partager.
Démarrage
La banque ayant déjà migré le reste de son infrastructure vers le nouvel hébergeur, il était tout à fait logique qu’elle veuille faire de même avec la plateforme hypothécaire.
De notre côté, nous avions aussi quelques griefs avec l’ancien hébergeur. Toutes les dépendances (PHP, MariaDB, Apache, etc.) avaient été installées une seule fois, au début du projet, par l’hébergeur lui-même… et jamais mises à jour depuis. Autant dire que cela représentait un cocktail explosif de failles de sécurité, de bugs non corrigés, et de problèmes de performance.
Heureusement, en interne, nous avions pris les devants et migré le projet sur Docker. Cela nous permettait non seulement de mettre à jour les versions des dépendances en toute simplicité, mais aussi de déployer la plateforme en quelques clics sur le poste de n’importe quel développeur rejoignant l’équipe, et sur notre serveur interne. L’idée de déployer la plateforme chez le nouvel hébergeur sous forme de projet Docker nous semblait donc évidente : un processus de déploiement simplifié, des coûts de maintenance réduits pour la banque, et une homogénéité avec nos autres projets.
Après une série de réunions avec la banque et le nouvel hébergeur, nous avons obtenu le feu vert pour un déploiement en Docker Compose. Tout semblait donc sur les rails 😁.
Parfait ! Entre ce changement d’hébergeur, la migration vers Symfony, et l’ajout des nouvelles fonctionnalités, il ne nous restait plus qu’à peaufiner notre roadmap.
La priorité numéro un était bien sûr de changer d’hébergeur tout en migrant les données des dossiers existants. Imaginez : les utilisateurs mettent déjà plusieurs jours à remplir leur dossier pour une hypothèque… Alors si l’on perdait tout pendant la migration, ce serait la catastrophe, autant pour les clients que pour la banque. Mais c’est là que les choses se compliquent : avec le niveau de sécurité bancaire implémenté sur la plateforme, impossible d’exporter les données existantes ! En effet, la plateforme a été conçue de manière à ce que même un administrateur système malveillant, avec un accès aux disques et à la base de données, ne puisse rien extraire ni revendre.
La deuxième priorité ? Migrer tout le code vers la dernière version LTS de Symfony. Ça signifie qu’il fallait revoir près de 100'000 lignes de code, passer à une nouvelle version de PHP, migrer Symfony, retravailler le back-office, et remplacer le front-end. Bref, que du fun à venir.
Enfin, en troisième position, venait l’ajout de nouvelles fonctionnalités à la plateforme, qui devront attendre la fin des 2 précédentes étapes.
Sécurité des données
Comme mentionné précédemment, il est tout simplement impossible d’extraire quoi que ce soit de la plateforme. Les données sont encryptées avant même d’être insérées dans la base de données, y compris les images et PDF téléchargés par les utilisateurs. Tout est chiffré de bout en bout, et le seul moyen d’accéder à ces informations en clair est via l’interface de la plateforme hypothécaire en ligne, avec les rôles et permissions appropriés, bien sûr.
Le système d’encryption est à la fois simple et redoutablement efficace. Il repose sur plusieurs éléments :
- Les données à chiffrer (logique, non ?)
- Un salt, qui change à chaque enregistrement
- Un pepper, qui reste constant et se trouve dans les fichiers de configuration de la plateforme
- Une clé calculée en fonction de la machine hébergeant la plateforme
Ce cocktail assure que même en ayant accès aux disques ou à la base de données, les informations restent inaccessibles sans passer par la plateforme elle-même.
La donnée
Ce système de chiffrement est appliqué à toutes les données, qu’il s’agisse du prénom du client, du nombre d’enfants qu’il a, ou même du scan PDF de son certificat de salaire. Bref, tout ce qui entre est automatiquement chiffré pour garantir une sécurité maximale.
Le salt
Le salt utilisé est unique à chaque table et à chaque ligne, et il change à chaque insertion ou mise à jour. Cela signifie que même si trois clients portent exactement le même nom, la valeur chiffrée insérée dans la base de données sera toujours différente.
Le pepper
À l’inverse du salt, le pepper est un ingrédient constant. Il reste identique pour tous les champs et tous les dossiers. Son rôle est de renforcer l’efficacité du salt en ajoutant une deuxième clé, qui n’est pas stockée dans la base de données. Cela complique considérablement les tentatives de bruteforce, en rendant la tâche encore plus ardue pour les pirates.
La clé machine
C’est là que les choses deviennent intéressantes. La clé machine est un élément subtil, mais essentiel. Elle garantit que, même si un administrateur système décidait de copier l’intégralité de la base de données, des fichiers uploadés, ainsi que tout le code de la plateforme (oui, on imagine un copier-coller XXL), il ne pourrait toujours pas accéder aux données chiffrées. Pourquoi ? Parce que la clé est calculée en fonction de la machine sur laquelle la plateforme tourne, rendant cette copie… parfaitement inutilisable ailleurs.
Migration des données
Étant donné qu’extraire les données en l’état est tout bonnement impossible, nous avons dû mettre en place un déploiement supplémentaire sur l’ancienne plateforme avant son retrait. Ce déploiement a introduit une nouvelle commande CLI, qui a pour mission de récupérer toutes les données nécessaires à la migration, de les sérialiser dans un fichier plat, et d’y appliquer une légère encryption avec une clé fixe. Nous avons également intégré la commande inverse dans le code de la nouvelle plateforme.
Ainsi, un administrateur système de la banque peut extraire les données et les transférer sur le nouveau serveur, où elles pourront ensuite être importées sans encombre.
Migration du code
Bien que le framework Symfony soit un champion dans l’art de simplifier la vie des développeurs, y compris pour les migrations, cette phase s’est tout de même révélée être un sacré défi. En effet, passer de Symfony 3 à Symfony 6 a impliqué une quantité astronomique de modifications – je parle ici de changements très, très nombreux ! Que ce soit au niveau de la structure des dossiers, des APIs internes, ou des méthodes pour réaliser certaines tâches, la transition a été tout sauf simple. Un exemple parmi d’autres : le système d’authentification, qui a maintenant adopté le concept de passeport. Cela a impliqué une révision complète de toute la couche d’authentification de la plateforme. Autant dire que cela a été un véritable casse-tête, mais aussi une excellente opportunité pour moderniser notre approche !
Symfony recommande vivement une approche progressive pour les migrations. L’idée est de passer de la version a.4 à la version b.0, puis de b.0 à b.4, et ainsi de suite, jusqu’à atteindre la version souhaitée :
- 3.4 LTS
- 4.0
- 4.4 LTS
- 5.0
- 5.4 LTS
- 6.0
- 6.4 LTS
Après avoir analysé les changements nécessaires et constaté que la séparation entre la partie applicative et la logique métier était déjà bien en place, nous avons opté pour une réinstallation complète d’un projet Symfony 6.4 LTS neuf, plutôt que de suivre la procédure officielle.
C’est risqué, c’est audacieux dirais-je même, mais cela a parfaitement fonctionné ! Cette approche nous a permis d’obtenir un site sur la dernière version de Symfony, avec une structure et des fonctionnalités modernes, plutôt qu’une solution hybride conservant l’ancienne architecture (pour ceux qui se souviennent des bundles et du fichier parameters.yml 😅).
La phase la plus chronophage a été la migration des annotations en attributs à travers les 100'000 fichiers PHP. Malheureusement, Rector n’a pas été d’une grande aide, en raison des anciens commentaires parfois erronés, du passage aux variables typées qui a modifié les signatures de toutes les fonctions. Sans oublier notre système maison de chiffrement/déchiffrement qui a compliqué les choses pour Doctrine.
Heureusement, nous avions plus de 2 000 tests unitaires, fonctionnels et de non-régression, ce qui nous a permis de vérifier que tous les éléments clés fonctionnaient sans générer d’erreurs ou d’avertissements.
Finalement, la migration du code s’est déroulée à merveille, et nous avons même eu l’occasion d’ajouter quelques tests supplémentaires en cours de route.
Déploiement
L’ancien environnement, toujours en production, est prêt pour l’exportation de ses données. De notre côté, le code a été testé et est prêt pour le déploiement. Il ne reste plus qu’à installer tout cela sur le nouveau serveur de production, effectuer quelques tests pour vérifier que tout fonctionne correctement, puis simplement modifier le DNS pour rediriger le nom de domaine vers le nouveau serveur, tout en activant une page de maintenance sur l’ancien serveur. En théorie, rien de plus simple !
Ou presque…
Docker oui, mais pas vraiment
Vous vous souvenez quand nous avons reçu le feu vert du nouvel hébergeur pour utiliser Docker Compose sur leur serveur ? Eh bien, il s’avère que notre contact n’avait pas vraiment les compétences techniques nécessaires ! Après plus d’un mois de discussions, nous avons enfin pu parler à quelqu’un de technique côté hébergeur, qui nous a expliqué que, en raison de :
- Un partenariat entre l’hébergeur et le fournisseur de l’OS du serveur, qui pousse ses propres outils alternatifs.
- Une surcouche de sécurité personnalisée de l’hébergeur qui réinitialise les ports ouverts et arrête les services à intervalles réguliers.
Il était impossible d’utiliser Docker Compose sur leur serveur. En revanche, nous pouvions utiliser Podman à la place.
Je n’avais jamais entendu parler de Podman, mais face à l’urgence, il ne nous restait plus qu’à nous adapter.
Podman
Podman, bien qu’étant une alternative à Docker, offrait un support de Docker Compose si limité qu’il couvrait à peine 10 % de nos besoins.
Nous avons donc dû écrire un script bash d’une longueur impressionnante pour exécuter chaque commande Podman de bas niveau, afin de reproduire ce que fait un simple “docker compose up -d” dans notre environnement local. Cela comprenait :
- Télécharger toutes les images
- Créer les différents réseaux
- Initialiser les volumes nommés
- Monter les volumes bind
- Attacher les conteneurs aux réseaux
- Mapper les ports entre les conteneurs
- Demander au pare-feu d’ouvrir des ports
- Rediriger le trafic du pare-feu vers les conteneurs
- Limiter les consommations CPU et RAM
- Limiter la taille des logs
- Et bien plus encore…
Cette étape a été un véritable calvaire. À côté, la migration du code et des données semblait être une promenade de santé dans un parc au bord du lac.
Avec une dose suffisante d’acharnement, nous avons réussi à mettre au point un script magique. Ce script se charge tout seul de mettre le site en maintenance, de mettre à jour les images, de mettre à jour la base de données, puis de remettre le site en ligne. En gros, il reproduit exactement ce que nous avions en local et sur nos serveurs internes, et ce que nous avions prévu de déployer sur les serveurs du nouvel hébergeur.
Le grand jour
Les tests de stabilité et de migration des données ont été validés avec succès en local, sur le serveur de préproduction, et enfin sur le serveur de production (avec temporairement les données de préproduction). Nous sommes prêts à passer à l’action !
La banque procède donc à un export complet de toutes les données depuis la production de l’ancien hébergeur et active la page de maintenance. Les clients n’ont plus accès à la plateforme, le chrono est lancé, et il faut aller vite !
L’export est transféré sur le nouveau serveur et c’est à nous de jouer ! Nous lançons la commande d’import des données… Des comptes employés, une multitude de dossiers, des milliers de documents – si un seul élément échoue à être importé, décrypté, et correctement encrypté avant d’être stocké, tout devra être annulé !
Hourra ! Tout a été importé avec succès !
Maintenant, testons les parcours utilisateur ! Heureusement, nos tests de bout en bout peuvent être exécutés sur des environnements autres que notre configuration locale. Je mets à jour le nom de domaine de nos tests et lance la procédure depuis ma machine. En parallèle, je vérifie le back-office pour les employés.
Les tests se déroulent parfaitement jusqu’au bout. J’ai vérifié manuellement le back-office, et mon dossier créé lors du test est bien présent ! Tout est en ordre. Je supprime le dossier de test et informe le client que la migration est terminée. Il ne leur reste plus qu’à basculer leur DNS vers le nouveau serveur !
Conclusion
Finalement, malgré une installation sur les serveurs du nouvel hébergeur qui a pris plus de temps que prévu (merci Podman…), tout s’est très bien déroulé. La plateforme est maintenant sur la dernière version LTS de Symfony, nous avons migré vers les dernières versions de PHP et MariaDB, remplacé Apache par Nginx, et nous avons désormais la flexibilité nécessaire pour mettre à jour ces dépendances à tout moment.
Le client a pu transférer sa plateforme hypothécaire vers le nouvel hébergeur, et nous sommes maintenant en train d’implémenter les nouvelles fonctionnalités demandées par leur équipe métier.
Le projet a été non seulement intéressant, mais aussi très amusant. Et même si Podman et moi ne sommes pas exactement les meilleurs amis (loin de là), c’est toujours enrichissant d’apprendre de nouvelles méthodes et technologies. Cela m’a aussi permis de plonger en profondeur dans les rouages de Docker et de Podman.
Client satisfait, équipe SQLI ravie, et moi, je repars avec un lot de nouvelles connaissances et un bon souvenir de ce projet. Que demander de plus ?