Concevoir, tester et déployer pour que les erreurs humaines et les attaques ne fassent pas tomber la production.
Pourquoi ce livre
Un dev web livre du code, puis se pose deux questions gênantes. Qui peut toucher la production, et avec quels droits ? Et comment savoir que ce qui tourne est bien ce qu'on a écrit ? Ce livre part d'une thèse : la sécurité et la fiabilité ne se greffent pas après coup, elles se conçoivent dès le départ.
Les auteurs sont six ingénieurs de Google, côté sécurité et côté SRE (Site Reliability Engineering : les équipes qui exploitent la production et la gardent debout). Il traite les pannes honnêtes et les attaques comme un seul sujet : une erreur humaine et un attaquant font tomber la production de la même façon, et se préviennent par la même conception.
Trois familles : concevoir (idées 1 à 4), fabriquer et livrer (5 à 8), tenir et se relever (9 et 10). L'idée 7, sur le déploiement et la provenance, est le cœur.
Trois avertissements. L'échelle est celle de Google : des milliers d'ingénieurs, des outils maison. Le code est surtout du C++ et du Java. Enfin le livre date de 2020 et ne dit rien des agents de code (des outils d'IA qui écrivent et modifient du code, parfois seuls). Tout rapprochement avec eux est donc de moi, dans les encadrés « Ma lecture » (mon avis, hors livre). Les renvois « (ch. N) » désignent le chapitre N du livre.
Je l'ai ouvert pour combler, dans le Grand livre du site, les chapitres sur la qualité et la sécurité web. Je laisse de côté les profils d'attaquants et la gestion de crise multi-équipes.
Les idées qui restent
1Une panne de sécurité est une panne : on ne greffe ni l'une ni l'autre après coup
On range souvent la sécurité et la fiabilité dans « ce qu'on ajoutera plus tard ». Le livre répond que toutes deux « sont des propriétés émergentes de la conception d'un système » (ch. 1). Une propriété émergente n'appartient à aucune pièce. Elle naît de l'assemblage, donc on ne la répare pas en changeant une pièce.
L'ouverture du livre en donne la preuve. Le 27 septembre 2012, le gestionnaire de mots de passe interne de Google tombe. Un courriel annonce à des milliers d'employés le nouveau mot de passe du WiFi des bus, rangé dans ce gestionnaire. Tous viennent le lire : le trafic explose, au-delà de ce que supportait un outil conçu pour quelques administrateurs. Le service n'avait pas de load shedding (abandonner une partie des requêtes pour sauver le reste). Cette panne est un problème de fiabilité. Mais la reprise s'est enlisée à cause de la sécurité. Le redémarrage exigeait une carte HSM (un boîtier matériel qui garde des clés). Cette carte était dans un coffre. La combinaison du coffre était dans le gestionnaire en panne. Il a fallu une perceuse pour le coffre, puis une heure de plus : le voyant vert du lecteur mentait, la carte était à l'envers (ch. 1).
Pourquoi traiter les deux ensemble, alors qu'elles se distinguent ? La fiabilité vise des pannes sans intention. La sécurité affronte un adversaire actif, qui cherche la faille. Et leurs remèdes se contredisent parfois. La redondance aide la fiabilité mais agrandit la surface d'attaque. En incident de sécurité, on réduit le cercle des intervenants, pour ne pas alerter l'attaquant. En incident de fiabilité, on l'élargit, pour varier les points de vue. Les journaux aident la reprise mais deviennent une cible (ch. 1).
Un changement anodin suffit à tout casser. Un développeur open source retire deux lignes d'OpenSSL (dans la version Debian) pour faire taire un outil de débogage. Résultat : la graine du générateur aléatoire (son point de départ) se réduit à un numéro de processus entre 1 et 32 768. La force brute retrouve alors les clés. Plus près de chez nous, YouTube est indisponible plus d'une heure en octobre 2018. La cause : un petit changement dans une bibliothèque de journaux, qui avait passé revue et tests. Sous la charge, les serveurs ont manqué de mémoire et les pannes en cascade ont tout arrêté (ch. 1).
Ces deux qualités sont invisibles tant que tout va bien, donc on les croit reportables. Le livre chiffre l'addition d'après des articles de presse. La fuite de Yahoo aurait fait baisser de 350 millions de dollars le prix de rachat par Verizon. La panne électrique de Delta a annulé près de 700 vols (ch. 1). Le piège, dit-il, est de les sacrifier « au nom de la vélocité » (ch. 1).
Hors livre, agents de code. Un agent de code, c'est de la vélocité au carré. Un changement banal passe revue et tests (YouTube) : les garde-fous doivent donc être structurels (droits, vérifications, déploiement), pas une promesse de bonne volonté.
2Le moindre privilège se conçoit : on limite les accès parce que les gens se trompent
Donner la clé de la production à un collègue « de confiance » semble raisonnable. Le livre refuse ce raccourci : « Les ingénieurs peuvent se tromper, leurs comptes peuvent être compromis, ou ils peuvent être malveillants » (ch. 5). Un privilège est un droit d'agir (lire, écrire, redémarrer). Le moindre privilège donne seulement ceux dont la tâche a besoin. La commande copiée-collée au mauvais endroit compte autant que l'attaquant.
D'abord, classer l'accès par risque. Le livre propose trois niveaux de données : public, sensible, très sensible (pour ce dernier, « aucun accès permanent »). Il les croise avec trois gestes : lire, écrire, toucher l'infrastructure. Une API qui efface des données ne se traite pas comme une API qui les lit.
Ensuite, préférer de petites API fonctionnelles, où un point d'entrée fait une seule chose. Un shell interactif, lui, expose tout le système : on y lance n'importe quoi. Auditer une session ne suffit pas : l'audit note après coup, n'empêche rien, et se contourne. Il « garde seulement honnêtes les gens honnêtes » (ch. 5). L'exemple du livre : depuis l'éditeur vim, :!/bin/evilcmd lance une commande sans passer par l'historique du shell, donc sans laisser de trace.
Cas concret : pousser une configuration web. La voie large est OpenSSH, c'est-à-dire un shell complet sur le serveur. La voie étroite est l'option ForceCommand d'OpenSSH, qui limite la connexion à un seul acte : déposer le fichier, dont on journalise l'empreinte. Un récepteur HTTP ou gRPC fait la même chose.
Quand il faut contourner la règle, le livre prévoit le breakglass (« briser la vitre », d'après l'alarme incendie) : un contournement de l'autorisation, réservé à l'équipe SRE du service, surveillé et testé régulièrement (ch. 5). Dans un réseau zero trust (où l'on se méfie de l'emplacement), il n'est utilisable que depuis des lieux précis. Un breakglass utilisé souvent signale qu'il manque une API normale. D'où un audit hebdomadaire par les pairs. Mais « sans renforcement culturel, les audits deviennent des tampons de validation (on approuve sans lire) et le breakglass un usage quotidien » (ch. 5).
Autour du breakglass, trois outils. Une justification structurée : un numéro de ticket que le système vérifie, pas un texte libre. Un accès temporaire, qui expire. Une MPA (autorisation multi-parties : une seconde personne doit approuver). Condition : s'assurer que « la technologie et la dynamique sociale permettent à quelqu'un de dire non » (ch. 5).
Dernier point, souvent oublié : tester les refus. On décrit ce que chaque rôle peut faire, on écrit des scénarios au résultat attendu, et on les rejoue avant tout changement de droits. Sinon, « ils testeront en production, en contournant les contrôles que vous avez mis en place » (ch. 5). À un client sans droit, on répond un 403 aveugle (« interdit », sans détail), car un refus détaillé aide à deviner la politique.
Hors livre, version réduite. À l'échelle d'un dev ou d'une petite équipe, l'essentiel tient en un ticket de justification, un accès qui expire et un breakglass journalisé. Pour un agent de code, appliquez la même règle : il ne reçoit jamais les identifiants du développeur, mais les siens, avec les droits de sa tâche et rien en production.
3Le proxy sûr : un seul passage pour l'accès opérateur, qui journalise et filtre
Comment imposer ces règles à un système existant, sans le réécrire ? Le livre répond par un cas d'étude : le proxy sûr. Un proxy est un intermédiaire. Le client lui parle, jamais à la cible.
Le fonctionnement tient en quatre gestes. Le proxy reçoit une demande (un RPC : un appel de fonction à travers le réseau). Il la journalise. Il la compare à une politique d'accès, des ACL (listes de contrôle d'accès : quel rôle peut lancer quelle action). Seulement ensuite, il exécute (ch. 3).
Google l'appelle le Tool Proxy. C'est un binaire qui expose un RPC générique : il lance la ligne de commande demandée, et chaque lancement est contrôlé par la politique, journalisé, avec une MPA possible. Exemple du livre : un membre de group:admin peut lancer l'outil borg après l'approbation de group:admin-leads. La politique embarque ses propres tests unitaires, avec un résultat attendu ALLOW (ch. 3). Le serveur cible refuse toute connexion directe, sauf par breakglass.
Le livre cite cinq bénéfices. Une MPA centralisée. Un audit des actes d'administration. Une limitation de débit : un redémarrage à la fois plutôt que tous d'un coup, donc une erreur touche moins de machines. La compatibilité avec des systèmes tiers fermés. Des améliorations de sécurité ajoutées en un seul endroit (ch. 3). Le proxy reprend les mêmes API que la cible, donc l'expérience des ingénieurs ne change pas.
Il vise un objectif de Google, Zero Touch Prod : tout changement en production est automatisé, validé d'avance, ou déclenché par un breakglass audité. Le livre estime que 13 % des pannes évaluées chez Google auraient pu être évitées ou atténuées par cette discipline (ch. 3). C'est une estimation du livre, pas une mesure.
Les inconvénients sont avoués. Le proxy coûte à maintenir. Il devient un point de défaillance unique (si lui tombe, plus personne n'agit), d'où plusieurs instances. Sa politique est source d'erreurs, d'où des modèles de politique sûrs par défaut. Et une machine centrale attire les attaquants, d'où une règle nette : le proxy n'a pas de privilèges élevés. Il transmet l'identité du demandeur et agit en son nom, car « aucune requête n'est exécutée sous un rôle de proxy » (ch. 3). Qui prend le proxy n'hérite donc pas d'un rôle puissant en propre. Le livre le présente comme l'option économique pour un système existant, plus solide quand on la combine avec les principes de l'idée 2.
Hors livre, agents de code. Le motif se transpose tel quel. Un agent de code qui lance des commandes sur un serveur devrait parler à un petit récepteur (HTTP ou gRPC). Ce récepteur journalise et n'accepte qu'une liste d'actions. L'agent n'a pas de shell.
4Dire ce qui est toujours vrai : des invariants, et une petite base de confiance
On croit comprendre son système parce qu'on l'a écrit. Le livre demande une preuve plus exigeante. Il définit l'invariant comme « une propriété toujours vraie, quel que soit le comportement ou le mauvais comportement de l'environnement du système » (ch. 6). Exemples : « toute valeur externe est validée ou encodée avant d'atteindre une API sensible à l'injection ». Ou, côté fiabilité : « un composant surchargé renvoie une erreur de surcharge plutôt que de planter ». Des retries (réessais automatiques) sans pause surchargent encore le composant jusqu'à le faire planter : ils violent le second exemple (idée 9).
Pourquoi des invariants, pas des tests ? Parce qu'une propriété « pour tous les comportements » ne se teste pas : les tests couvrent une petite part des cas. Le livre le dit sobrement : « l'absence de preuve n'est pas la preuve de l'absence » (ch. 6). À l'autre extrême, la preuve formelle d'un micro-noyau a coûté environ 20 années-personnes, ce qui est irréaliste pour une application. Le chapitre vise le milieu : des arguments informels mais disciplinés.
Un modèle mental (l'image simplifiée qu'on se fait du système) aide, mais il se brise sous attaque ou surcharge. Remède concret du livre : des serveurs de production sans swap (la mémoire de secours sur disque). Un service à court de mémoire renvoie alors vite une erreur prévisible, au lieu de ramer indéfiniment (ch. 6).
L'ennemi nommé est la complexité : « L'ennemi principal de la compréhensibilité est la complexité non gérée » (ch. 6). Deux remèdes. Des composants plus petits. Et un framework (un cadre de code commun) qui centralise authentification, autorisation, journalisation et délais : un relecteur lit le framework et la configuration, pas chaque méthode.
Reste la notion de TCB (base de confiance : l'ensemble des composants dont la défaillance casse la politique de sécurité). Plus elle est petite, plus elle est auditable. L'exemple du livre est un site de vente de widgets. En monolithe avec une base unique, tout est dans la TCB : une injection SQL (idée 5) dans la recherche du catalogue expose les adresses des clients. Découpé en microservices (petits services séparés, chacun avec sa base), la TCB se réduit au service d'achat. Un jeton de contexte de l'utilisateur final est un ticket court, émis par un service central d'authentification : il prouve que la requête vient de cet utilisateur. Le service d'achat l'exige : un frontend compromis ne lit que les données de l'utilisateur dont il détient le ticket (ch. 6).
Et une origine web séparée pour le paiement (un sous-domaine distinct : le navigateur cloisonne les pages par origine) isole une faille XSS du catalogue (ch. 6).
Hors livre. Écrire trois invariants par projet, sous forme de tests qui échouent s'ils sont violés. Pour un agent, ils servent de cahier des charges vérifiable : il peut modifier tout, sauf ce qui casse un invariant.
5Rendre le bug inexprimable : des types et des frameworks plutôt que des relectures
Les humains ne maintiennent pas un invariant global sur des milliers de fichiers. Le livre l'assume : « même les ingénieurs les mieux formés font des erreurs » (ch. 12). La relecture manuelle ne suffit pas non plus. Les relecteurs gravitent vers les attaques intéressantes. Ils délaissent les centaines de gabarits HTML à vérifier un par un contre le XSS (injection de script dans une page, vu par le visiteur).
La réponse est d'écrire des bibliothèques et des frameworks qui rendent la classe de bug impossible à écrire. Une correction faite à un endroit profite à toutes les applications. Premier exemple : un framework de serveur d'appels distants avec des intercepteurs. Ce sont des fonctions lancées avant et après chaque requête pour journaliser, authentifier, autoriser et limiter le débit. Si la requête est refusée, la logique métier ne s'exécute pas, mais le refus est journalisé (ch. 12).
Second exemple, plus parlant : les types assainis. Une injection SQL arrive quand une requête est construite en collant du texte venu de l'utilisateur. Le livre définit un type TrustedSqlString : on ne peut en fabriquer que depuis des littéraux (du texte écrit tel quel dans le code source). En Go, il s'obtient par un type alias stringLiteral privé au package : le code appelant ne peut pas en créer, mais les littéraux s'y convertissent d'eux-mêmes. Les fonctions de requête n'acceptent plus que ce type. Un texte venu de l'extérieur, ou sa concaténation avec une requête, n'est pas un littéral : il n'a pas le bon type, et le compilateur refuse le programme (ch. 12). Même principe pour le XSS, avec des types SafeHtml et SafeUrl et des gabarits à échappement selon le contexte.
Une issue de secours existe : un package unsafequery, relu par un ingénieur sécurité à temps partiel, à tour de rôle, pour des centaines à des milliers de développeurs (ch. 12). La relecture se concentre sur les rares endroits qui sortent des rails.
Le chiffre le plus fort du chapitre : les applications d'un framework interne conçu avec ces types ont eu « bien moins de vulnérabilités XSS signalées (de deux ordres de grandeur) » que celles écrites sans types sûrs, pourtant relues avec soin (ch. 12). Deux ordres de grandeur, c'est environ cent fois moins.
L'aveu : c'est plus dur à greffer sur du code existant. Le livre décrit un déploiement progressif. On ajoute une surcharge qui accepte le type sûr. On restreint l'ancien appel par annotation. Des hooks Git bloquent les nouveaux usages. Puis on nettoie le reste. Autre retour du livre : les erreurs de compilation donnent un retour immédiat, et les développeurs adoptent une API sûre quand le cycle est rapide et la correction simple.
Leviers plus brefs : un code simple, des types forts, le détecteur de data races de Go. Et un langage à mémoire gérée, qui libère la mémoire pour vous : une erreur de mémoire laisse lire ou écraser ce qui n'est pas à soi. Environ 70 % des vulnérabilités chez Microsoft en viennent, et 85 % des bugs d'Android (ch. 12).
Hors livre, agents de code. Un compilateur et un type qu'on ne fabrique qu'à un endroit sont un relecteur qui ne se fatigue pas. Face à du code généré, c'est la défense la moins chère : l'agent peut écrire n'importe quoi, le compilateur refuse ce qui n'est pas du type sûr. Les gabarits html/template de Go et l'échappement automatique de Twig vont dans le même sens.
6Tester par familles : sanitizers la nuit, fuzzing en continu, analyse statique en revue
Un test unitaire vérifie ce qu'on a pensé à vérifier. Le livre en ajoute trois familles pour ce qu'on n'a pas pensé : les sanitizers, le fuzzing et l'analyse statique. Elles ont des coûts différents, donc on les place à des étapes différentes de la CI (intégration continue : la chaîne qui construit et teste à chaque changement).
Un sanitizer est un compilateur qui insère des contrôles dans le programme. AddressSanitizer entoure chaque allocation de zones « rouges » empoisonnées et marque la mémoire libérée comme empoisonnée. Un débordement ou une réutilisation de mémoire libérée déclenche alors une erreur. D'autres détectent les comportements indéfinis, les accès concurrents ou les fuites. Le coût : les binaires instrumentés « peuvent être plus lents que les binaires natifs de plusieurs ordres de grandeur » (ch. 13). Réponse du livre : les lancer la nuit, pas à chaque commit.
Le fuzzing envoie à un programme des entrées aléatoires ou mutées pour le faire planter. Un moteur génère les entrées, un pilote les transmet à la cible : un analyseur de format, un décodeur, un protocole. Un dictionnaire de mots-clés et un corpus (des exemples valides de départ) évitent de buter sur le rejet des entrées invalides : un analyseur écarte aussitôt le bruit pur, un exemple valide va plus loin. L'entrée fautive devient ensuite un test de non-régression. Limite assumée : « il n'est pas faisable de bloquer chaque commit sur le résultat d'un test long » (ch. 13). Le bug peut donc être déjà fusionné quand le fuzzing le trouve : il complète, il ne remplace pas.
OSS-Fuzz, le service de fuzzing continu de Google pour les projets libres, a trouvé plus de mille bugs en cinq mois (lancement : décembre 2016). Tricorder, l'outil d'analyse statique de Google, examine environ 50 000 changements par jour avec 146 analyseurs. Un faux positif est une alerte à tort. Tricorder mesure les faux positifs perçus grâce à un lien « Not useful » que le relecteur clique en revue, et plafonne ce taux à 10 % (ch. 13). Un plafond bas compte : sans lui, on cesse de lire les alertes.
L'analyse statique lit le code sans l'exécuter. Elle est limitée par principe : « vérifier statiquement un programme quelconque est un problème indécidable » (ch. 13). Indécidable : aucun outil ne tranche tous les cas. D'où un arbitrage entre alertes à tort et failles non vues, qui change selon l'étape.
Deux pièges de discipline. Les tests instables (qui passent ou échouent sans raison) : « essayez de corriger les tests instables dès qu'ils apparaissent, sinon les développeurs prennent l'habitude d'ignorer les résultats » (ch. 13). Et le test creux : dans le code neuf, remplacez le temps d'un essai une condition par if (false). Si aucun test n'échoue, aucun test ne protégeait cette condition. Dernier détail : ne copiez pas une vraie base dans les tests (droits excessifs, idée 2).
Hors livre, Go, PHP et agents. Le livre est centré C et C++. Go n'y sert que d'exemple (intercepteurs, détecteur de data races), et son seul fuzzer cité est l'outil tiers go-fuzz (ch. 13). Depuis Go 1.18, go test -fuzz fait du fuzzing natif, et go test -race détecte, à l'exécution, les accès concurrents à une même variable. En PHP, PHPStan cherche des bugs sans écrire de tests. Psalm est un outil d'analyse statique et suit les données de l'utilisateur (analyse de taint). Pour du code écrit par un agent, lancez d'abord le test if (false) : un agent peut produire des tests qui passent sans rien protéger.
7Déployer sans croire le poste du dev : revue obligatoire, build verrouillé, provenance
La question du chapitre est celle-ci : « Le code qui tourne dans votre production est-il celui que vous croyez ? » (ch. 14). Le livre traite à égalité trois adversaires : l'initié qui se trompe, l'initié malveillant et l'attaquant qui a pris un compte. La chaîne va du dépôt au build, aux tests, au déploiement. Le livre y liste onze menaces, dont un build lancé depuis une copie locale modifiée.
Le socle tient en cinq pratiques. Un build est la production d'un artefact (un binaire, une image) à partir du code. D'abord, la revue obligatoire, une forme de MPA : « Un adversaire ne sera pas découragé s'il peut simplement ne pas passer par la revue ! » (ch. 14). Ensuite, un build automatisé sur un système verrouillé (accès restreints, configuration figée). Troisième règle : « les environnements de déploiement doivent vérifier ce qui est déployé » (ch. 14), c'est-à-dire des artefacts, pas des personnes. Quatrième : la configuration se traite comme du code, relue aussi. Cinquième : les secrets restent hors du dépôt. Limite avouée : la revue ne couvre ni la collusion ni plusieurs comptes compromis.
Le niveau avancé repose sur la provenance, la fiche d'identité d'un artefact : les entrées du build, la commande lancée, le hash du résultat (son empreinte, qui change si un seul octet change). Le tout est signé par le système de build (ch. 14). Le déploiement applique alors trois vérifications. Un : la signature est valide, donc la provenance est authentique et nul ne l'a falsifiée. Deux : le hash de l'artefact reçu est celui de la fiche, donc elle s'applique à lui et pas à un artefact trafiqué. Trois : elle respecte les règles, par exemple « construit depuis tel dépôt ». Un build hermétique a ses entrées fixées d'avance. Un build reproductible redonne le même hash.
Trois architectures sont comparées. Un service de build de confiance, utilisé par Google en interne. Refaire le build soi-même au déploiement, déconseillé : « les builds prennent souvent des minutes ou des heures, alors que les décisions de déploiement doivent souvent se prendre en millisecondes » (ch. 14). Ou des rebuilders à quorum (plusieurs machines refont le build et doivent concorder), comme chez Debian. Les privilèges sont séparés : un orchestrateur (le processus de confiance qui lance le build) signe la provenance. Les commandes de l'utilisateur tournent sans la clé, sinon il pourrait signer n'importe quoi. Le contrôle se place à un point d'étranglement, là où passent toutes les demandes. Exemple : l'Admission Controller de Kubernetes (le système qui fait tourner les conteneurs), le portier qui accepte ou refuse chaque déploiement.
Google a envoyé la provenance en asynchrone dans une base, retrouvée au déploiement par le hash de l'artefact. Or un artefact pouvait être construit plusieurs fois, d'où plusieurs fiches par hash : beaucoup de builds produisant un fichier vide, des millions de fiches se sont accumulées pour son hash. Pour le vérifier, il fallait les parcourir toutes, et si aucune ne convenait, l'erreur affichée était : « Aucun de ces 497 129 enregistrements ne respecte la politique » (ch. 14). La vérification a dépassé de plusieurs ordres de grandeur le SLO de 100 ms (l'objectif de temps fixé pour ce service). Leçon : propager la provenance avec l'artefact. Un premier langage de politique, très souple, empêchait de donner des messages d'erreur exploitables, et a été remplacé par un langage très limité (ch. 14).
Le breakglass existe ici aussi, mais « pour que l'audit soit praticable, les événements de breakglass doivent être rares » (ch. 14). Chaque usage lève une alarme.
La version minimale est le point à retenir pour un petit projet. Le livre ne traite pas le développeur seul, la revue suppose une seconde personne. Il admet que le niveau avancé peut ne pas avoir de sens pour de petites organisations peu exposées à l'initié. Plancher : « au minimum, scriptez toutes les étapes » (ch. 14), via une CI. Niveau suivant : ajouter la signature, qui peut suffire pour une petite organisation avec un « service de build central » (ch. 14). Le livre conseille aussi d'exiger les approbations de revue sur GitHub, GitLab ou BitBucket. Méthode : un maillon à la fois, car une erreur dans ces contrôles peut causer une panne. Et : « vous seul pouvez décider si ces menaces valent d'être traitées pour votre organisation » (ch. 14).
Hors livre, agents de code. La chaîne vaut surtout quand quelqu'un de très rapide produit des changements. Un agent peut ouvrir une demande de fusion, jamais la valider seul, et une autre personne que l'auteur approuve. Il ne détient pas la clé de signature, qui vit dans la CI.
8Changer vite est une défense : correctifs, rebuilds fréquents, et l'embargo qui saute
On craint de déployer souvent parce que chaque changement peut casser. Le livre soutient l'inverse : il faut « pouvoir changer son infrastructure fréquemment et rapidement, tout en gardant un service très fiable » (ch. 7). Quand une faille critique tombe, la vitesse du correctif est une propriété de sécurité. Tout changement doit être incrémental, documenté et testé. Il est isolé par un feature flag (un interrupteur qui active le code neuf). Puis il est validé et déployé par étapes, à commencer par un canari (une petite part du trafic).
L'architecture qui facilite le changement a trois traits. Les dépendances restent à jour, pour appliquer un correctif critique sans rattraper d'un coup des mises à jour en retard. On reconstruit et redéploie souvent, de sorte que « vous serez prêt à déployer une nouvelle version quand il le faudra » (ch. 7). Et les conteneurs sont immuables : on corrige l'image dans le registre, jamais le conteneur vivant, et on n'autorise en production que des images récentes. Un frontend commun (le point d'entrée partagé) a ainsi protégé tous les services derrière lui : une seule règle y a limité les renégociations SSL lors d'une faille (ch. 7).
La vitesse dépend de quatre facteurs : la gravité, les dépendances (une autre équipe ou un fournisseur doit agir avant), la sensibilité de la période et l'échéance. Pas de changement non urgent en pleine période critique. Presser tout est contre-productif : « les calendriers accélérés sont perturbants et risquent plus de casser les systèmes » (ch. 7).
Un zero-day (une faille inconnue du public, sans correctif) n'est pas forcément la menace principale. Le livre note que ces failles « ne sont pas nécessairement celles que les attaquants exploitent le plus » (ch. 7). Corrigez d'abord les grands classiques des années passées. Même en urgence, le déploiement reste progressif, en heures ou en jours. S'il n'existe pas de correctif, on restreint l'accès au composant.
Deux histoires l'illustrent. Shellshock, le 24 septembre 2014 : les serveurs à faible risque ont été corrigés automatiquement, une minorité non standard à la main. Leçon : standardiser la distribution pour que patcher soit le chemin facile. Heartbleed : le bug entre dans OpenSSL en décembre 2011, devient public en avril 2014 et laisse lire 64 Ko de mémoire privée. L'embargo (le délai de silence convenu avant l'annonce publique) a sauté. L'entreprise de sécurité qui avait trouvé la faille a lancé un site et un logo, et les médias ont suivi. Leçons : prévoir l'embargo rompu, « changer régulièrement vos clés de chiffrement et autres secrets » (ch. 7), garder un canal vers les utilisateurs.
Le changement lent a sa place : par groupes d'utilisateurs, avec un mode qui prévient avant de faire appliquer la règle. Les clés FIDO ont été étudiées en 2011, déployées en 2013, et l'OTP bloqué en 2015. Il faut accepter l'adoption partielle : « atteindre 80 % ou 90 % d'adoption peut réduire sensiblement le risque » (ch. 7).
Hors livre, agents de code. Si un agent livre dix fois par jour, la fréquence est déjà là. La question devient : peut-on reculer en une commande, et les dépendances qu'il ajoute sont-elles à jour ?
9Dégrader au lieu de tomber : fail static et retries avec jitter
Face à une attaque par déni de service (DoS : saturer un service pour le rendre inutilisable), on pense à surdimensionner. Le livre rappelle : « un défenseur bien doté peut absorber les attaques en surdimensionnant toute sa pile, mais à grands frais » (ch. 10). L'attaquant vise la ressource la plus contrainte (bande passante, processeur applicatif, base de données). Plus son trafic s'enfonce dans le système, plus il est précis et coûteux à filtrer, d'où des défenses en couches.
Première réponse : la dégradation gracieuse, qui sert un service réduit plutôt que rien. Chez Google, en surcharge, Blogger passe en lecture seule sans commentaires. La recherche réduit ses fonctions. Des réponses automatiques (limiter les adresses IP les plus bruyantes, imposer un défi JavaScript ou un CAPTCHA) laissent du temps aux humains. Ne bloquez pas le trafic suspect pour toujours : on perdrait la visibilité sur l'attaque et on bloquerait du trafic légitime qui lui ressemble. N'alertez que si une action humaine est requise, c'est-à-dire quand la demande dépasse la capacité malgré les défenses automatiques (ch. 10).
Deuxième réponse : que fait le système de défense quand son propre contrôleur (le composant qui décide des règles de filtrage) tombe ? Trois choix. Fail closed : tout couper, ce qui est une panne. Fail open : tout laisser passer, ce qui livre le service à l'attaque. Le livre choisit un troisième : « nous échouons en statique, c'est-à-dire que la politique ne change pas » (ch. 10). Le contrôleur peut mourir, les règles déjà en place continuent de filtrer. Le chapitre précise que la panne du contrôleur en pleine attaque est déjà arrivée chez Google.
Troisième leçon, stratégique. Un filtre sur l'en-tête User-Agent « I AM BOTNET » aurait bloqué l'attaque, mais « nous aurions appris à notre adversaire à utiliser un User-Agent plus plausible, comme Chrome » (ch. 10). Le livre a donc interposé des CAPTCHA pour les adresses concernées.
Les attaques les plus fréquentes sont auto-infligées. En 2009, un jeu télévisé allemand a ressemblé à un botnet sur Google Search : des spectateurs jouaient chez eux, tous sur les mêmes débuts de mots. Google a répondu par l'autocomplétion. Surtout, les retries des clients. Un client qui réessaie sans pause aggrave la panne. Remède : le backoff exponentiel (l'attente double à chaque échec) plus un jitter, car « chaque client doit attendre une durée aléatoire, appelée jitter » (ch. 10). Le jitter évite que tous les clients reviennent en même temps. Pour un DNS autoritatif en panne, les retries des résolveurs multiplient la charge d'environ 30 fois. La parade est de répondre au plus de requêtes possible, un client servi cesse de réessayer.
Hors livre, agents de code. Un agent qui appelle une API en boucle est un client qui réessaie. Donnez-lui un plafond d'essais, un backoff avec jitter et un budget global. Sans cela, la panne qu'il cherche à contourner devient la sienne.
10Après l'incident : reprendre dans l'ordre, puis écrire des actions avec un propriétaire
Après une compromission, l'envie est de tout réparer vite. Le livre, en survol ici, dit de préparer la reprise avant d'agir, dès qu'on a l'état de base de l'attaque. Le périmètre vient de l'enquête : la liste des systèmes, des réseaux et des données touchés. Un système de distribution de configuration compromis met en jeu tous ceux qui en ont reçu. Attention : l'effort de reprise n'est pas proportionnel à la gravité de l'attaque.
Les pièges de la reprise se posent en questions. Les outils et l'infrastructure de reprise sont-ils eux-mêmes compromis ? Le livre propose de monter un réseau « propre », en quarantaine, et de reconstruire le serveur de configuration avant les ordinateurs portables qu'il configure. Y a-t-il des variantes de l'attaque ? Un dépassement de tampon sur un serveur pose la question des 20 autres serveurs identiques. La reprise réintroduit-elle la faille, par des golden images (images système de référence) ou des sauvegardes contenant déjà les modifications de l'attaquant ? Et surtout : « il y a un humain de l'autre côté de l'attaque, qui réagit à votre réponse à l'incident » (ch. 18).
Scénario du livre : l'attaquant a volé les clés SSL et glissé dans le code une porte dérobée qui prélève 0,02 $ par transaction (ch. 18). Appliquons-y les pièges ci-dessus (lecture de ma part). Il faut vérifier que les outils de reprise sont sains. Il faut aussi chercher la même porte sur d'autres serveurs. La golden image ou la sauvegarde ne doit pas la contenir. Les canaux de coordination peuvent même être lus par l'attaquant.
Quand éjecter l'attaquant ? La règle courante est d'attendre la compréhension complète. Mais s'il vole ou détruit déjà des données, on peut agir avant : le livre parle de « partie d'échecs ». Les mitigations rapides créent de la dette technique, par exemple une règle de routeur ajoutée à la main en contournant la revue. Il faudra ensuite refaire proprement cette règle.
Pour répartir le travail sous un commandant d'incident (la personne qui coordonne), le livre propose une checklist de reprise. Chaque ligne contient une tâche, la compétence requise, les outils et commandes précis, les étapes de nettoyage et de retour arrière. La rotation des comptes suit une priorité : administrateurs, comptes connus compromis, accès sensibles. S'y ajoutent les clés SSL et les clés d'API rangées dans le code. Et c'est l'occasion de déployer la double authentification, qui avance vite pendant une reprise.
Le post-mortem (l'analyse écrite après coup) se juge à ses suites : « chaque post-mortem doit comporter une liste d'actions qui traitent les problèmes sous-jacents trouvés pendant l'incident » (ch. 18). Chaque action a un propriétaire, et se classe en court terme (les fruits à portée de main : double authentification, délai de correctifs) ou long terme, qui demande plus de temps (une équipe sécurité, le chiffrement du réseau interne). Questions propres à la sécurité : un contrôle attendu a-t-il détecté l'attaque, et en combien de temps ? Quelles procédures normales a-t-on contournées pendant la reprise ? Le livre ne détaille pas ici le « sans blâme » et renvoie à un autre livre de Google. Autre repère : après Operation Aurora en 2009, BeyondCorp et les clés FIDO ont demandé plus de temps (ch. 18).
Hors livre, agents de code. Après un incident causé par un changement d'agent, les actions du post-mortem se traduisent en garde-fous : un test qui échoue, une règle dans le fichier de consignes de l'agent, un droit retiré.
Mon avis, honnêtement
Je l'ai ouvert avec une question de dev pressé : comment livrer sans trembler, quand une machine écrit une part du code ? Le livre ne répond pas à cette question, il ne la connaît pas. Mais il répond à celle d'avant : qui a le droit de quoi, et comment vérifier ce qui part en production. Pour ça, l'idée 7 vaut à elle seule le déplacement, et l'idée 2 vous évitera des nuits blanches.
Sa force : il avoue. Le fichier vide, le breakglass devenu habitude, la perceuse. On sort convaincu que l'erreur est normale et que le système doit la prévoir.
Deux réserves. L'échelle est celle de Google, et la version pour un dev seul tient en quelques phrases : à vous de la fabriquer, avec le plancher « scriptez tout ». Ensuite le code est surtout du C++ et du Java, Go à peine, PHP absent : les principes se transposent, les listings non.
Mon conseil : lisez d'abord le chapitre 14 (déployer), puis les chapitres 5 et 3 (droits et proxy), puis 7 et 10. Les chapitres 6, 12 et 13 se lisent en diagonale, sauf les passages sur les invariants et les types sûrs.
Odilon
Toujours valable en 2026 ?
Les principes restent valables : moindre privilège, revue obligatoire, déploiement vérifié, fail static. Le vocabulaire et les outils ont changé, et le livre ne les connaît pas.
- Chaîne d'approvisionnement. Le texte entier ne contient ni SLSA, ni SBOM (la liste des composants d'un logiciel), ni sigstore. Il parle pourtant de provenance et de build hermétique (idée 7). Hors livre : SLSA, un cadre de niveaux de garantie du build, est sorti en version 1.0 le 19 avril 2023.
- Log4j. Le mot n'apparaît pas. Hors livre : la faille Log4Shell de décembre 2021 est le cas d'école de l'idée 8, une dépendance enfouie à corriger partout, vite.
- Dépendances. Pas de Dependabot ni de Renovate. Hors livre :
govulncheckcôté Go etcomposer auditcôté PHP font le travail de repérage. - IA. Aucun LLM, aucun agent de code. La seule trace d'IA est le concours DARPA de 2015 (ch. 2), plus deux mentions de « machine learning » en passant (ch. 5 et 15). Les encadrés « Ma lecture » sont des hypothèses de mon cru.
- Go et CI. Le fuzzing natif de Go (
go test -fuzz) est absent, comme les outils de CI de GitHub et de GitLab (GitHub Actions, GitLab CI). Le livre ne cite ces plateformes que pour la revue de code (idée 7).
À qui s'adresse-t-il ?
Lisez-le si
- vous livrez un backend PHP ou Go en production et voulez savoir qui devrait avoir quels droits.
- vous avez au moins quelques années de métier et déjà une CI, mais sans vérification de ce qui part en production.
- vous faites écrire une part de votre code par un agent et voulez des garde-fous qui ne dépendent pas de sa bonne volonté.
- vous aimez qu'un livre avoue ses échecs de terrain avec des chiffres.
Passez si
- vous cherchez des recettes de code Go ou PHP à copier : les listings sont surtout en C++ et en Java.
- vous êtes seul et attendez un pas-à-pas pour un projet perso : la version minimale tient en quelques phrases.
- vous voulez les failles du moment (SBOM, SLSA, sigstore, IA) : le livre date de 2020.
Pour aller plus loin
- Le livre est gratuit en ligne : sre.google/books.
- Le Grand livre du développeur, chapitres sur la qualité (CI/CD) et la sécurité web, que cette fiche prolonge.
- Web Application Security : les failles applicatives côté attaquant (idées 5 et 6).
- Defending APIs : jetons, authentification et défense d'API (idées 2 et 3).
- Continuous Delivery : la chaîne de livraison automatisée (idée 7).
- Accelerate : pourquoi livrer souvent est lié à la stabilité (idée 8).
- The Phoenix Project : le roman du flux et de la culture DevOps (idées 8 et 10).
Fiche fondée sur : chapitres 1, 3, 5, 6, 7, 12, 13 et 14 lus en détail, 10 et 18 en survol. Des passages des chapitres 2 et 15 sont repérés par recherche. Cela fait 77 000 mots du livre sur 181 000. Le reste est trié mais non lu.
Commentaires (0)