sMug@replicatorbe
~/Publications/Infrastructure/le-vocabulaire-change-plus-vite-que-les-problemes

Le vocabulaire change plus vite que les problèmes

Infrastructure / /13 min de lecture

En republiant des articles écrits entre 2007 et 2019, j'ai relu vingt ans de mes propres pannes. Presque tout le vocabulaire est mort ; presque aucun des problèmes. Inventaire de ce qui a seulement changé de nom — et de ce qui a réellement changé, parce qu'il y en a.

En 2012, j'ai passé une soirée sur un bug qui n'en était pas un. Mon client de chat en ActionScript 3 se connectait au serveur IRC, envoyait sa première commande, et le serveur fermait la connexion sans un mot.

La cause tenait en un octet. XMLSocket terminait chaque message par un octet nul. IRC exige un retour chariot suivi d'un saut de ligne. Deux couches qui ne s'entendaient pas sur la façon de dire « fin du message ». Certains serveurs IRC acceptaient un module qui tolérait le nul. J'ai refusé de le demander : on ne demande pas à un serveur de se conformer à un client. La solution était la classe Socket, arrivée dans AS3 fin 2006, qui lit et écrit du binaire brut sans dicter le format. Je l'ai racontée en détail à l'époque.

Quatorze ans plus tard, le même chat tourne dans un navigateur, sans greffon, et plus personne ne se pose la question. Entre les deux, je l'ai réécrit une fois de plus, en Flutter, pour Android et iOS. Trois fois le même service rendu, trois réponses différentes à la même question. Ce n'est pas le problème qui a été résolu : c'est l'endroit où on le règle qui a bougé.

Depuis un an, je remets en ligne des textes écrits entre 2007 et 2019. À les relire d'affilée, une chose saute aux yeux : presque tout le vocabulaire est mort, et presque aucun des problèmes.

Le même client de chat, écrit trois fois

En 2020, j'ai refait l'application en Flutter, pour les deux magasins. Sur mobile, dart:io donne une vraie socket TCP, chiffrée si on le demande : SecureSocket.connect(host, 6697). Elle rend un flux d'octets, et rien d'autre. Personne ne décide à ma place où s'arrête un message — donc c'est encore à moi de le faire.

socket
    .transform(utf8.decoder)
    .transform(const LineSplitter())
    .listen(traiterLigne);

Deux lignes de dart:convert, et le délimiteur choisi par IRC en 1988 est réimplémenté en 2020. Avec un piège au passage : IRC n'a jamais garanti de l'UTF-8 valide, et un décodeur strict lève une exception au premier octet douteux — un pseudo mal encodé suffit à couper la connexion. C'est allowMalformed, ou on apprend la leçon en production.

Et dans le navigateur, la question disparaît. WebSocket encadre lui-même chaque message dans sa propre trame ; on ne découpe plus rien parce que quelqu'un l'a fait un étage plus bas. Le détail qui m'a amusé, c'est que le code Dart de l'application mobile ne peut pas servir : dart:io n'existe pas sur le web. La plateforme reprend la socket d'une main et rend le cadrage de l'autre.

Trois époques, trois réponses — et ce sont les trois seules qui existent. Un délimiteur, une longueur annoncée d'avance, ou la trame de la couche en dessous. Il n'y en a jamais eu de quatrième. IRC a choisi le délimiteur en 1988, WebSocket la trame en 2011, et entre les deux j'ai perdu une soirée parce que Flash avait choisi un troisième délimiteur sans le dire à personne.

Ce que j'en ai gardé n'a rien à voir avec Flash ni avec Dart. Quand deux systèmes ne se parlent pas, je regarde d'abord où chacun croit que le message s'arrête. C'est vrai d'une socket, d'un fichier CSV et d'une trame radio.

Serveur dédié, bare metal, et ce qu'on a perdu entre les deux

Le premier hébergement que j'ai payé, chez Double V Network, se facturait au nombre de PID. Un pour l'IRCd, un pour l'eggdrop qui animait les salons de jeux, un pour Anope — les services de pseudos et de salons — et un pour le BNC, qui gardait ma connexion ouverte quand je fermais le client. Quatre processus, et il fallait compter. À quatorze ans, un processus supplémentaire entrait déjà dans une réflexion budgétaire.

Puis un serveur dédié, chez Sivit.fr. Et là, une phrase que je n'ai comprise qu'après coup : quand il tombait, il fallait le réparer. Pas le détruire et en relancer un autre en trente secondes. Il était là. C'était le même objet le lundi que le vendredi.

« Bare metal » est le mot qu'on a inventé quand la machine physique a cessé d'être la valeur par défaut. Personne ne disait « serveur bare metal » en 2007 : on disait « le serveur », parce qu'il n'y avait rien d'autre. Le terme ne décrit pas une technologie, il décrit un contraste — et ce contraste, c'est le jetable.

Aujourd'hui je fais tourner les deux. Une Debian qui reste, des conteneurs qu'on reconstruit. En 2016 j'écrivais ici qu'il fallait un conteneur par service ; en 2024 j'ai expliqué pourquoi j'étais revenu à un nginx, un PHP-FPM et une base partagés pour tous mes sites. J'ai fait le chemin dans les deux sens, et c'est le trajet qui m'a appris quelque chose, pas la destination.

Le disque plein, deux fois, à dix-sept ans d'écart

Vers 2007, mon réseau Espace-IRC prend une attaque de clones. Des dizaines de connexions par proxy, refusées, journalisées. Chaque refus écrit une ligne. Le disque arrive à 100 %, l'hébergeur prévient que la prochaine intervention sera facturée. Personne ne m'avait dit : aujourd'hui tu vas apprendre la rotation de logs.

En 2024, un dimanche, un disque plein sur un petit serveur. Les journaux de conteneurs, cette fois. La correction tient en deux lignes de YAML : max-size: 10m, max-file: 3.

Sauf que l'histoire est moins propre que ça. Entre-temps on a appris à provisionner : on taille une machine virtuelle, on lui donne un disque qu'on juge large, et on considère la question réglée. Elle ne l'est pas. Un conteneur ne consomme pas que ses journaux. Il laisse des images intermédiaires à chaque reconstruction, la couche d'écriture de ceux qu'on a arrêtés sans les supprimer, des volumes anonymes que plus rien ne réclame, un cache de build. Rien de tout ça n'a été décidé : ça s'accumule parce qu'on a construit, et construire est devenu gratuit.

Alors je regarde docker system df avant de chercher qui écrit trop. Souvent, ce n'est pas un journal emballé — c'est l'empilement de tout ce que j'ai fabriqué et jamais rangé.

Entre les deux, le mot a changé. On ne dit plus rotation de logs, on dit politique de rétention, et il existe des produits pour ça. Le geste, lui, est identique, et la liste de ce qu'il faut borner s'est seulement allongée. Il s'écrit le jour de l'installation, ou il ne s'écrit jamais. Un disque qui se remplit tout seul est la seule panne que j'aie vue deux fois à dix-sept ans d'intervalle, pour exactement la même raison : quelque chose grossissait sans que personne lui ait dit jusqu'où.

L'horloge est le vrai problème, et elle l'a toujours été

Un mardi matin, on me demande les images d'une nuit passée. L'enregistreur retarde de onze minutes sur le reste du parc. Un quartz dérive d'environ une seconde et demie par jour, et il ralentit toujours dès qu'on s'éloigne de 25 °C. Personne ne s'en aperçoit tant que personne ne demande rien.

Mon erreur ce jour-là n'a pas été la dérive, que je ne pouvais pas empêcher. Elle a été de remettre l'heure à l'heure avant d'avoir noté l'écart. En corrigeant l'horloge, je venais de supprimer la seule information qui permettait de recaler les semaines déjà enregistrées.

Une horloge fausse dont on connaît l'erreur reste utilisable ; une horloge fausse dont on ignore l'erreur détruit la chronologie.

C'est la même règle que je m'impose devant une capture réseau : noter l'heure de l'événement, l'heure système de la sonde et le décalage entre les deux avant de commencer. Un décalage de fuseau non documenté a déjà envoyé une analyse entière au mauvais endroit.

Et l'horodatage ressort toujours par une porte à laquelle on n'a pas pensé. Un ETag nginx, par exemple, n'est rien d'autre que la date de modification du fichier et sa taille, écrites en hexadécimal. Retirer l'en-tête Last-Modified en croyant masquer la date du fichier ne masque rien du tout : on l'a déplacée deux lignes plus bas, en base 16.

Écouter ce qui sort plutôt que réclamer une API

En 2017, j'installe un portier vidéo qui n'expose aucune API. Impossible de savoir qu'on a sonné. Alors j'ai écouté le routeur :

tcpdump -i br-lan -l -vvv dst host 192.168.0.206

À chaque appui, l'appareil arrose cinq ou six serveurs en UDP, des paquets de soixante octets, tous sur le port 10006, en moins de trois millisecondes. Et un nombre toujours présent dans la rafale : 277. Un grep sur ce chiffre, un curl derrière, et la caméra s'affiche sur la télévision. Plus une seule sonnerie manquée.

Cinq ans plus tard, même geste sur une capture de plusieurs gigaoctets après une alarme : capinfos pour cadrer, tshark -q -z conv,tcp pour voir qui parle à qui, editcap pour découper vingt minutes autour de l'heure, et seulement ensuite l'interface graphique. Trois trames d'un côté, trois gigaoctets de l'autre, exactement le même raisonnement.

Aujourd'hui ça s'appelle de l'observabilité réseau et ça se vend en licences. En 2017, ça s'appelait brancher tcpdump sur le bon pont et lire ce qui passe. Un objet connecté ne sait pas travailler seul : à chaque événement il bavarde avec ses serveurs. Si on ne peut pas lui demander de nous prévenir, on peut au moins écouter ce qu'il dit aux autres.

Il faut dire la limite avant de conclure. Écouter le réseau est un contournement, et je l'annonce comme tel chaque fois que je le fais. Celui-là a parfaitement fonctionné — et le portier n'est resté que deux ans. C'est toute la démonstration : l'astuce était bonne, le matériel ne valait rien.

Chez moi je l'assume, ça ne m'a coûté qu'une soirée. Au travail, jamais. On écrit l'interface dans le cahier des charges, on exige une documentation, et on écarte le matériel qui n'en a pas — même moins cher, même plus joli en démonstration.

Parce qu'un appareil sans API ne coûte pas moins cher : il coûte plus tard. Il oblige à deviner un protocole qui changera au prochain firmware, il ne s'intègre à rien sans qu'on écrive la colle, et il dépend d'un service en ligne que le fabricant fermera un jour sans prévenir. Ce jour-là on ne perd pas une fonction, on perd l'appareil. Le bas de gamme se paie en temps d'ingénieur, et ce temps-là n'apparaît sur aucun bon de commande.

Réduire ce qui est joignable

En 2011, je faisais tourner un jeu Java dans un navigateur sans signer l'applet, donc sans jamais demander la moindre permission. La contrainte était sèche : pas de disque, pas de processus, et aucune communication avec un autre serveur que celui d'origine. C'était la politique de même origine avant qu'on lui donne ce nom.

En 2012, sur mon serveur IRC, j'activais des modules qui masquaient la liste des serveurs et des modules chargés. J'écrivais déjà à l'époque que ça n'arrêterait personne de compétent. C'était vrai, et c'est la seule ligne de ces archives que je n'ai pas eu à corriger.

En 2024, plus aucun port publié sur mes conteneurs, la base isolée sur un réseau interne, les sites montés en lecture seule. Sur les installations vidéo, un réseau dédié, et les caméras bloquées entre elles — pas seulement vis-à-vis de l'extérieur.

Et ce site, en 2026, ne fait plus tourner la moindre ligne de code à la visite. Les scanners qui cherchent /wp-login.php reçoivent une 404 rigoureusement identique à toutes les autres. Ce n'est pas moins de code exposé : c'est zéro code exposé. La différence est de nature, pas de degré.

Le mot d'aujourd'hui pour tout ça, c'est zero-trust. L'idée n'a pas d'âge : on n'autorise pas ce qu'on n'a pas eu besoin d'autoriser.

Ce qui a vraiment changé

Je me méfie du billet où un ancien explique que rien n'est nouveau. Quatre choses ont changé pour de bon, et elles comptent.

Le coût de l'erreur, d'abord. Le serveur qu'il fallait réparer imposait de comprendre la panne. Aujourd'hui on détruit et on relance, et c'est un progrès réel — mais on répare moins, donc on comprend moins. Je ne sais pas encore quoi faire de cette phrase.

Le bruit de fond, ensuite — et là je dois me corriger, parce que j'ai longtemps raconté cette période de travers. L'attaque automatique n'a rien de neuf. Mon premier piratage date de 2007 : une force brute sur un compte FTP, celui d'un de mes vieux sites de chat, que personne n'avait choisi de viser. Je n'utilisais pas encore SFTP — le mot de passe passait en clair, et rien côté serveur ne se fatiguait de voir échouer mille tentatives. L'attaquant n'a rien cassé et n'a rien effacé : il a ajouté des liens vers ses propres sites, servis uniquement aux robots des moteurs de recherche. Du cloaking. Je visitais mes pages, tout allait bien ; c'est Google qui voyait l'autre version.

Ce qui a changé n'est donc pas le fait d'être attaqué sans être visé — c'était déjà vrai. C'est la permanence, et surtout ce que ça rapporte. En 2007 on volait du référencement. Aujourd'hui on revend de la puissance, des identifiants et des relais. La motivation a monté d'un cran, donc l'insistance aussi.

Je garde surtout la leçon de la forme de l'attaque : elle était invisible depuis la seule place d'où je regardais. C'est la même chose qu'un ETag qui continue d'annoncer une date qu'on croyait avoir retirée. Une information sort par plusieurs tuyaux, et on ne pense à fermer que celui qu'on voit.

La chaîne d'approvisionnement, aussi. En 2007 j'avertissais mes lecteurs qu'un installeur de messagerie glissait des « sponsors » si on cliquait Suivant sans lire. C'était artisanal. C'est aujourd'hui le vecteur sérieux, et c'est pour ça que ce blog n'a aucune dépendance : pas de composer.json, pas de node_modules, un seul require_once.

La vitesse, enfin. Les modèles de langage sont le vecteur de changement le plus rapide que j'aie vu en vingt ans. J'en ai mis un en production pour modérer un chat, avec ce qu'il attrape et ce qu'il rate. Un outil de plus — à condition de savoir vérifier ce qu'il produit.

Ce que je retiens

  1. Un problème résolu n'a pas disparu, il a été descendu d'un étage. Le cadrage des messages est devenu invisible parce qu'une couche s'en charge, pas parce qu'il a cessé d'exister.
  2. Le mot neuf sert à vendre, l'ancien à comprendre. « Bare metal » ne décrit pas une machine, il décrit ce que le jetable a rendu remarquable.
  3. Les fondamentaux tiennent dans une main : où finit un message, quelle heure il est vraiment, ce qui grossit sans qu'on lui ait dit jusqu'où, ce qui est joignable, et par où ça passe. Le reste est de l'emballage, et l'emballage change tous les trois ans.
  4. Ce qu'on n'a pas mesuré avant de corriger est perdu. L'horloge de l'enregistreur me l'a appris une fois ; ça a suffi.
  5. Une technologie meurt, une habitude reste. Flash est mort, l'applet est morte, le 433 MHz en clair aussi. Le mot de passe en clair dans un fichier de sauvegarde, lui, se porte très bien.

La prochaine pile arrivera dans trois ans et elle aura son vocabulaire à elle. Ce sera encore un message qu'il faut savoir terminer, une horloge à recaler, quelqu'un à reconnaître et un chemin réseau à fermer.

Une question, un projet ?

Infrastructure, réseau, sûreté ou cybersécurité — le canal est ouvert.

jerome@fafchamps.be