Décaler la sécurité vers la gauche, analyse des dépendances et des images, secrets jamais commités, moindre privilège, conformité intégrée au pipeline.
Dans le modèle traditionnel, la sécurité arrive à la fin : le développement livre, une équipe spécialisée audite, et rend un rapport de quatre-vingts pages deux semaines avant la mise en production.
Le résultat est prévisible, et c'est exactement le mur du chapitre 1 sous une autre forme. Les corrections coûtent cher parce qu'elles arrivent tard. Le rapport est partiellement ignoré parce qu'il n'est pas tenable dans le délai. Et l'équipe apprend que la sécurité est un obstacle plutôt qu'une exigence.
Décaler la sécurité vers la gauche consiste à la répartir tout au long du flux qu'on a construit — dans l'éditeur, dans la demande de fusion, dans le pipeline, dans l'exécution — plutôt qu'à la concentrer en une porte finale.
Le coût de la correction
L'argument est économique avant d'être moral.
| Découverte | Coût relatif | Pourquoi |
|---|---|---|
| À l'écriture | 1 | le contexte est présent, rien n'est déployé |
| En revue | 5 | il faut réexpliquer, refaire passer le pipeline |
| En recette | 15 | l'artefact est à reconstruire, la validation à refaire |
| En production | 60 | incident, correctif d'urgence, parfois notification légale |
| Après exploitation par un tiers | 500+ | fuite de données, obligations réglementaires, réputation |
Les ordres de grandeur varient selon les études ; la forme de la courbe, elle, ne varie pas. C'est la boucle de rétroaction du chapitre 1, appliquée à la sécurité : plus la détection est proche de l'écriture, moins elle coûte.
D'où le principe d'organisation : chaque étape du pipeline porte une vérification de sécurité, aucune n'attend la fin.
Les dépendances
C'est le sujet le plus important en volume, et le plus mal traité.
Une application moderne écrit quelques milliers de lignes et en importe des centaines de milliers. Un projet Node ou Python typique dépend de plusieurs centaines de paquets, dont la plupart n'ont jamais été choisis par personne : ce sont des dépendances transitives, tirées par d'autres dépendances.
L'analyse de composition compare cet arbre à des bases de vulnérabilités publiques et signale les paquets concernés. C'est indispensable, et cela produit immédiatement un problème que le chapitre 10 a déjà nommé : le bruit.
Un projet de taille moyenne remonte couramment cent à trois cents alertes. La quasi-totalité n'est pas exploitable dans son contexte : la vulnérabilité est dans une fonction jamais appelée, dans un outil de développement absent de l'image finale, ou demande un accès que l'attaquant n'a pas. Une équipe qui reçoit trois cents alertes ne les traite pas — elle les ignore, et une alerte vraiment grave se perd dans le tas.
Le tri repose donc sur trois questions, dans cet ordre, et pas sur le score de gravité seul.
Le code vulnérable est-il atteignable ? Une faille dans une fonction que le projet n'appelle jamais n'est pas exploitable. Les outils modernes savent en partie le déterminer, et c'est le filtre le plus efficace.
Est-elle dans l'image de production ? Une vulnérabilité dans une dépendance de développement, absente de l'image finale grâce à la construction multi-étapes du chapitre 3, ne menace rien.
Est-elle accessible depuis l'extérieur ? Une faille exploitable seulement avec un accès local sur une machine déjà compromise n'a pas la même urgence qu'une exécution de code à distance sur le point d'entrée public.
Deux mesures complètent l'analyse. Le verrouillage des versions — le fichier de verrouillage committé — garantit que tout le monde installe exactement les mêmes versions, et fait de la mise à jour une décision plutôt qu'un effet de bord. Et la mise à jour régulière en petits lots : c'est encore le chapitre 1, une montée de version par semaine étant infiniment moins risquée qu'une migration de deux ans de retard un jour d'urgence.
Les images
Une image hérite des vulnérabilités de sa base. Une image construite sur une distribution complète embarque des centaines de paquets dont l'application n'utilise aucun — et chacun est de la surface d'attaque.
Trois mesures, qui sont celles du chapitre 3 vues sous un autre angle.
Réduire la surface. Une image alpine ou distroless contient un ordre de grandeur de
paquets en moins, donc un ordre de grandeur de vulnérabilités en moins — sans aucun effort de
correction.
Ne pas tourner en root. Une faille d'application donne alors les droits d'un compte restreint, et non ceux de l'administrateur du conteneur.
Analyser l'image dans le pipeline, et pas seulement les dépendances applicatives : la base vieillit toute seule, sans qu'aucune ligne de code n'ait changé.
Les secrets
Le chapitre 8 a posé la règle et sa conséquence : un secret ne va jamais dans Git, et un secret commité doit être considéré comme compromis et changé, la réécriture d'historique n'étant qu'un nettoyage tardif.
Il reste à l'empêcher d'entrer, et cela se fait en trois couches complémentaires.
Avant le commit, un crochet local refuse un ajout contenant un motif de secret. Rapide, mais contournable et dépendant de la configuration de chaque poste.
Dans le pipeline, une analyse systématique de la demande de fusion. Non contournable — c'est la couche qui compte — mais elle intervient après que le secret est parti sur le serveur, donc la rotation reste nécessaire.
Dans l'exécution, les secrets ne sont jamais dans l'image mais injectés au démarrage, et le chapitre 3 rappelait que la variable d'environnement n'est pas un mécanisme de secret. Les coffres-forts du chapitre 8 ajoutent ce qui manque : journalisation des accès, rotation, et surtout durée de vie limitée — un identifiant valable une heure a beaucoup moins de valeur pour un attaquant qu'un mot de passe permanent.
Accès et moindre privilège
Le principe de moindre privilège est le même qu'au chapitre 8 du cours de systèmes : chaque acteur ne reçoit que les droits strictement nécessaires à sa tâche.
Trois applications concrètes dans le contexte de ce cours.
Le pipeline. C'est souvent l'acteur le plus privilégié de toute l'organisation — il peut déployer en production, lire les secrets, modifier l'infrastructure. Un dépôt compromis donne alors tout. On restreint donc par branche et par environnement, et l'on préfère des identifiants éphémères obtenus à l'exécution à des jetons permanents stockés dans l'outil.
Les comptes de service. Un service qui lit une base n'a pas besoin des droits d'écriture, ni de la table des utilisateurs. Le compte par défaut, souvent tout-puissant, est le raccourci à éviter.
Les accès humains. Nominatifs, révocables, et journalisés — c'est la traçabilité du chapitre 1 du cours de cybersécurité, sans laquelle aucun incident n'est analysable.
Conformité intégrée
Dernière idée du chapitre, et elle est cohérente avec tout le reste : une exigence de sécurité écrite dans un document est une intention ; écrite dans le pipeline, c'est une garantie.
Une politique comme code exprime des règles vérifiables automatiquement : aucun conteneur en root, aucun port de base exposé publiquement, chiffrement obligatoire sur les volumes, image provenant d'un registre approuvé. Le plan Terraform du chapitre 7 ou le manifeste Kubernetes du chapitre 9 sont validés contre ces règles avant application.
L'audit devient alors un sous-produit : plutôt que de reconstituer six mois après qui a déployé quoi, on dispose de l'historique Git, des exécutions de pipeline et des journaux d'accès. C'est la même bascule que dans tout le semestre — d'un contrôle ponctuel et manuel vers une propriété continue et automatique.
Un analyseur remonte 280 vulnérabilités sur un projet. Comment traiter cela ?
Pourquoi le pipeline d'intégration continue est-il une cible privilégiée ?
À vous
L'exercice fait le tri que le chapitre décrit, et il montre ce que le tri change.
Vous disposez d'un arbre de dépendances, de vulnérabilités avec leur score, et de trois informations de contexte : la fonction vulnérable est-elle appelée, la dépendance est-elle dans l'image de production, la faille est-elle exploitable à distance. Vous écrirez le tri et comparerez le classement par gravité seule au classement par exploitabilité — les deux premières places ne sont pas les mêmes.
La seconde partie compare deux images de base sur le nombre de paquets et de vulnérabilités héritées, ce qui chiffre l'argument du chapitre 3.
La troisième audite des permissions : un compte de service, ses droits accordés et ses droits réellement utilisés sur un mois de journaux. Vous calculerez l'écart, qui est exactement ce que le moindre privilège demande de supprimer.
Triez des vulnérabilités par exploitabilité, chiffrez l'image minimale, puis auditez des permissions.
// ── 1. Des vulnérabilités, et leur contexte ─────────────────────────────── const VULNERABILITES = [ { id: "CVE-2025-1001", paquet: "lodash", gravite: 9.8, atteignable: false, enProduction: true, distance: true, note: "prototype pollution dans une fonction que le projet n'appelle pas" }, { id: "CVE-2025-1002", paquet: "express", gravite: 6.5, atteignable: true, enProduction: true, distance: true, note: "sur le point d'entrée public" }, { id: "CVE-2025-1003", paquet: "webpack", gravite: 8.1, atteignable: true, enProduction: false, distance: false, note: "outil de construction, absent de l'image finale" }, { id: "CVE-2025-1004", paquet: "postgres", gravite: 7.5, atteignable: true, enProduction: true, distance: false, note: "exploitable avec un accès local sur la machine" }, { id: "CVE-2025-1005", paquet: "jsonwebtoken", gravite: 7.2, atteignable: true, enProduction: true, distance: true, note: "vérification de signature contournable" }, { id: "CVE-2025-1006", paquet: "chalk", gravite: 5.3, atteignable: false, enProduction: false, distance: false, note: "coloration de sortie, développement seulement" }, ]; function score(v) { // ← à écrire : pondérer la gravité par l'exploitabilité RÉELLE. // Non atteignable, hors production, ou non exploitable à distance // doivent faire chuter la priorité. return v.gravite; } // ── 2. Deux images de base ──────────────────────────────────────────────── const IMAGES = { "node:20": { paquets: 412, vulnHautes: 17, vulnMoyennes: 63, mo: 1100 }, "node:20-alpine": { paquets: 47, vulnHautes: 1, vulnMoyennes: 4, mo: 130 }, "distroless/nodejs": { paquets: 12, vulnHautes: 0, vulnMoyennes: 1, mo: 110 }, }; // ── 3. Audit de permissions ─────────────────────────────────────────────── const COMPTE = { nom: "service-commandes", accordes: ["db:read", "db:write", "db:drop", "s3:read", "s3:write", "secrets:read", "users:read", "users:write", "deploy:prod"], }; const JOURNAL_UN_MOIS = [ "db:read", "db:read", "db:write", "db:read", "s3:read", "db:write", "db:read", "s3:read", "db:read", "db:write", ]; // ── À VOUS ──────────────────────────────────────────────────────────────── // 1. Écrivez score(). Comparez le classement par GRAVITÉ et par // EXPLOITABILITÉ : les deux premières places sont-elles les mêmes ? // 2. Chiffrez ce que l'image minimale supprime — sans aucune correction. // 3. Calculez l'écart entre droits accordés et droits utilisés. for (const v of VULNERABILITES) console.log(" " + v.id + " " + v.gravite);
En travaux pratiques
Ajouter la sécurité au pipeline, sans le rendre inutilisable
Brancher trois vérifications sur le pipeline du TP 5, puis trier leurs résultats pour qu'ils restent exploitables.
- Le pipeline du TP 5, qui construit et publie une image
- Les outils trivy et gitleaks, ou leurs équivalents
- 1. Analyser les dépendances
Lancez une analyse de composition sur le projet et comptez les vulnérabilités remontées. Notez le nombre : c'est lui qui pose le problème du chapitre.
- 2. Trier par exploitabilité
Pour les dix plus graves, répondez aux trois questions : le code vulnérable est-il atteignable, est-il dans l'image de production, est-il exploitable à distance ? Comparez le classement obtenu à celui par gravité.
- 3. Analyser l'image
Analysez l'image du TP 3, puis la même application construite sur une base complète. Comparez le nombre de vulnérabilités héritées.
- 4. Empêcher les secrets d'entrer
Ajoutez un crochet local et une étape de pipeline qui refusent une modification contenant un secret. Testez avec une fausse clé, puis avec une référence à une variable d'environnement — la seconde ne doit PAS déclencher d'alerte.
- 5. Mesurer les faux positifs
Passez le détecteur sur tout l'historique du dépôt. Comptez les alertes et la part réellement problématique. Que se passerait-il si vous laissiez ce niveau de bruit ?
- 6. Auditer les droits du pipeline
Listez ce que votre pipeline a le droit de faire. Retirez tout ce dont il n'a pas besoin sur une demande de fusion — notamment le droit de déployer en production.
- 7. Écrire une règle de conformité
Ajoutez une vérification automatique qui refuse tout manifeste déclarant un conteneur tournant en root. Testez-la sur un manifeste fautif.
- Le pipeline échoue sur une fausse clé et passe sur une référence à une variable
- Vous savez nommer les trois ou quatre vulnérabilités qui méritent une action cette semaine
- Une demande de fusion ne peut plus déployer en production
- Un manifeste sans utilisateur non privilégié est refusé
Ce que ce semestre laisse
Onze chapitres plus tôt, le problème était une contradiction d'organisation : livrer vite d'un côté, ne rien casser de l'autre.
Le trajet a suivi celui d'une modification de code. Elle est écrite dans un dépôt dont la stratégie de branchement décide de la taille des lots. Elle est empaquetée avec tout ce dont elle a besoin, ce qui rend « ça marche sur ma machine » sans objet. Elle est vérifiée par un pipeline qui échoue vite, puis livrée par une stratégie qui limite le rayon d'impact. Elle atterrit sur une infrastructure décrite dans des fichiers plutôt que construite à la main, qu'un orchestrateur maintient dans l'état déclaré. Et elle est observée, mesurée, défendue.
Ce qu'il faut en garder tient peut-être en trois idées.
Les petits lots gouvernent tout. Fréquence de livraison, taille des branches, granularité des demandes de fusion, mises à jour de dépendances : le même raisonnement revient à chaque chapitre, et il explique à lui seul pourquoi vitesse et stabilité vont ensemble.
On ne cherche pas à empêcher les incidents, mais à en réduire l'ampleur et la durée. Le canari, le retour arrière, l'auto-réparation et le budget d'erreur disent tous la même chose : la panne aura lieu, et ce qui se mesure est ce qu'elle coûte.
Le bruit détruit le signal. Un test instable, une alerte non actionnable, trois cents vulnérabilités non triées produisent tous le même effet — une équipe qui apprend à ignorer, et qui rate ce qui compte. Ce n'est pas une question d'outil mais d'exigence sur ce qu'on accepte d'afficher en rouge.
À retenir
Vous avez parcouru les 10 sections.
Marquez-la terminée pour faire avancer votre parcours, ou revenez sur un point avant de passer à la suite.