En 2020, l’attaque SolarWinds a compromis 18 000 organisations en injectant du code malveillant dans le processus de build d’un logiciel légitime. Les attaquants n’ont pas exploité une vulnérabilité applicative — ils ont compromis le pipeline lui-même. Cette attaque a redéfini notre compréhension des risques : le pipeline CI/CD n’est plus un outil de développement, c’est une surface d’attaque critique.
Un pipeline non sécurisé est une porte ouverte. Il a accès aux secrets de production, peut déployer du code en production, et s’exécute souvent avec des privilèges élevés. C’est exactement ce que recherchent les attaquants.
Anatomie d’un pipeline sécurisé
Section intitulée « Anatomie d’un pipeline sécurisé »Un pipeline CI/CD sécurisé repose sur quatre piliers fondamentaux qui forment une défense en profondeur :
| Pilier | Objectif | Menace adressée |
|---|---|---|
| Security gates | Bloquer le code vulnérable avant déploiement | Code malveillant, vulnérabilités connues |
| Gestion des secrets | Protéger les credentials et tokens | Fuite de secrets, accès non autorisé |
| Signature d’artefacts | Garantir l’intégrité et la provenance | Tampering, supply chain attack |
| Isolation | Limiter l’impact d’une compromission | Mouvement latéral, élévation de privilèges |
Ces piliers ne sont pas indépendants : ils se renforcent mutuellement. Un secret bien protégé n’a de valeur que si le pipeline qui l’utilise est isolé. Une signature n’a de sens que si les security gates ont validé le code signé.
Security gates : les points de contrôle
Section intitulée « Security gates : les points de contrôle »Les security gates sont des points de décision dans le pipeline. Si les critères ne sont pas remplis, le pipeline s’arrête. C’est le principe du “fail fast” appliqué à la sécurité.
Architecture des gates
Section intitulée « Architecture des gates »Un pipeline efficace place des gates à chaque transition :
| Gate | Position | Ce qu’il vérifie | Action si échec |
|---|---|---|---|
| Pre-commit | Avant le commit | Secrets, formatage | Bloque le commit |
| PR Gate | À l’ouverture de PR | SAST, SCA, tests | Bloque le merge |
| Build Gate | Après compilation | Scan d’image, signature | Bloque la publication |
| Deploy Gate | Avant déploiement | Approbation, checks finaux | Bloque le déploiement |
Stratégie de seuils
Section intitulée « Stratégie de seuils »Tous les problèmes ne méritent pas de bloquer le pipeline. Une stratégie efficace distingue plusieurs niveaux :
# Exemple de stratégie de seuilssecurity_gates: pre-commit: block_on: [secrets] # Seuls les secrets bloquent warn_on: [high_cvss]
pr_gate: block_on: [critical_cvss, secrets, high_cvss_with_exploit] warn_on: [high_cvss, medium_cvss]
deploy_gate: block_on: [any_critical, missing_signature] require_approval_for: [high_cvss]Implémentation GitHub Actions
Section intitulée « Implémentation GitHub Actions »name: Security Gates
on: pull_request: branches: [main]
jobs: # Gate 1 : Secrets secrets-scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # Historique complet pour scanner les commits
- name: Detect secrets uses: gitleaks/gitleaks-action@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Gate 2 : SAST sast: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: SAST scan uses: returntocorp/semgrep-action@v1 with: config: >- p/security-audit p/owasp-top-ten
# Gate 3 : SCA sca: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Dependency scan run: | trivy fs --severity CRITICAL --exit-code 1 .
# Gate final : tous les checks doivent passer security-gate: needs: [secrets-scan, sast, sca] runs-on: ubuntu-latest steps: - run: echo "All security gates passed"Gestion des secrets
Section intitulée « Gestion des secrets »Les secrets (API keys, tokens, passwords, certificats) sont le nerf de la guerre. Un secret exposé dans un pipeline compromet potentiellement toute l’infrastructure.
Les erreurs classiques
Section intitulée « Les erreurs classiques »| Erreur | Risque | Fréquence |
|---|---|---|
| Secret en variable d’environnement non masquée | Visible dans les logs | Très courante |
| Secret hardcodé dans le code | Exposé dans l’historique Git | Courante |
| Secret partagé entre environnements | Compromission transversale | Courante |
| Secret sans rotation | Exploitation prolongée après fuite | Très courante |
| Secret avec privilèges excessifs | Impact amplifié | Courante |
Principes de gestion sécurisée
Section intitulée « Principes de gestion sécurisée »-
Jamais de secrets dans le code
Utilisez toujours un gestionnaire de secrets externe. Le code ne doit contenir que des références.
# ❌ JAMAISenv:DATABASE_PASSWORD: "SuperSecret123!"# ✅ TOUJOURSenv:DATABASE_PASSWORD: ${{ secrets.DATABASE_PASSWORD }} -
Chaque secret ne doit avoir que les permissions strictement nécessaires.
# Token GitHub avec permissions minimalespermissions:contents: readpackages: write # Uniquement si nécessaire -
Isolation par environnement
Des secrets différents pour dev, staging et production. Jamais de secret prod en dev.
jobs:deploy:environment: production # Environnement GitHub avec ses propres secretssteps:- name: Deployenv:API_KEY: ${{ secrets.PROD_API_KEY }} # Secret spécifique à prod -
Rotation automatique
Les secrets doivent être renouvelés régulièrement. Idéalement, automatiquement.
Type de secret Fréquence de rotation API keys 90 jours Tokens d’accès 24h (préférer les tokens éphémères) Certificats Avant expiration, automatisé Passwords de service 180 jours -
Audit et monitoring
Chaque accès à un secret doit être loggé et auditable.
Solutions de gestion de secrets
Section intitulée « Solutions de gestion de secrets »Plusieurs approches existent, du simple au sophistiqué :
| Solution | Cas d’usage | Complexité |
|---|---|---|
| GitHub Secrets | Projets simples, GitHub-centric | Faible |
| SOPS | Secrets versionnés avec le code (chiffrés) | Moyenne |
| HashiCorp Vault | Enterprise, multi-cloud, rotation automatique | Élevée |
| Infisical | Alternative open source à Vault | Moyenne |
Signature d’artefacts
Section intitulée « Signature d’artefacts »La signature cryptographique garantit deux propriétés essentielles pour la sécurité de la supply chain :
- Intégrité : L’artefact n’a pas été modifié depuis sa création
- Provenance : L’artefact provient bien du pipeline autorisé
Sans signature, rien ne prouve qu’une image Docker en production est bien celle construite par votre CI. Un attaquant pourrait la remplacer.
Le problème de la confiance
Section intitulée « Le problème de la confiance »Dans une architecture moderne, les artefacts traversent de nombreuses étapes :
Code → Build → Registry → Deploy → ProductionÀ chaque transition, un attaquant pourrait intercepter et modifier l’artefact. La signature crée une chaîne de confiance vérifiable à chaque étape.
Sigstore : l’écosystème de signature moderne
Section intitulée « Sigstore : l’écosystème de signature moderne »Sigstore est devenu le standard de facto pour la signature d’artefacts dans l’écosystème cloud-native. Il résout les problèmes historiques de la signature (gestion des clés) avec une approche “keyless”.
| Composant | Rôle | Analogie |
|---|---|---|
| Cosign | Signer et vérifier les images/artefacts | Le stylo qui signe |
| Fulcio | CA qui émet des certificats éphémères | Le notaire qui certifie l’identité |
| Rekor | Log de transparence (audit trail) | Le registre public des signatures |
Workflow de signature
Section intitulée « Workflow de signature »-
Build : créer l’artefact
Fenêtre de terminal docker build -t myapp:v1.0.0 . -
Push : publier dans le registry
Fenêtre de terminal docker push registry.example.com/myapp:v1.0.0 -
Sign : signer avec Cosign
Fenêtre de terminal # Signature keyless (recommandé)cosign sign registry.example.com/myapp:v1.0.0# Cosign utilise l'identité OIDC (GitHub Actions, GitLab CI)# Pas de clé privée à gérer ! -
Verify : vérifier avant déploiement
Fenêtre de terminal cosign verify \--certificate-identity "https://github.com/myorg/myrepo/.github/workflows/build.yml@refs/heads/main" \--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \registry.example.com/myapp:v1.0.0
Intégration GitHub Actions
Section intitulée « Intégration GitHub Actions »name: Build and Sign
on: push: branches: [main]
jobs: build: runs-on: ubuntu-latest permissions: contents: read packages: write id-token: write # Nécessaire pour la signature keyless
steps: - uses: actions/checkout@v4
- name: Build image run: | docker build -t ghcr.io/${{ github.repository }}:${{ github.sha }} .
- name: Login to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Push image run: | docker push ghcr.io/${{ github.repository }}:${{ github.sha }}
- name: Install Cosign uses: sigstore/cosign-installer@v3
- name: Sign image run: | cosign sign --yes ghcr.io/${{ github.repository }}:${{ github.sha }}Isolation et moindre privilège
Section intitulée « Isolation et moindre privilège »Un pipeline compromis ne devrait pas pouvoir compromettre toute l’infrastructure. L’isolation limite le “blast radius” d’une attaque.
Principes d’isolation
Section intitulée « Principes d’isolation »| Niveau | Mesure | Bénéfice |
|---|---|---|
| Réseau | Runners dans un réseau isolé | Pas d’accès aux ressources internes |
| Compute | Runners éphémères (destroyed après usage) | Pas de persistance d’un compromis |
| Permissions | Token avec moindre privilège | Limite les actions possibles |
| Environnements | Séparation dev/staging/prod | Compromis dev ≠ compromis prod |
Runners éphémères
Section intitulée « Runners éphémères »Les runners self-hosted permanents sont un risque : un attaquant qui compromet un job peut persister sur le runner et compromettre les jobs suivants.
Préférez les runners éphémères :
jobs: build: runs-on: ubuntu-latest # Runner GitHub hébergé, détruit après le job
# Ou pour self-hosted sensitive-deploy: runs-on: [self-hosted, ephemeral] # Label pour runners éphémèresPermissions GitHub Actions
Section intitulée « Permissions GitHub Actions »Réduisez les permissions au strict minimum :
# Permissions par défaut restrictivespermissions: contents: read # Lecture du code seulement
jobs: build: # Permissions spécifiques au job si nécessaire permissions: contents: read packages: write # Uniquement pour ce jobAttestations et provenance
Section intitulée « Attestations et provenance »Au-delà de la signature, les attestations ajoutent des métadonnées vérifiables sur comment, où et par qui un artefact a été construit.
SLSA : le framework de référence
Section intitulée « SLSA : le framework de référence »SLSA (Supply-chain Levels for Software Artifacts) définit des niveaux de maturité pour la sécurité de la supply chain :
| Niveau | Exigences | Ce que ça prouve |
|---|---|---|
| SLSA 1 | Provenance documentée | Qui a construit, quand |
| SLSA 2 | Provenance générée par le service de build | Build reproductible |
| SLSA 3 | Build isolé, provenance non falsifiable | Intégrité garantie |
| SLSA 4 | Hermétique, reproductible | Vérifiable par tous |
Génération d’attestations
Section intitulée « Génération d’attestations »- name: Generate SLSA provenance uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1 with: image: ghcr.io/${{ github.repository }} digest: ${{ steps.build.outputs.digest }}Checklist pipeline sécurisé
Section intitulée « Checklist pipeline sécurisé »Une checklist pour évaluer la maturité de votre pipeline :
Basique (à avoir immédiatement)
Section intitulée « Basique (à avoir immédiatement) »- Secrets dans un gestionnaire (pas dans le code)
- Scan de secrets en pre-commit
- SAST sur les PR
- SCA sur les dépendances
Intermédiaire (à planifier)
Section intitulée « Intermédiaire (à planifier) »- Runners éphémères
- Permissions minimales
- Environnements séparés (dev/staging/prod)
- Signature des images
Avancé (maturité DevSecOps)
Section intitulée « Avancé (maturité DevSecOps) »- Attestations SLSA
- SBOM pour tous les artefacts
- Vérification des signatures avant déploiement
- Rotation automatique des secrets
À retenir
Section intitulée « À retenir »- Security gates : Points de contrôle automatiques, fail fast
- Secrets : Jamais dans le code, rotation régulière, moindre privilège
- Signature : Cosign/Sigstore pour l’intégrité et la provenance
- Isolation : Runners éphémères, permissions minimales
- Attestations : SLSA pour prouver comment l’artefact a été construit