Introduction
Les pipelines CI/CD figurent parmi les composants les plus privilégiés de toute organisation logicielle moderne. Ils clonent le code source, accèdent aux secrets, construisent des artefacts et déploient en production — souvent avec une supervision humaine minimale. Pourtant, malgré ce niveau d’accès extraordinaire, les modèles de confiance qui sous-tendent ces pipelines sont rarement rendus explicites.
Lorsqu’un pipeline s’exécute, il répond implicitement à une chaîne de questions de sécurité : Qui a déclenché cette exécution ? Quel code est exécuté ? Quelle identité le pipeline assume-t-il ? Quelles ressources peut-il atteindre ? Dans la plupart des organisations, ces questions trouvent leur réponse dans les configurations par défaut plutôt que dans des décisions de sécurité délibérées.
Ce guide cartographie le fonctionnement des différents modèles d’exécution CI/CD, les endroits où la confiance est supposée plutôt que vérifiée, et comment durcir vos pipelines contre les schémas d’attaque réels qui exploitent ces failles. Que vous utilisiez GitHub Actions, GitLab CI ou une autre plateforme, les dynamiques de confiance sous-jacentes sont universelles — et les comprendre est essentiel pour sécuriser votre chaîne d’approvisionnement logicielle.
Qu’est-ce qu’un modèle d’exécution CI/CD ?
Un modèle d’exécution CI/CD définit le cycle de vie complet de la manière dont le code du pipeline est déclenché, où il s’exécute physiquement, quelle identité il assume pendant l’exécution et quelles ressources il peut atteindre. Il constitue, par essence, l’architecture de sécurité de votre couche d’automatisation.
Chaque modèle d’exécution doit répondre à quatre questions fondamentales :
- Déclencheur : Quel événement initie le pipeline, et qui ou quoi est autorisé à provoquer cet événement ?
- Environnement : Où le code du pipeline s’exécute-t-il — sur quelle infrastructure, avec quel système d’exploitation et avec quel degré d’isolation ?
- Identité : Quels identifiants, tokens ou comptes de service le pipeline en cours d’exécution possède-t-il ?
- Accès : Quels systèmes en aval, secrets, registres et cibles de déploiement le pipeline peut-il atteindre ?
La manière dont ces questions trouvent leur réponse varie considérablement selon les environnements d’exécution :
Runners hébergés en SaaS
Les plateformes comme GitHub Actions (runners hébergés par GitHub) et les runners partagés de GitLab.com fournissent des machines virtuelles éphémères gérées par le fournisseur CI/CD. Chaque job obtient généralement une VM neuve qui est détruite après l’exécution. La plateforme gère les mises à jour, l’isolation et le cycle de vie. Le compromis est que vous faites confiance aux garanties d’isolation du fournisseur — vous ne pouvez ni inspecter ni contrôler l’infrastructure sous-jacente.
Runners auto-hébergés
Les organisations déploient leurs propres agents runner sur l’infrastructure qu’elles contrôlent — VMs, serveurs physiques ou pods Kubernetes. Cela offre un contrôle total sur l’environnement d’exécution mais transfère entièrement la responsabilité de l’isolation, des mises à jour et de la gestion des identifiants à l’opérateur. Un runner auto-hébergé mal configuré est l’un des vecteurs les plus courants de mouvement latéral dans les attaques CI/CD.
Exécution conteneurisée
De nombreux pipelines exécutent les jobs à l’intérieur de conteneurs, que ce soit sur une infrastructure auto-hébergée ou sur des clusters Kubernetes managés. L’exécution basée sur les conteneurs fournit une isolation au niveau des processus et des environnements reproductibles, mais les conteneurs ne constituent pas des frontières de sécurité de la même manière que les VMs. L’accès partagé au kernel, les volumes montés et l’exposition du socket Docker peuvent tous compromettre le modèle d’isolation.
Exécution serverless et à la demande
Certains systèmes CI/CD modernes (tels qu’AWS CodeBuild ou certaines configurations Buildkite) provisionnent un calcul entièrement à la demande pour chaque job. Ces modèles offrent de fortes garanties d’isolation puisque chaque exécution obtient une instance de calcul dédiée et éphémère, mais ils introduisent une complexité autour du bootstrapping des identifiants et du contrôle d’accès réseau.
Comprendre quel modèle votre organisation utilise — et les propriétés de sécurité qu’il fournit ou ne fournit pas — est le fondement du raisonnement sur la confiance CI/CD.
Frontières de confiance dans le CI/CD
Une frontière de confiance existe partout où le contrôle passe d’une entité ou d’un système à un autre. Dans le CI/CD, il existe plusieurs frontières de confiance critiques, et les défaillances à n’importe laquelle d’entre elles peuvent mener à une compromission complète du pipeline.
Du dépôt de code source au déclencheur du pipeline
La première frontière de confiance se situe entre le dépôt de code et le mécanisme de déclenchement du pipeline. Lorsqu’un développeur pousse un commit ou ouvre une pull request, la plateforme CI/CD décide si et comment exécuter un pipeline. La question critique est : qui peut déclencher l’exécution du pipeline, et peut-il contrôler quel code le pipeline exécute ?
Dans de nombreuses configurations, quiconque peut ouvrir une pull request — y compris les contributeurs externes aux dépôts publics — peut déclencher l’exécution du pipeline. Si la définition du pipeline elle-même provient de la branche de la PR, le contributeur contrôle effectivement le code qui s’exécute dans votre environnement CI.
De la définition du pipeline à l’environnement d’exécution
La deuxième frontière de confiance sépare la définition du pipeline (le fichier YAML, le Jenkinsfile, le script de build) de l’environnement où il s’exécute. Les questions clés incluent : Le runner a-t-il accès au réseau ? Le pipeline peut-il installer des logiciels arbitraires ? Peut-il modifier le runner lui-même pour les jobs futurs ?
Sur les runners partagés ou persistants, une définition de pipeline malveillante pourrait installer une porte dérobée qui persiste à travers les exécutions de jobs ultérieures — affectant des dépôts et des équipes entièrement différents.
De l’environnement d’exécution aux secrets et identifiants
Les pipelines ont besoin d’identifiants pour effectuer un travail utile : tokens API, clés de fournisseurs cloud, mots de passe de registres, clés de signature. La frontière de confiance entre l’environnement d’exécution et le magasin de secrets détermine ce à quoi un pipeline compromis peut accéder. Un accès aux secrets trop large est l’une des erreurs de configuration les plus courantes et les plus dangereuses dans le CI/CD.
De la sortie du build à la cible de déploiement
La dernière frontière de confiance se situe entre ce que le pipeline produit (une image de conteneur, un binaire, un plan Terraform) et le système où cette sortie est déployée. Si l’identité du pipeline qui construit un artefact est la même identité qui le déploie en production, il n’y a pas de séparation des responsabilités. Une seule étape de build compromise peut mener directement à une compromission de la production.
Cartographie des zones de confiance
Conceptuellement, un pipeline CI/CD traverse quatre zones de confiance :
Zone 1: Contrôle de source (Postes de travail des développeurs, branches, PRs)
↓ [Frontière de déclenchement]
Zone 2: Définition du pipeline (YAML/config analysé par la plateforme CI)
↓ [Frontière d'exécution]
Zone 3: Environnement d'exécution (Runner, conteneur, VM — avec secrets)
↓ [Frontière de déploiement]
Zone 4: Cibles de déploiement (Production, staging, registres, APIs cloud)
Chaque flèche représente une frontière de confiance. Des contrôles de sécurité devraient exister à chaque transition : règles de protection des branches à la frontière de déclenchement, isolation des runners à la frontière d’exécution, identifiants à portée limitée à la frontière des secrets, et approbations de déploiement à la frontière de déploiement.
Modèle d’exécution GitHub Actions
GitHub Actions est l’une des plateformes CI/CD les plus largement adoptées, et son modèle d’exécution possède plusieurs caractéristiques de confiance uniques qu’il convient de comprendre en profondeur.
Runners hébergés par GitHub vs runners auto-hébergés
Les runners hébergés par GitHub sont des VMs éphémères provisionnées par GitHub pour chaque job. Ils fonctionnent sur l’infrastructure Azure, sont détruits après chaque exécution de job et fournissent une forte isolation entre les jobs. Les runners auto-hébergés, en revanche, sont des machines que vous enregistrez auprès de GitHub. Ils persistent entre les jobs, peuvent accumuler de l’état et — point critique — tout dépôt de l’organisation ayant accès au runner peut exécuter du code dessus.
Pour les runners auto-hébergés, GitHub avertit explicitement : n’utilisez pas de runners auto-hébergés avec des dépôts publics. N’importe quel fork peut soumettre une pull request qui déclenche un workflow, et ce workflow s’exécute sur votre infrastructure avec votre accès réseau.
Permissions et portée du GITHUB_TOKEN
Chaque exécution de workflow reçoit un GITHUB_TOKEN automatique avec des permissions limitées au dépôt. Par défaut, ce token dispose de larges permissions de lecture/écriture sur le contenu du dépôt, les packages, les issues et plus encore. La clé permissions vous permet de restreindre ce token à ce qui est strictement nécessaire :
permissions:
contents: read
packages: write
id-token: write # Pour la fédération OIDC
Définir les permissions au niveau supérieur à read-all ou même vides ({}) puis accorder des permissions spécifiques par job est une étape de durcissement critique. Sans cela, toute étape compromise dans n’importe quel job dispose d’un accès en écriture à votre dépôt.
Workflows de PR de forks : pull_request vs pull_request_target
C’est l’une des frontières de confiance les plus dangereuses dans GitHub Actions. L’événement pull_request exécute la définition du workflow depuis la branche head de la PR — ce qui signifie que le contributeur contrôle le code du workflow — mais de manière critique, il n’a pas accès aux secrets du dépôt. L’événement pull_request_target exécute le workflow depuis la branche base (la branche main de votre dépôt) mais a accès aux secrets.
Le danger survient lorsque les workflows pull_request_target font un checkout du code de la branche head de la PR :
# DANGEREUX : pull_request_target avec checkout explicite du code de la PR
on: pull_request_target
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
# Ceci exécute maintenant du CODE NON FIABLE avec accès aux SECRETS
- run: npm install && npm test
Ce pattern donne à un attaquant la capacité d’exécuter du code arbitraire avec accès aux secrets de votre dépôt. C’est l’exemple canonique de Poisoned Pipeline Execution dans GitHub Actions.
Workflows réutilisables et délégation de confiance
Les workflows réutilisables vous permettent de centraliser la logique de pipeline dans un dépôt partagé et de l’appeler depuis d’autres dépôts. Lorsqu’un workflow réutilisable est invoqué, il s’exécute avec les permissions et les secrets du workflow appelant. Cela crée une chaîne de délégation de confiance : vous faites confiance au code du workflow réutilisable (dans un autre dépôt) pour gérer vos secrets de manière responsable.
Épinglez les workflows réutilisables à un SHA de commit spécifique, pas à une branche ou un tag :
jobs:
deploy:
uses: my-org/shared-workflows/.github/workflows/deploy.yml@a1b2c3d4e5f6
secrets: inherit
Règles de protection des environnements
Les Environments GitHub fournissent une frontière de confiance critique pour les workflows de déploiement. Vous pouvez configurer des réviseurs requis, des délais d’attente et des restrictions de branches sur les environnements. Lorsqu’un job référence un environnement, il doit satisfaire les règles de protection avant que les secrets associés à cet environnement ne soient rendus disponibles :
jobs:
deploy-production:
runs-on: ubuntu-latest
environment:
name: production
url: https://example.com
steps:
- name: Deploy
run: ./deploy.sh
env:
AWS_ACCESS_KEY_ID: ${{ secrets.PROD_AWS_KEY }}
Cela garantit que même si un workflow est déclenché, les identifiants de production ne sont pas exposés sans approbation humaine.
Modèle d’exécution GitLab CI
GitLab CI possède un modèle d’exécution différent avec ses propres caractéristiques de confiance, notamment autour de la portée des runners et de la protection des variables.
Runners partagés vs runners de groupe vs runners de projet
GitLab offre trois niveaux de portée pour les runners. Les runners partagés (sur GitLab.com, ceux-ci sont gérés par GitLab) sont disponibles pour tous les projets. Les runners de groupe sont disponibles pour tous les projets au sein d’un groupe GitLab. Les runners de projet sont dédiés à un seul projet. La portée détermine le rayon d’impact d’un runner compromis — une compromission de runner partagé affecte tous les projets, tandis qu’une compromission de runner de projet est contenue à un seul projet.
Pour les charges de travail sensibles, préférez toujours les runners spécifiques au projet avec un étiquetage approprié :
deploy-production:
stage: deploy
tags:
- production-runner
- isolated
script:
- ./deploy.sh
rules:
- if: $CI_COMMIT_BRANCH == "main"
Branches protégées et variables protégées
Le mécanisme de variables protégées de GitLab est un contrôle de confiance clé. Les variables marquées comme « protégées » ne sont exposées qu’aux pipelines s’exécutant sur des branches protégées ou des tags protégés. Cela signifie qu’un pipeline déclenché par une merge request depuis une branche de fonctionnalité — ou pire, depuis un fork — n’aura pas accès aux variables protégées.
C’est le mécanisme principal de GitLab pour empêcher l’exposition des secrets au code non fiable :
# Dans .gitlab-ci.yml, les variables protégées ne sont disponibles que sur les branches protégées
deploy:
stage: deploy
script:
- echo "Deploying with $PRODUCTION_API_KEY"
rules:
- if: $CI_COMMIT_BRANCH == "main" # main est une branche protégée
environment:
name: production
Portée et limitations du CI_JOB_TOKEN
Chaque job GitLab CI reçoit un CI_JOB_TOKEN, un token généré automatiquement et limité au projet. Par défaut, ce token peut accéder aux ressources d’autres projets, ce qui crée une relation de confiance implicite. GitLab vous permet de restreindre l’accès du CI_JOB_TOKEN en configurant une liste blanche de projets accessibles — une étape de durcissement critique qui limite le mouvement latéral si un pipeline est compromis.
Dans les paramètres de votre projet sous CI/CD → Token Access, restreignez la portée du token aux seuls projets avec lesquels votre pipeline a véritablement besoin d’interagir.
Pipelines de merge request et frontières de confiance
GitLab distingue les pipelines de branche et les pipelines de merge request. Les pipelines de merge request s’exécutent dans le contexte de la merge request et ont accès à un ensemble limité de variables prédéfinies. Pour les pipelines déclenchés par des merge requests provenant de forks, GitLab n’expose pas les variables protégées ni les secrets au niveau du projet — c’est une frontière de confiance intentionnelle.
Cependant, les pipelines s’exécutant sur le résultat fusionné (le merge_request_event avec les pipelines de résultats fusionnés activés) exécutent toujours le code du fork. Si votre définition de pipeline permet l’exécution de code arbitraire et que le job a accès aux secrets via des variables non protégées, cela peut toujours être exploité.
Défaillances courantes des hypothèses de confiance
Comprendre les modèles d’exécution est important, mais la vraie valeur réside dans la reconnaissance des patterns qui mènent à la compromission. Voici les défaillances d’hypothèses de confiance qui apparaissent de manière répétée dans les violations CI/CD réelles.
Poisoned Pipeline Execution (PPE)
Le Poisoned Pipeline Execution survient lorsqu’un attaquant peut modifier la définition du pipeline qui s’exécute dans un contexte privilégié. C’est la classe de vulnérabilité CI/CD la plus répandue. Cela se produit lorsque :
- Une pull request déclenche un workflow qui utilise la version du fichier pipeline de la PR
- Ce workflow a accès aux secrets ou aux identifiants de déploiement
- Il n’y a pas de porte de révision ou d’approbation entre la PR et l’exécution du pipeline
L’attaquant modifie le YAML du pipeline (ou un script qu’il appelle) pour exfiltrer les secrets, injecter des portes dérobées dans les artefacts de build, ou pivoter vers les systèmes internes.
Supposer l’isolation des runners sur une infrastructure partagée
Lorsque plusieurs équipes ou projets partagent des runners — en particulier des runners auto-hébergés — il existe souvent une hypothèse implicite d’isolation qui n’existe pas réellement. Un job s’exécutant sur un runner auto-hébergé partagé peut être en mesure de :
- Lire les fichiers laissés par les jobs précédents (identifiants en cache, artefacts de build)
- Accéder au socket Docker et inspecter ou modifier d’autres conteneurs
- Atteindre les ressources du réseau interne disponibles pour l’hôte du runner
- Installer des portes dérobées persistantes sur le runner pour les jobs futurs
Comptes de service sur-permissionnés
Un pattern d’une fréquence alarmante consiste à donner au compte de service CI/CD un large accès administratif — « juste pour que ça fonctionne ». Un rôle IAM AWS avec AdministratorAccess, un compte de service Kubernetes avec cluster-admin, ou un compte SQL cloud avec des privilèges DBA. Lorsque n’importe quelle étape du pipeline est compromise, l’attaquant hérite de toutes ces permissions.
Confiance implicite dans les actions et templates tiers
Utiliser des GitHub Actions communautaires ou des templates GitLab CI signifie exécuter le code de quelqu’un d’autre dans votre pipeline avec vos secrets. Lorsque vous référencez uses: some-org/some-action@v2, vous faites confiance que :
- Le code de l’action n’est pas malveillant
- Les mainteneurs de l’action n’ont pas été compromis
- Le tag
v2n’a pas été déplacé pour pointer vers un code différent - Les dépendances de l’action sont dignes de confiance
Les références de tags sont mutables. Un attaquant qui compromet le dépôt d’une action peut déplacer le tag v2 vers un commit malveillant, et chaque pipeline référençant ce tag exécutera le nouveau code lors de sa prochaine exécution.
Confusion entre identité de build et identité de déploiement
De nombreux pipelines utilisent une seule identité (compte de service, rôle IAM ou token) pour le build et le déploiement. Cette confusion signifie qu’une compromission pendant la phase de build — qui manipule du code non fiable — donne un accès direct aux cibles de déploiement. L’identité de build ne devrait pouvoir que produire des artefacts. Une identité de déploiement distincte et plus restreinte devrait être utilisée pour déployer ces artefacts en production.
Durcissement des hypothèses de confiance
Avec le modèle de menace clarifié, voici les mesures d’atténuation concrètes qui alignent les contrôles sur les frontières de confiance.
Conditions de déclenchement explicites et filtres de branches
N’autorisez jamais les déclencheurs de pipeline sans restriction. Limitez les événements qui peuvent déclencher quels workflows, et assurez-vous que les pipelines privilégiés ne s’exécutent que sur des branches de confiance :
# GitHub Actions : restreindre le déploiement à la branche main uniquement
on:
push:
branches: [main]
pull_request:
branches: [main]
# Ne déclencher que sur les PRs ciblant main ; le code de la PR s'exécute sans secrets
jobs:
deploy:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ./deploy.sh
# GitLab CI : utiliser des rules pour restreindre les jobs sensibles
deploy-production:
stage: deploy
script:
- ./deploy.sh
rules:
- if: $CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE != "merge_request_event"
when: manual
allow_failure: false
environment:
name: production
Permissions minimales des tokens
Appliquez le principe du moindre privilège à chaque token de votre pipeline. Dans GitHub Actions, définissez des permissions par défaut restrictives et accordez des permissions spécifiques par job :
# Définir des valeurs par défaut restrictives au niveau du workflow
permissions: read-all
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
deploy:
needs: build
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # Uniquement pour OIDC, pas d'écriture sur le dépôt
environment: production
steps:
- run: ./deploy.sh
Dans GitLab, restreignez la portée du CI_JOB_TOKEN dans les paramètres du projet et utilisez exclusivement les variables protégées pour les identifiants sensibles.
Runners éphémères et isolés
Dans la mesure du possible, utilisez des runners éphémères qui sont créés à neuf pour chaque job et détruits immédiatement après. Cela élimine les attaques basées sur la persistance et les fuites de données entre jobs. Pour les environnements auto-hébergés, des outils comme Actions Runner Controller (ARC) de GitHub pour Kubernetes ou le runner autoscaling de GitLab sur AWS/GCP peuvent provisionner des pods ou VMs de runner éphémères pour chaque job.
Propriétés clés d’une configuration de runner durcie :
- Pas de stockage persistant entre les jobs
- Pas de socket Docker partagé
- Segmentation réseau limitant l’accès aux seuls endpoints requis
- Aucune possibilité pour le job de modifier la configuration du runner lui-même
Épinglage des actions et images par SHA
Les références mutables (noms de branches, tags comme v2) peuvent être modifiées par les mainteneurs en amont — ou par des attaquants. L’épinglage à un SHA de commit spécifique garantit que le code exact que vous avez révisé est celui qui s’exécute dans votre pipeline :
# Au lieu de ceci (tag mutable) :
- uses: actions/checkout@v4
# Utilisez ceci (SHA immuable) :
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
Le même principe s’applique aux images de conteneurs. Utilisez les digests d’images au lieu des tags :
# Au lieu de :
image: node:20-alpine
# Utilisez :
image: node@sha256:a1b2c3d4e5f6... # épinglé à un digest spécifique
Des outils comme Dependabot et Renovate peuvent automatiquement créer des PRs pour mettre à jour les SHAs épinglés lorsque de nouvelles versions sont publiées, vous offrant ainsi à la fois sécurité et maintenabilité.
Séparation des identités de build et de déploiement
Implémentez des identités distinctes pour les phases de build et de déploiement. L’identité de build devrait avoir :
- Un accès en lecture au code source
- Un accès en écriture au stockage d’artefacts (registre de conteneurs, bucket S3)
- Aucun accès aux environnements de production
L’identité de déploiement devrait avoir :
- Un accès en lecture au stockage d’artefacts
- Un accès en écriture à la cible de déploiement spécifique
- Aucun accès au code source ni la capacité de déclencher des builds
Utilisez la fédération OIDC lorsque c’est possible pour éliminer entièrement les identifiants à longue durée de vie. GitHub Actions et GitLab CI supportent tous deux les tokens OIDC qui peuvent être échangés contre des identifiants de fournisseur cloud à courte durée de vie :
# GitHub Actions OIDC avec AWS
jobs:
deploy:
permissions:
id-token: write
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502
with:
role-to-assume: arn:aws:iam::123456789012:role/deploy-production
aws-region: us-east-1
# GitLab CI OIDC avec AWS
deploy:
stage: deploy
id_tokens:
AWS_TOKEN:
aud: https://gitlab.com
script:
- >
STS_CREDENTIALS=$(aws sts assume-role-with-web-identity
--role-arn arn:aws:iam::123456789012:role/deploy-production
--web-identity-token $AWS_TOKEN
--role-session-name "gitlab-ci-${CI_JOB_ID}")
- export AWS_ACCESS_KEY_ID=$(echo $STS_CREDENTIALS | jq -r '.Credentials.AccessKeyId')
- ./deploy.sh
Conclusion
Chaque pipeline CI/CD possède un modèle de confiance. La question est de savoir si ce modèle de confiance a été conçu intentionnellement ou s’il a émergé accidentellement des configurations par défaut et des corrections rapides.
Le modèle d’exécution que vous choisissez — hébergé en SaaS, auto-hébergé, conteneurisé ou serverless — détermine les propriétés de sécurité de base de votre pipeline. Mais le modèle d’exécution seul ne suffit pas. La confiance doit être explicitement délimitée à chaque transition : du code source au déclencheur, du déclencheur à l’exécution, de l’exécution aux secrets, et du build au déploiement.
Les patterns couverts dans ce guide — Poisoned Pipeline Execution, abus de runners partagés, identités sur-permissionnées, références d’actions mutables et identités de build/déploiement confondues — ne sont pas théoriques. Ce sont les techniques réellement utilisées dans les attaques de chaîne d’approvisionnement du monde réel, de la compromission SolarWinds à la brèche Codecov et au-delà.
Commencez par cartographier vos frontières de confiance actuelles. Identifiez où la confiance est supposée plutôt que vérifiée. Puis appliquez les mesures de durcissement de manière systématique : restreignez les déclencheurs, minimisez les permissions, isolez les runners, épinglez les dépendances et séparez les identités. Traitez votre pipeline CI/CD avec la même rigueur que vous appliquez à votre infrastructure de production — car en pratique, c’est la porte d’entrée de votre infrastructure de production.