Détail des réalisations
Migrations VMware vers Proxmox sur des parcs de production
Contexte
Une plateforme de virtualisation coûte deux fois : la licence qu'on renouvelle, et les ressources qu'elle immobilise. J'ai migré des serveurs de production de VMware vers Proxmox sur plusieurs parcs, pour sortir de la première et récupérer les secondes. Ce qui tourne sur ces machines ne se négocie pas : annuaire Active Directory, applicatif métier, serveurs de fichiers. Une migration qui se passe mal à cet endroit, c'est la journée de travail de tout le monde qui s'arrête, et c'est la raison pour laquelle ces chantiers sont si souvent repoussés.
Workflow
- Inventaire d'abord : ce qui tourne réellement, ce qui dépend de quoi, ce qui peut s'arrêter une heure et ce qui ne peut pas. C'est cet inventaire qui décide de l'ordre de bascule, pas le planning
- Sauvegarde vérifiée par une restauration réelle avant d'y toucher. Une sauvegarde qu'on n'a jamais restaurée n'est pas une sauvegarde, c'est une intention
- Bascule par lots, avec le retour arrière préparé à chaque lot. Tant que l'hôte d'origine reste intact, un lot qui se passe mal se rejoue au lieu de se subir
- Validation par l'usage et pas par la console : on ouvre une session, on atteint les partages, on lance l'applicatif. Un hyperviseur qui affiche du vert ne prouve rien
Résultats
- Aucune coupure d'activité constatée sur les migrations menées
- Coût de licence de virtualisation supprimé sur le périmètre migré
- Ressources récupérées : la consolidation rend du CPU et de la mémoire qui étaient immobilisés par l'ancienne plateforme
- Restauration plus rapide qu'avant, parce qu'elle se rejoue à l'échelle de la machine virtuelle et qu'elle est testée
Sentinel SRE : supervision prédictive et analyse par IA (Gemini 2.5)
Contexte
La supervision d'un parc de plus de 50 serveurs Linux génère un volume d'alertes complexes à analyser manuellement au quotidien. L'objectif était de remplacer la supervision classique 'réactive' par un système 'proactif', sans installer d'agents lourds sur les machines, en utilisant l'IA pour interpréter les métriques de base.
Workflow
- Agent léger (Bash) : un script CRON exécuté sur chaque serveur extrait les signes vitaux (Load, RAM, IO, Patchs de sécurité, Uptime) via des commandes natives
- Orchestration n8n : réception des JSON via Webhook, agrégation des données du parc complet
- Cerveau IA : le modèle Gemini 2.5 analyse le tableau de bord global, identifie les goulots d'étranglement (ex: charge CPU) et corrèle avec les mises à jour en attente
Solution technique
#!/bin/bash
# Script de santé : Collecte des métriques SRE pour analyse IA
WEBHOOK_URL="https://xxxxxxxx.xxxx.xx/webhook/system-health-xxxx"
HOSTNAME=$(hostname | tr '[:upper:]' '[:lower:]')
IP_ADDR="10.0.x.x"
REBOOT_REQ=$( [ -f /var/run/reboot-required ] && echo "true" || echo "false" )
RAW_UPGRADE=$(apt-get -s upgrade 2>/dev/null)
PKG_LIST=$(echo "$RAW_UPGRADE" | grep "^Inst" | awk '{print $2}' | tr '\n' ',' | sed 's/,$//' | tr -d '[:cntrl:]"' )
APT_CHECK_TOOL="/usr/lib/update-notifier/apt-check"
if [ -f "$APT_CHECK_TOOL" ]; then
CHECK_DATA=$($APT_CHECK_TOOL 2>&1)
TOTAL_UPDATES=$(echo "$CHECK_DATA" | cut -d';' -f1 | grep -oE '[0-9]+$' | tail -n 1)
SECURITY_UPDATES=$(echo "$CHECK_DATA" | cut -d';' -f2 | grep -oE '[0-9]+$' | tail -n 1)
else
TOTAL_UPDATES=$(echo "$RAW_UPGRADE" | grep -c "^Inst" | tr -d '[:space:]')
SECURITY_UPDATES=$(echo "$RAW_UPGRADE" | grep -i "security" | grep -c "^Inst" | tr -d '[:space:]')
fi
RELEASE_CHECK=$(do-release-upgrade -c 2>/dev/null | grep -i "available" | wc -l)
OS_UPGRADE=$( [ "$RELEASE_CHECK" -gt 0 ] && echo "true" || echo "false" )
UPTIME=$(uptime -p | sed 's/up //' | tr -d '[:cntrl:]"' )
DISK_USAGE=$(df -h / | awk 'NR==2 {print $5}' | tr -d '[:space:]')
RAM_USAGE=$(free | grep Mem | awk '{printf "%.0f%%", $3/$2 * 100.0}' | tr -d '[:space:]')
CPU_LOAD=$(cat /proc/loadavg | awk '{print $1}' | tr -d '[:space:]')
LAST_USER=$(last -n 1 | grep -vE 'reboot|wtmp|^$' | awk '{print $1}' | head -n 1 | tr -d '[:space:]')
[ -z "$LAST_USER" ] && LAST_USER="System"
PAYLOAD=$(cat <<EOF
{
"hostname": "$HOSTNAME",
"ip": "$IP_ADDR",
"reboot_required": "$REBOOT_REQ",
"total_updates": "$TOTAL_UPDATES",
"security_updates": "$SECURITY_UPDATES",
"os_upgrade": "$OS_UPGRADE",
"package_list": "$PKG_LIST",
"uptime": "$UPTIME",
"disk_usage": "$DISK_USAGE",
"ram_usage": "$RAM_USAGE",
"cpu_load": "$CPU_LOAD",
"last_user": "$LAST_USER"
}
EOF
)
curl -s -X POST "$WEBHOOK_URL" -H "Content-Type: application/json" -d "$PAYLOAD"
Résultats
- Gouvernance IT : vision claire et interprétée de la santé du parc chaque matin pour la direction IT
- Gain de temps : suppression des vérifications manuelles SSH sur les serveurs individuels
Surveillance de la réputation IP Starlink et anti-blacklistage
Contexte
L'Incident : Interruption totale des services sur un plateau de production suite au blacklistage d'une adresse IP publique Starlink. La Cause : la nature dynamique des IPs Starlink peut attribuer des adresses ayant un historique de score de fraude élevé, provoquant des blocages par les pare-feu applicatifs (WAF) des partenaires. L'Enjeu : garantir la Continuité d'Activité (BCP) en détectant la dégradation de réputation avant que l'impact métier ne survienne.
Workflow
- Collecte Distribuée : un script Bash léger déployé sur les passerelles identifie l'IP de sortie réelle via curl et la transmet de manière sécurisée
- Trigger Webhook : n8n reçoit les données de flux via un endpoint sécurisé
- Enrichissement : interrogation de l'intelligence collective via l'API AbuseIPDB pour calculer le Confidence Score
- Persistance : archivage structuré dans Google Sheets pour l'analyse forensique et le suivi des tendances
Solution technique
#!/bin/bash
# Script : sentinel-ip-check.sh
# Fonction : Collecte l'IP publique et l'envoie à l'instance d'automatisation
# Identifiants masqués pour la sécurité
WEBHOOK_URL="https://xxxxxxxx.xxxx.xx/webhook/xxxxxxxx-xxxx"
VLAN_ID=$(hostname)
# Récupération de l'IP de sortie
PUBLIC_IP=$(curl -s https://icanhazip.com)
# Transmission sécurisée des métriques
curl -X POST "$WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d "{\"ip\": \"$PUBLIC_IP\", \"vlan_name\": \"$VLAN_ID\"}"
Résultats
- Indicateur Clé : 0 minute d'arrêt de production suite à une IP blacklistée depuis le déploiement
- Proactivité : l'équipe IT reçoit à 8h30 un rapport consolidé permettant une rotation préventive des IPs si le score dépasse 10%
Shadow IT Scanner : audit de conformité logicielle
Contexte
Afin de garantir la sécurité du système d'information et le respect des licences, un audit régulier des logiciels installés est obligatoire. Le problème : l'extraction brute depuis les outils d'inventaire génère un volume de données inexploitable (variations de noms, numéros de version infinis) rendant la détection des logiciels non autorisés (Shadow IT) impossible à l'œil nu. L'objectif était de créer un pipeline de normalisation et de catégorisation.
Workflow
- Déclencheur : un script Batch couplé à PDQ Inventory exporte un rapport CSV et le pousse vers un Webhook n8n
- Traitement & Nettoyage (Data Normalization) : un nœud JavaScript analyse les chaînes, supprime les mots parasites et tronque les versions via Regex
- Catégorisation : les logiciels sont regroupés par VLAN/Département, associant chaque logiciel au PC et à l'utilisateur ciblé
Solution technique
#!/bin/bash
# Script de Push : Export PDQ Inventory vers n8n
REPORT_PATH="D:\ApplicationsHebdo\Applications.csv"
WEBHOOK_URL="https://xxxxxxxx.xxxx.xx/webhook/ApplicationsHebdo"
curl -X POST \
-H "Content-Type: multipart/form-data" \
-F "data=@%REPORT_PATH%" \
"%WEBHOOK_URL%"
Résultats
- Visibilité Totale : génération automatique d'un classeur Google Sheets avec un onglet par VLAN
- Actionnabilité : pour chaque logiciel, l'équipe IT sait instantanément le nombre de postes, le PC et l'utilisateur concernés
- Conformité : détection instantanée des anomalies, réduction des risques Shadow IT et vulnérabilités
Agent de tri d'e-mails (n8n, Notion, Gemini)
Contexte
En tant que Manager IT, je reçois des centaines d'emails par jour : alertes serveurs, notifications automatiques, et demandes utilisateurs. Le tri manuel est chronophage et les emails critiques risquent d'être noyés. L'objectif était de créer un agent capable de filtrer le 'bruit' (supervision massive) sans consommer inutilement des tokens IA, pour ne pousser dans mon Notion que les tâches nécessitant mon intervention réelle.
Workflow
- Filtrage Pré-IA : un nœud 'If' élimine les emails d'exceptions et de supervision connus pour économiser les appels API
- Analyse LLM : l'IA analyse le corps de l'email pour déterminer la pertinence et structurer l'information
- Router de Tâches : si l'IA confirme qu'il s'agit d'une action pour moi, elle génère un résumé et une priorité
- Publication Notion : la tâche structurée est pushée dans ma base Notion avec titre, priorité, catégorie et plan d'action
Solution technique
// Structure du JSON attendu en sortie de l'IA
// L'intelligence réside dans le prompt système du nœud LLM Gemini
{
"is_task": true,
"is_for_me": true,
"owner": "Mbolafinaritra ANDRIANARIMANANA",
"priority": "CRITIQUE",
"category": "Infrastructure & Sécurité",
"title": "Maintenance Critique : Santé Parc Serveurs Linux",
"summary": "Analyse SRE : Action requise sur 9 serveurs (Docker, Zabbix, NXFilter, etc.). 25 mises à jour de sécurité critiques détectées sur le DNS et 44 sur Zabbix. Alerte saturation : CPU Docker (1.61 load) et Disque NXFilter (81%).",
"action_plan": [
"Planifier reboot : ansible, docker, glpi-v3, samba, squid, wazuh",
"Patching : 25 correctifs DNS + 44 correctifs Zabbix",
"Investigation : Surcharge CPU Docker & IO Disk NXFilter"
],
"source": "[email protected]",
"timestamp": "2026-05-15T08:35:05Z"
}
Résultats
- Une "Boîte de réception" Notion propre, catégorisée et priorisée automatiquement
- Réduction de 80% du temps passé à lire des emails non pertinents
- Économie de tokens IA grâce au filtre pré-LLM (nœud If)
- Visibilité temps réel sur les tâches critiques via le dashboard Notion
Pilotage automatisé du helpdesk à partir de GLPI
Contexte
Pour piloter un helpdesk traitant des centaines de tickets par mois, j'ai automatisé l'extraction des données GLPI, le calcul des indicateurs ITIL et l'analyse de la charge par technicien. Le rapport mensuel met en évidence les retards, les incidents récurrents et les déséquilibres de charge afin de décider où agir.
Workflow
- Ingestion & Data Cleaning : Un webhook n8n reçoit les exports GLPI. Plusieurs nœuds JavaScript effectuent un nettoyage intensif (exclusion des tickets 'Logistique' et 'Services Généraux' pour ne pas fausser les métriques purement IT).
- Calcul des SLAs : Le code JS recalcule les taux de réussite TTO/TTR par technicien et extrait le Top 5 des incidents récurrents.
- Stockage Structuré : La donnée nettoyée est ventilée dans plusieurs onglets d'un Google Sheets (Synthèse, Techniciens, Retards, Top Analyse) pour l'historisation.
- Analyse Cognitive : L'ensemble des données chiffrées est envoyé à Gemini 2.5 Flash-lite avec un prompt d'Ingénieur System/Manager pour rédiger le constat qualitatif.
Solution technique
// Extrait du Prompt de cadrage de l'IA (Gemini)
Analyse les données GLPI pour le mois de : {{ $json.mois }}
STRUCTURE DU RAPPORT EXIGÉE :
1. Analyse Quantitative : Volume, Taux de résolution, Stats TTO/TTR, Priorités.
2. Analyse Qualitative : Identifie 3 pôles critiques (ex: alertes sécurité Wazuh, comptes AD verrouillés). Donne le constat et l'impact métier réel.
3. Performance de l'Équipe : Top contributeurs, analyse de la charge de travail.
4. Axes d'Amélioration : Propose des actions basées sur le rééquilibrage de la charge et la réduction des incidents récurrents.
Rédige de manière exécutive. Interdiction d'utiliser du Markdown brut.
Résultats
- Pilotage Éclairé : Réception chaque mois d'un email HTML formaté (Dashboard exécutif) détaillant la santé du SI.
- Décisions Data-Driven : Détection automatique de la surcharge de certains collaborateurs (ex: un technicien absorbant 44% des tickets) permettant un rééquilibrage managérial proactif.
- Cybersécurité : L'IA identifie automatiquement les pics d'alertes du SOC (ex: CVE signalées par Wazuh) noyées dans le flux des tickets, alertant sur un risque de fatigue de l'équipe sécurité.
Pilotage d'une plateforme scolaire mise en production
Contexte
Conduite d'un projet SI pour un lycée privé, du besoin métier à la mise en production. La plateforme relie inscriptions, comptes utilisateurs, scolarité, notes, messagerie et réinscription dans un même système multi-rôles. J'ai pris en charge l'architecture, les échanges par API, la gestion des accès, le déploiement conteneurisé et l'exploitation.
Workflow
- Architecture full-stack découplée : API REST Symfony 7 derrière Nginx + frontend Next.js 16 / React 19 / TypeScript, orchestrés par Docker Compose (PostgreSQL 16, Symfony, Nginx, Next.js)
- Sécurité : authentification JWT (clés RSA) avec blacklist de tokens, firewall Symfony et garde JWT côté frontend via middleware
- Pattern BFF (Backend-For-Frontend) : le frontend proxifie chaque appel API via ses propres routes, le JWT vivant dans un cookie httpOnly invisible au JavaScript client (protection anti-XSS)
- Modèle de données riche : ~35 entités couvrant identité/sécurité, structure académique (années, cycles, niveaux, classes, matières, affectations enseignants), LMS, quiz, notes, vie scolaire et messagerie
- Règle métier clé : le coefficient et le volume horaire sont définis par couple Niveau + Matière ; une classe hérite dynamiquement des matières de son niveau, et une affectation enseignant est propre à un triplet classe × matière × année scolaire
- Provisionnement automatique : la validation d'une demande d'inscription crée le compte élève et affiche un mot de passe temporaire à usage unique
- Réinscription par QR code : un jeton à usage unique par élève est imprimé en QR sur le bulletin final ; le parent le scanne, atterrit sur un formulaire de réinscription pré-rempli et confirme en quelques secondes ; la demande rejoint la file de validation admin
Solution technique
// Pattern BFF : le frontend Next.js proxifie l'API Symfony.
// Le JWT vit dans un cookie httpOnly : invisible au JS client (anti-XSS),
// jamais exposé au navigateur, injecté côté serveur uniquement.
// middleware.ts : garde JWT à l'entrée des espaces authentifiés
export function middleware(req: NextRequest) {
const token = req.cookies.get("auth_token")?.value
if (req.nextUrl.pathname.startsWith("/dashboard") && !token) {
return NextResponse.redirect(new URL("/login", req.url))
}
return NextResponse.next()
}
// app/api/grades/route.ts : route BFF : proxy vers l'API Symfony interne
export async function POST(req: Request) {
const token = (await cookies()).get("auth_token")?.value
const res = await fetch(`${process.env.BACKEND_INTERNAL_URL}/api/grades`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`, // ajouté côté serveur, jamais côté client
},
body: await req.text(),
})
return new Response(await res.text(), { status: res.status })
}
Résultats
- Plateforme complète déployée en production via Docker Compose : site vitrine public + inscriptions en ligne + ENT multi-rôles (élève / enseignant / admin / parent)
- Périmètre fonctionnel large : LMS (cours, chapitres, ressources PDF/vidéo/lien, reprise de progression), quiz QCM chronométrés avec barème, notes & moyennes pondérées, vie scolaire (appel présent/absent/retard + justificatifs), emploi du temps anti-conflit, messagerie et annonces ciblées par rôle/classe
- Back-office d'administration : CRUD utilisateurs & rôles, configuration de l'établissement (années, cycles, niveaux, classes, matières), gestion des inscriptions, dashboard analytique et exports CSV (utilisateurs, notes, assiduité)
- Réinscription par QR code, sans ressaisie annuelle : le QR imprimé sur le bulletin ouvre une demande de réinscription pré-remplie, sécurisée par un jeton à usage unique et validée par l'admin
- Côté structure : ~35 entités Doctrine, ~30 contrôleurs REST, sécurité JWT (RSA + blacklist), pattern BFF anti-XSS, TypeScript côté frontend