Patterns Défensifs et Atténuations pour les Attaques de Pipelines CI/CD

Introduction

Comprendre comment les pipelines CI/CD sont attaqués ne représente que la moitié du tableau. La modélisation des menaces et la taxonomie des attaques nous fournissent une carte du champ de bataille, mais sans patterns défensifs concrets et atténuations techniques, ces connaissances restent théoriques. Ce guide comble le fossé entre la sensibilisation et l’action.

L’objectif n’est pas de construire une forteresse imprenable — cela n’existe pas. Au lieu de cela, nous nous concentrons sur la réduction de la surface d’attaque, la limitation du rayon d’impact lorsque quelque chose tourne mal, et la résilience des pipelines pour une reprise rapide. Chaque contrôle décrit ici correspond à des patterns d’attaques réels : pipelines empoisonnés, vol d’identifiants, détournement de dépendances et falsification d’artefacts.

Nous parcourrons les défenses couche par couche — du code source jusqu’à l’exécution — puis nous couvrirons les capacités de détection et de réponse aux incidents qui bouclent la boucle. Que vous sécurisiez GitHub Actions, GitLab CI, Jenkins ou toute autre plateforme CI/CD, les principes restent les mêmes.

Défense en profondeur pour le CI/CD

Aucun contrôle de sécurité unique n’est suffisant pour protéger un pipeline CI/CD. Les attaquants sont créatifs et trouveront la faille dans toute défense à couche unique. La seule stratégie viable est la défense en profondeur : des contrôles superposés à chaque étape du cycle de livraison logicielle.

Correspondance des défenses avec le Top 10 OWASP des risques de sécurité CI/CD

Le Top 10 OWASP des risques de sécurité CI/CD fournit un cadre structuré pour comprendre ce qui peut mal tourner. Chaque risque — de CICD-SEC-1 (Mécanismes de contrôle de flux insuffisants) à CICD-SEC-10 (Journalisation et visibilité insuffisantes) — exige des atténuations spécifiques. Les défenses de ce guide sont organisées pour traiter ces risques de manière systématique.

Les trois piliers : Prévention, Détection, Réponse

  • Prévention : Les contrôles qui arrêtent les attaques avant qu’elles ne réussissent — protections de branches, permissions minimales, artefacts signés, runners éphémères.
  • Détection : La surveillance et les alertes qui révèlent les anomalies — comportement inattendu du pipeline, dérive de configuration, nouvelles dépendances, exposition de secrets.
  • Réponse : Les playbooks et procédures pour quand les défenses échouent — révocation d’identifiants, analyse du rayon d’impact, vérification de l’intégrité des artefacts, investigation forensique.

Défense à chaque couche

Considérez le pipeline CI/CD comme une chaîne de frontières de confiance :

  • Source : Là où le code et la configuration entrent dans le pipeline
  • Build : Là où le code est compilé, testé et empaqueté
  • Artefact : Là où les résultats de build sont stockés et distribués
  • Déploiement : Là où les artefacts atteignent l’infrastructure de production
  • Exécution : Là où le logiciel déployé s’exécute et est surveillé

Chaque couche a des menaces distinctes et nécessite des défenses distinctes. La compromission d’une couche ne devrait pas automatiquement se propager à la suivante.

Défenses de la couche Source — Protection des entrées du pipeline

La couche source est là où la plupart des attaques CI/CD commencent. Un attaquant capable de modifier le code, les définitions de pipeline ou les fichiers de configuration contrôle ce que le pipeline exécute. Les défenses de la couche source garantissent que seules les modifications autorisées, révisées et vérifiées entrent dans le pipeline.

Règles de protection des branches

La protection des branches est la première ligne de défense. Au minimum, les branches main et release doivent imposer :

  • Revues de pull request obligatoires : Pas de push direct sur les branches protégées. Toutes les modifications passent par une revue de code.
  • Vérifications de statut requises : Le CI doit passer avant la fusion. Cela empêche la fusion de code cassé ou malveillant qui contourne les tests.
  • Pas de force push : Le force push réécrit l’historique et peut être utilisé pour supprimer les preuves de commits malveillants.
  • Historique linéaire requis : Empêche les merge commits qui peuvent masquer des modifications malveillantes dans des diffs complexes.

CODEOWNERS pour les chemins sensibles

Tous les fichiers d’un dépôt ne comportent pas le même risque. Les définitions de pipeline, les templates d’infrastructure as code et les configurations de conteneurs sont des cibles à haute valeur. Utilisez CODEOWNERS pour exiger la revue par des équipes spécifiques pour les chemins sensibles :

# .github/CODEOWNERS

# Les définitions de pipeline nécessitent la revue de l'équipe sécurité
.github/workflows/    @org/security-team
.gitlab-ci.yml        @org/security-team
Jenkinsfile           @org/security-team

# Infrastructure as code
terraform/            @org/platform-team @org/security-team
pulumi/               @org/platform-team @org/security-team

# Définitions de conteneurs
Dockerfile*           @org/security-team
docker-compose*.yml   @org/security-team

# Manifestes de dépendances
package.json          @org/security-team
requirements.txt      @org/security-team
go.sum                @org/security-team

Commits signés et vérification

La signature des commits fournit une preuve cryptographique de paternité. Sans cela, un attaquant qui compromet le jeton d’accès d’un développeur peut pousser des commits qui semblent provenir de n’importe qui. Activez la vérification de signature des commits sur les branches protégées pour vous assurer que chaque commit est signé avec une clé GPG ou SSH vérifiée.

# Configurer Git pour signer les commits avec une clé SSH
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true

# Vérifier la signature d'un commit
git verify-commit HEAD

Politiques de revue des PR

La revue de code est un contrôle humain, et elle a besoin de garde-fous :

  • Pas d’auto-approbation : L’auteur d’une PR ne devrait jamais pouvoir approuver ses propres modifications.
  • Réviseurs requis de l’équipe sécurité pour les modifications des fichiers de pipeline, de la configuration des secrets ou des manifestes de déploiement.
  • Invalider les revues obsolètes : Si de nouveaux commits sont poussés après approbation, les approbations précédentes doivent être invalidées pour forcer une nouvelle revue.
  • Exiger la revue des propriétaires de code : Combinez cela avec CODEOWNERS pour imposer des exigences de revue spécifiques au domaine.

Limitation des déclencheurs de pipeline

Chaque événement ne devrait pas déclencher une exécution complète du pipeline, surtout une qui a accès aux secrets :

  • Restrictions de fork : Les PR provenant de forks doivent s’exécuter dans un contexte restreint sans accès aux secrets du dépôt.
  • Permissions des contributeurs : Seuls les collaborateurs avec accès en écriture devraient pouvoir déclencher des workflows accédant à des ressources sensibles.
  • Approbation pour les nouveaux contributeurs : Exiger une approbation manuelle avant d’exécuter les pipelines pour les nouveaux contributeurs.

Défenses de la couche Build — Sécuriser le processus de build

La couche build est là où le code devient exécutable. Une compromission ici signifie qu’un attaquant peut injecter une logique malveillante dans vos artefacts sans modifier le code source. Les défenses de la couche build se concentrent sur l’isolation, l’éphémérité et le moindre privilège.

Runners éphémères

Les runners CI persistants accumulent un état : identifiants mis en cache, fichiers résiduels des builds précédents, variables d’environnement qui fuient entre les jobs. Les runners éphémères éliminent entièrement cette classe de risque en provisionnant une VM ou un conteneur neuf pour chaque job et en le détruisant immédiatement après.

# GitHub Actions : Runner éphémère auto-hébergé avec actions-runner-controller
apiVersion: actions.summerwind.dev/v1alpha1
kind: RunnerDeployment
metadata:
  name: ephemeral-runners
spec:
  replicas: 5
  template:
    spec:
      ephemeral: true
      repository: your-org/your-repo
      labels:
        - self-hosted
        - ephemeral
        - linux
      dockerdWithinRunnerContainer: false
      image: ghcr.io/actions/actions-runner:latest
      resources:
        limits:
          cpu: "2"
          memory: "4Gi"

Environnements de build isolés

Même avec des runners éphémères, les builds qui partagent des caches ou des espaces de noms réseau peuvent faire fuiter des informations entre les jobs. Assurez-vous :

  • Pas de caches partagés entre les builds non fiables : L’empoisonnement de cache est un vecteur d’attaque réel. Isolez les caches par branche ou par PR.
  • Pools de runners séparés : Les runners de déploiement en production ne devraient jamais être partagés avec les runners de validation de PR.
  • Isolation par conteneur : Utilisez des conteneurs rootless ou des microVMs (Firecracker, gVisor) pour une isolation plus forte que le Docker standard.

Restrictions réseau pendant les builds

Une étape de build compromise avec un accès réseau non restreint peut exfiltrer des secrets vers une infrastructure contrôlée par l’attaquant. Restreignez l’accès réseau sortant :

  • Pas d’accès internet sortant : L’option la plus stricte. Toutes les dépendances doivent provenir de miroirs internes ou d’images pré-mises en cache.
  • Domaines autorisés uniquement : Si l’accès internet est nécessaire, restreignez-le aux registres et dépôts de paquets connus et fiables.
  • Filtrage basé sur le DNS : Utilisez des politiques DNS pour bloquer l’accès aux domaines non autorisés pendant les builds.
# Kubernetes NetworkPolicy pour les pods de runners CI
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: ci-runner-egress-restricted
  namespace: ci-runners
spec:
  podSelector:
    matchLabels:
      role: ci-runner
  policyTypes:
    - Egress
  egress:
    - to:
        - ipBlock:
            cidr: 10.0.0.0/8    # Réseau interne uniquement
      ports:
        - protocol: TCP
          port: 443              # HTTPS vers les registres internes
        - protocol: TCP
          port: 53               # DNS
        - protocol: UDP
          port: 53               # DNS

Images de build minimales

Chaque outil installé dans une image de build est une surface d’attaque potentielle. Réduisez les images de build au strict minimum :

  • Utilisez des images distroless ou basées sur Alpine comme bases de build.
  • Supprimez les shells, les gestionnaires de paquets et les utilitaires réseau des images de build de production lorsque c’est possible.
  • Épinglez les digests d’images, pas les tags, pour prévenir les attaques de supply chain basées sur les tags.
# Épingler par digest, pas par tag
FROM golang:1.22@sha256:a3b21c5d8e... AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o /app/binary

# Utiliser distroless pour l'image finale
FROM gcr.io/distroless/static-debian12@sha256:f4e8b1c2d9...
COPY --from=builder /app/binary /binary
ENTRYPOINT ["/binary"]

Désactiver les modes debug dans les pipelines de production

La journalisation de debug et la sortie verbeuse sont inestimables pendant le développement mais dangereuses dans les pipelines de production. Elles peuvent faire fuiter des secrets, des chemins internes et des détails d’infrastructure. Assurez-vous que ACTIONS_STEP_DEBUG, CI_DEBUG_TRACE et les flags équivalents sont désactivés dans les configurations de pipeline de production.

Défenses des identifiants et de l’identité — Limiter ce que les pipelines peuvent accéder

Les identifiants sont la cible la plus précieuse dans tout pipeline CI/CD. Un attaquant qui obtient une clé d’accès cloud, un token de déploiement ou un secret d’API peut pivoter bien au-delà du pipeline lui-même. Les défenses des identifiants se concentrent sur la minimisation de ce qui existe, de ce qui peut être accédé et de la durée d’accès.

Permissions minimales des tokens

Le GITHUB_TOKEN par défaut dans GitHub Actions a des permissions larges. Restreignez-le toujours au minimum requis :

# GitHub Actions : Restreindre les permissions du token par défaut
permissions:
  contents: read
  packages: read
  id-token: write   # Uniquement si vous utilisez OIDC

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4
      - run: make build

  deploy:
    runs-on: ubuntu-latest
    needs: build
    permissions:
      contents: read
      id-token: write   # Pour l'authentification OIDC
    steps:
      - name: S'authentifier auprès du cloud
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/deploy-role
          aws-region: us-east-1

OIDC et Workload Identity

Les secrets à longue durée de vie stockés dans les systèmes CI/CD sont des bombes à retardement. Remplacez-les par la fédération d’identité de charge de travail basée sur OIDC partout où c’est possible :

  • GitHub Actions vers AWS : Utilisez aws-actions/configure-aws-credentials avec l’assumption de rôle OIDC.
  • GitHub Actions vers GCP : Utilisez google-github-actions/auth avec Workload Identity Federation.
  • GitHub Actions vers Azure : Utilisez azure/login avec les identifiants fédérés.
  • GitLab CI vers AWS/GCP/Azure : Utilisez le token OIDC natif de GitLab (CI_JOB_JWT_V2) avec la fédération du fournisseur cloud.

Avec OIDC, la plateforme CI/CD émet un JWT à courte durée de vie, et le fournisseur cloud l’échange contre des identifiants temporaires. Aucun secret statique n’est stocké nulle part.

Identifiants par environnement, par étape

Un seul jeu d’identifiants partagé entre tous les environnements représente un rayon d’impact catastrophique. Segmentez les identifiants :

  • Le développement, le staging et la production doivent utiliser des comptes de service séparés avec des permissions séparées.
  • Les étapes de build ne doivent pas avoir accès aux identifiants de déploiement.
  • Les étapes de test doivent utiliser une infrastructure de test isolée, pas des environnements partagés.

Pas de secrets dans les workflows PR/Fork

Les pull requests provenant de forks ne devraient jamais avoir accès aux secrets du dépôt. C’est une mauvaise configuration courante qui permet aux attaquants d’exfiltrer des secrets en soumettant une PR malveillante. Dans GitHub Actions, utilisez pull_request (pas pull_request_target) pour le code non fiable, et ne passez jamais de secrets aux étapes qui exécutent du code de PR.

Intégration Vault avec secrets dynamiques

Pour les identifiants qui ne peuvent pas utiliser OIDC (mots de passe de base de données, clés API pour des services tiers), utilisez un gestionnaire de secrets comme HashiCorp Vault avec des secrets dynamiques à courte durée de vie :

# HashiCorp Vault : Générer des identifiants de base de données à courte durée de vie
vault read database/creds/ci-readonly
# Retourne :
# Key                Value
# ---                -----
# lease_id           database/creds/ci-readonly/abc123
# lease_duration     1h
# username           v-ci-readonly-xyz789
# password           A1B2-C3D4-E5F6-G7H8

Les secrets dynamiques sont générés à la demande, limités à l’identité demandeuse et automatiquement révoqués à leur expiration. Même en cas de fuite, la fenêtre d’exposition se mesure en minutes, pas en mois.

Journalisation d’audit de tous les accès aux secrets

Chaque récupération de secret devrait générer une entrée de journal d’audit. Si votre gestionnaire de secrets ne journalise pas les accès, vous n’avez aucun moyen d’investiguer une compromission. Assurez-vous que les journaux capturent : qui a accédé à quoi, quand, depuis quelle exécution de pipeline et depuis quelle adresse IP.

Défenses de la couche Artefact — Assurer l’intégrité des résultats

Les artefacts de build — images de conteneurs, binaires, paquets — sont le pont entre votre pipeline et la production. Si un attaquant peut falsifier les artefacts après leur construction, toutes les défenses en amont deviennent sans objet. Les défenses de la couche artefact garantissent l’intégrité, la provenance et l’immuabilité.

Signer tous les artefacts avec Sigstore/Cosign

La signature d’artefacts fournit une preuve cryptographique qu’un artefact a été produit par votre pipeline et n’a pas été modifié depuis. Cosign de Sigstore rend la signature sans clé pratique :

# Signer une image de conteneur avec Cosign (sans clé, basé sur OIDC)
cosign sign --yes ghcr.io/your-org/your-app:v1.2.3@sha256:abc123...

# Vérifier la signature
cosign verify \
  --certificate-identity=https://github.com/your-org/your-app/.github/workflows/build.yml@refs/heads/main \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com \
  ghcr.io/your-org/your-app:v1.2.3@sha256:abc123...

Avec la signature sans clé, la clé de signature est éphémère et liée à l’identité OIDC du workflow CI/CD. Il n’y a pas de clé de signature à longue durée de vie à voler.

Générer et stocker la provenance SLSA

La provenance SLSA (Supply-chain Levels for Software Artifacts) enregistre comment, où et par qui un artefact a été construit. Au niveau SLSA 3, la provenance est générée par la plateforme de build elle-même et ne peut pas être falsifiée par le processus de build :

# GitHub Actions : Générer la provenance SLSA pour les images de conteneurs
- uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.0.0
  with:
    image: ghcr.io/your-org/your-app
    digest: ${{ steps.build.outputs.digest }}
  secrets:
    registry-username: ${{ github.actor }}
    registry-password: ${{ secrets.GITHUB_TOKEN }}

Stockage d’artefacts immuable

Les artefacts publiés ne devraient jamais être écrasés. Si un attaquant peut remplacer une version publiée, il peut injecter du code malveillant dans chaque déploiement qui référence cette version. Configurez vos registres pour l’immuabilité :

  • Registres de conteneurs : Activez l’immuabilité des tags (ECR, GCR, ACR supportent tous cela).
  • Registres de paquets : Empêchez la republication de versions existantes.
  • Stockage de binaires : Utilisez des politiques de stockage en écriture unique (S3 Object Lock, politiques de rétention GCS).

Génération et attestation de SBOM

Un Software Bill of Materials (SBOM) liste chaque composant de votre artefact. Générer un SBOM au moment du build et l’attester aux côtés de l’artefact crée un inventaire vérifiable pour la gestion des vulnérabilités :

# Générer un SBOM avec Syft et attester avec Cosign
syft ghcr.io/your-org/your-app:v1.2.3 -o spdx-json > sbom.spdx.json
cosign attest --predicate sbom.spdx.json --type spdxjson \
  ghcr.io/your-org/your-app:v1.2.3@sha256:abc123...

Contrôleurs d’admission pour la vérification de signature

Signer les artefacts n’est utile que si vous vérifiez les signatures avant le déploiement. Utilisez les contrôleurs d’admission Kubernetes pour imposer cela automatiquement :

# Kyverno : Exiger des images signées
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-signed-images
spec:
  validationFailureAction: Enforce
  background: false
  rules:
    - name: verify-cosign-signature
      match:
        any:
          - resources:
              kinds:
                - Pod
      verifyImages:
        - imageReferences:
            - "ghcr.io/your-org/*"
          attestors:
            - entries:
                - keyless:
                    issuer: "https://token.actions.githubusercontent.com"
                    subject: "https://github.com/your-org/*"

Avec cette politique en place, toute image de conteneur dépourvue d’une signature Cosign valide provenant de vos workflows GitHub Actions sera rejetée au moment de l’admission — avant même de s’exécuter dans votre cluster.

Défenses de la couche Déploiement — Contrôler ce qui atteint la production

La couche de déploiement est la dernière porte avant que les modifications n’atteignent la production. Les défenses ici garantissent que seuls les artefacts vérifiés et approuvés sont déployés, et que le processus de déploiement lui-même est contrôlé et auditable.

Approbations manuelles requises

Pour les déploiements en production, les pipelines automatisés doivent se mettre en pause et exiger une approbation humaine explicite. Cela fournit un point de contrôle final où un humain peut vérifier que la modification est attendue, testée et autorisée.

# GitHub Actions : Environnement avec réviseurs requis
jobs:
  deploy-production:
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://your-app.example.com
    steps:
      - name: Déployer en production
        run: ./deploy.sh production

Dans les paramètres du dépôt GitHub, configurez l’environnement « production » pour exiger l’approbation de réviseurs désignés avant que le job ne se poursuive.

GitOps avec déploiement en mode pull

Les pipelines CI/CD traditionnels poussent vers la production : le pipeline a des identifiants pour modifier l’infrastructure de production. Le GitOps avec déploiement en mode pull inverse le modèle :

  • Le pipeline met à jour un dépôt Git avec l’état désiré (tags d’images, manifestes).
  • Le cluster exécute un contrôleur (Flux, ArgoCD) qui surveille le dépôt Git et tire les modifications.
  • Le pipeline n’a jamais d’accès direct au cluster. Le cluster tire depuis Git, et Git est la source unique de vérité.
# Flux : GitRepository et Kustomization pour le déploiement en mode pull
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: app-manifests
  namespace: flux-system
spec:
  interval: 1m
  url: https://github.com/your-org/app-manifests
  ref:
    branch: main
  secretRef:
    name: git-credentials
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: app-production
  namespace: flux-system
spec:
  interval: 5m
  path: ./environments/production
  prune: true
  sourceRef:
    kind: GitRepository
    name: app-manifests
  healthChecks:
    - apiVersion: apps/v1
      kind: Deployment
      name: your-app
      namespace: production

Déploiements canary et rollback automatisé

Même avec toutes les défenses en amont, un déploiement peut introduire des problèmes. Les déploiements canary limitent l’exposition en déployant d’abord les modifications sur un petit pourcentage du trafic. Si les métriques se dégradent, le rollback automatisé annule la modification avant qu’elle n’affecte tous les utilisateurs.

  • Utilisez des outils de livraison progressive comme Flagger, Argo Rollouts ou les fonctionnalités canary natives des fournisseurs cloud.
  • Définissez des critères de succès clairs : taux d’erreur, latence, métriques de saturation.
  • Automatisez les déclencheurs de rollback — ne comptez pas sur les humains pour remarquer et réagir à temps.

Gels de déploiement

Pendant les incidents actifs, les fenêtres de maintenance ou les périodes de fort trafic, les déploiements doivent être gelés. Implémentez des politiques de gel de déploiement qui empêchent les déploiements initiés par le pipeline pendant des fenêtres spécifiées, et assurez-vous que seuls les commandants d’incident désignés peuvent outrepasser le gel.

Détection et surveillance — Savoir quand quelque chose ne va pas

La prévention finira par échouer. Les capacités de détection déterminent si vous attrapez une compromission en minutes ou en mois. La surveillance CI/CD est un angle mort pour de nombreuses organisations — leur SIEM ingère les journaux d’application et d’infrastructure mais ignore complètement la télémétrie des pipelines.

Détection d’anomalies d’exécution de pipeline

Établissez des références pour le comportement normal du pipeline et alertez sur les déviations :

  • Temps d’exécution inhabituels : Un build qui prend normalement 5 minutes et qui prend soudainement 30 minutes pourrait indiquer du cryptomining ou une exfiltration de données.
  • Étapes inattendues : De nouvelles étapes de pipeline apparaissant sans modifications de PR correspondantes.
  • Exécution en dehors des heures : Des exécutions de pipeline déclenchées en dehors des heures de travail normales par des comptes inhabituels.
  • Pics d’échecs d’authentification : Plusieurs tentatives d’accès aux secrets échouées depuis une seule exécution de pipeline.

Alertes sur les différences de dépendances

Les nouvelles dépendances ajoutées dans les PR devraient déclencher une revue automatisée et des alertes. Un outil de diff de dépendances peut :

  • Signaler les nouvelles dépendances ajoutées dans une PR pour une revue manuelle.
  • Vérifier les nouvelles dépendances contre les bases de données de paquets malveillants connus.
  • Vérifier que les versions des dépendances correspondent à celles des fichiers de verrouillage connus comme fiables.
  • Alerter sur les dépendances avec des dates de publication très récentes (typosquatting potentiel).

Scanning de secrets

Les secrets fuient à travers les commits, les journaux et les artefacts. Superposez plusieurs approches de scanning :

  • Hooks pre-commit : Des outils comme gitleaks ou trufflehog attrapent les secrets avant qu’ils n’entrent dans le dépôt.
  • Scanning dans le pipeline : Scannez les résultats de build et les journaux pour les identifiants accidentellement exposés.
  • GitHub secret scanning / GitLab secret detection : Scanning natif de la plateforme qui couvre les événements de push et les commits historiques.
  • Alertes du programme partenaire : Le programme partenaire de secret scanning de GitHub notifie les fournisseurs de services lorsque leurs tokens sont exposés, permettant une révocation automatique.
# Hook pre-commit avec gitleaks
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.18.0
    hooks:
      - id: gitleaks

Surveillance de la dérive de configuration

Les définitions de pipeline devraient changer via le processus normal de PR. Surveillez les modifications inattendues :

  • Alertez lorsque les fichiers de workflow, les configurations CI ou les manifestes de déploiement changent en dehors des PR approuvées.
  • Suivez les modifications de permissions de pipeline au fil du temps.
  • Détectez les nouveaux secrets de pipeline ajoutés sans demandes de modification correspondantes.

Intégration SIEM pour les journaux d’audit CI/CD

Transmettez les journaux d’audit CI/CD à votre SIEM aux côtés des journaux d’application et d’infrastructure. Les sources de journaux clés incluent :

  • GitHub Audit Log (niveau organisation et entreprise)
  • GitLab Audit Events
  • Journaux système et journaux de build Jenkins
  • Journaux d’audit du fournisseur cloud pour les appels API initiés par le pipeline (CloudTrail, Cloud Audit Logs, Azure Activity Log)

Corrélez l’activité du pipeline avec les modifications d’infrastructure cloud. Si une exécution de pipeline coïncide avec des modifications de politique IAM inattendues ou la création de ressources, c’est une alerte de haute priorité.

Réponse aux incidents pour le CI/CD — Quand les défenses échouent

Lorsqu’une compromission CI/CD est détectée — ou suspectée — la rapidité est essentielle. L’attaquant peut encore avoir un accès actif, et chaque minute de retard élargit le rayon d’impact. Un playbook de réponse aux incidents préparé pour les scénarios spécifiques au CI/CD est indispensable.

Actions immédiates : Contenir la compromission

  • Révoquer immédiatement les identifiants compromis. Faites tourner tous les secrets auxquels le pipeline compromis avait accès. Cela inclut les identifiants des fournisseurs cloud, les tokens API, les mots de passe de base de données et les tokens de la plateforme CI/CD eux-mêmes.
  • Désactiver le pipeline compromis. Empêcher toute exécution supplémentaire jusqu’à ce que l’investigation soit terminée.
  • Mettre en quarantaine les runners affectés. Si vous utilisez des runners persistants, isolez-les du réseau pour l’analyse forensique.

Analyse du rayon d’impact

Déterminez ce que l’attaquant aurait pu accéder :

  • Quels secrets étaient disponibles pour le job compromis ?
  • Quelles ressources cloud ces identifiants pouvaient-ils accéder ?
  • Quels artefacts ont été produits pendant la période compromise ?
  • Quels environnements ont été déployés depuis le pipeline compromis ?

Vérification de l’intégrité des artefacts

Vérifiez si les artefacts publiés ont été falsifiés :

  • Vérifiez les signatures de tous les artefacts publiés pendant la fenêtre compromise.
  • Comparez les checksums des artefacts avec ceux des builds connus comme fiables.
  • Si l’intégrité des artefacts ne peut être vérifiée, reconstruisez et republiez à partir de commits source connus comme fiables.
  • Notifiez les consommateurs en aval si des artefacts potentiellement compromis ont été distribués.

Investigation forensique

Rassemblez les preuves provenant de multiples sources :

  • Journaux des runners : Quelles commandes ont été exécutées ? Quelles connexions réseau ont été établies ?
  • Journaux d’audit API : Quels appels API l’attaquant a-t-il effectués en utilisant les identifiants du pipeline ?
  • Historique Git : Des commits ou des branches ont-ils été modifiés ? Vérifiez les force pushes ou la réécriture d’historique.
  • Journaux d’audit cloud : Quelles modifications d’infrastructure ont été effectuées par les comptes de service du pipeline ?

Reprise après incident

Après le confinement et l’investigation, restaurez les opérations sécurisées :

  • Faites tourner tous les secrets qui étaient accessibles au pipeline compromis, même s’il n’y a aucune preuve qu’ils ont été exfiltrés.
  • Revoyez et resserrez les permissions du pipeline. L’incident a probablement révélé des portées de permissions plus larges que nécessaire.
  • Mettez à jour les règles de surveillance en fonction des indicateurs de compromission découverts pendant l’investigation.
  • Menez un post-mortem sans blâme axé sur les changements systémiques qui préviennent la récurrence.

Modèle de playbook de réponse aux incidents CI/CD

## Playbook d'incident de sécurité CI/CD

### Phase 1 : Détection et triage (0-15 minutes)
- [ ] Confirmer que l'alerte est un vrai positif
- [ ] Classifier la sévérité (P1 : compromission active, P2 : compromission suspectée, P3 : violation de politique)
- [ ] Notifier le commandant d'incident et l'équipe sécurité

### Phase 2 : Confinement (15-60 minutes)
- [ ] Révoquer les identifiants compromis
- [ ] Désactiver les pipelines affectés
- [ ] Isoler les runners affectés
- [ ] Bloquer l'accès de l'attaquant (révoquer les tokens, désactiver les comptes)

### Phase 3 : Investigation (1-24 heures)
- [ ] Collecter les journaux des runners, les journaux d'audit, l'historique git
- [ ] Déterminer le rayon d'impact (identifiants, artefacts, déploiements)
- [ ] Identifier le vecteur d'attaque (comment l'attaquant est-il entré ?)
- [ ] Vérifier l'intégrité des artefacts pour la période compromise

### Phase 4 : Reprise (24-72 heures)
- [ ] Faire tourner tous les secrets potentiellement compromis
- [ ] Reconstruire et republier les artefacts affectés à partir de sources connues comme fiables
- [ ] Redéployer les environnements affectés à partir d'artefacts vérifiés
- [ ] Restaurer les opérations de pipeline avec des contrôles renforcés

### Phase 5 : Post-incident (1-2 semaines)
- [ ] Mener un post-mortem sans blâme
- [ ] Documenter les leçons apprises et mettre à jour ce playbook
- [ ] Implémenter les améliorations systémiques pour prévenir la récurrence
- [ ] Mettre à jour les règles de détection en fonction des IOC découverts

Conclusion

La sécurité CI/CD n’est pas une checklist que l’on complète une fois pour l’oublier. C’est une pratique d’ingénierie continue qui évolue avec vos pipelines, votre infrastructure et le paysage des menaces. Les attaquants continueront de cibler la supply chain logicielle parce qu’elle offre un levier élevé — un seul pipeline compromis peut affecter chaque déploiement, chaque environnement et chaque client.

Les défenses de ce guide sont organisées par couche, mais les points de départ les plus impactants traversent les couches :

  • Les runners éphémères éliminent des classes entières d’attaques de persistance et de fuite d’état.
  • Les permissions minimales (portée des tokens, OIDC, identifiants par environnement) limitent ce qu’un attaquant peut faire même après avoir obtenu l’accès au pipeline.
  • Les artefacts signés avec contrôle d’admission garantissent que les artefacts falsifiés ne peuvent pas atteindre la production.
  • La détection et la journalisation d’audit comblent le déficit de visibilité qui permet aux compromissions de passer inaperçues pendant des mois.

Commencez par ces contrôles à fort impact. Ajoutez des défenses supplémentaires à mesure que votre programme de sécurité mûrit. Et supposez toujours que votre pipeline sera ciblé — car il le sera.

Dans le prochain article de cette série, nous parcourrons l’implémentation de ces défenses dans un pipeline GitHub Actions réel, avec un exemple fonctionnel complet que vous pourrez adapter pour vos propres dépôts.