## Introduction GitLab Runner exécute les tâches CI/CD, ce qui signifie qu'il détient des informations d'identification, touche au code source et dispose souvent d'un accès étendu à votre infrastructure. Un runner mal configuré peut divulguer des secrets, permettre une exécution de code non autorisée ou devenir un point de pivot pour les attaquants. Ce guide fournit des étapes concrètes et testables pour durcir GitLab Runner, depuis les vérifications initiales de version jusqu'au contrôle d'accès, à la gestion des secrets et aux procédures de reprise. Nous nous concentrons sur les runners autogérés sous Linux, bien que de nombreux principes s'appliquent à d'autres plateformes. Vous apprendrez à inventorier votre runner, verrouiller sa configuration, restreindre qui peut l'utiliser, gérer les secrets en toute sécurité, vérifier vos modifications et récupérer en cas de problème. Chaque section comprend des commandes, les sorties attendues et des chemins de retour en arrière. Avant de commencer, assurez-vous de disposer de : - Une instance GitLab en cours d'exécution (autogérée ou GitLab.com) et au moins un runner enregistré. - Un accès shell à la machine hébergeant le runner. - Les privilèges sudo sur cette machine pour les modifications de configuration. - Un projet de test dans GitLab pour valider le comportement du runner après les changements. Avertissement de sécurité : N'utilisez jamais de véritables informations d'identification, jetons ou clés privées dans les exemples ou la documentation. Remplacez-les par des espaces réservés clairement identifiés comme VOTRE_JETON_RUNNER . Testez toujours les modifications dans un environnement de préproduction d'abord. ## Inventaire des versions et de l'environnement Savoir exactement quelle version de GitLab Runner vous exécutez, comment elle est déployée et quelles permissions elle possède est le fondement de tout effort de durcissement. Différentes versions ont des fonctionnalités de sécurité et des corrections de bogues différentes. ### Vérifier la version du runner Exécutez ceci sur l'hôte du runner : gitlab-runner --version Sortie attendue : Version: 16.11.0 Git revision: 4b8e4c1f Git branch: 16-11-stable GO version: go1.21.9 Built: 2024-04-18T14:32:11Z OS/Arch: linux/amd64 Notez le numéro de version. GitLab Runner suit une gestion sémantique de version, et les correctifs de sécurité sont publiés régulièrement. Consultez la page officielle des versions de GitLab Runner pour vérifier si vous utilisez la dernière version stable. Sinon, planifiez une mise à niveau après avoir terminé votre inventaire. ### Déterminer la topologie de déploiement GitLab Runner peut être installé en tant que binaire sur un hôte, exécuté dans un conteneur Docker ou déployé dans Kubernetes. La topologie affecte la manière d'appliquer les contrôles de sécurité. Installation binaire : Vérifiez l'état du service : sudo systemctl status gitlab-runner Installation Docker : Listez les conteneurs : docker ps --filter "name=gitlab-runner" Installation Kubernetes : Listez les pods dans l'espace de noms du runner : kubectl get pods -n gitlab-runner Connaître la topologie vous aide à décider où appliquer les permissions de fichiers, les politiques réseau et les procédures de mise à jour. ### Lister les runners enregistrés et leurs configurations Le fichier de configuration du runner (généralement /etc/gitlab-runner/config.toml ) contient des informations sensibles comme les jetons d'enregistrement et les paramètres de l'exécuteur. Consultez-le avec prudence : sudo cat /etc/gitlab-runner/config.toml Ce fichier peut inclure des jetons. Ne le partagez jamais et ne le committez pas dans un système de contrôle de version. Pour un résumé rapide sans exposer les secrets, vous pouvez utiliser : sudo gitlab-runner list Exemple de sortie : Runtime platform arch=amd64 os=linux pid=1234 revision=4b8e4c1f version=16.11.0 Listing configured runners ConfigFile=/etc/gitlab-runner/config.toml MyRunner Executor=docker Token=xxxxxx URL=https://gitlab.example.com Notez les types d'exécuteur (shell, docker, kubernetes, etc.). L'exécuteur détermine la surface d'attaque. Par exemple, l'exécuteur shell exécute les tâches directement sur l'hôte avec les privilèges de l'utilisateur gitlab-runner , ce qui est plus risqué que l'exécuteur Docker qui fournit une certaine isolation. ### Vérifier l'utilisateur et les permissions du runner Identifiez l'utilisateur sous lequel le service du runner s'exécute : ps aux | grep gitlab-runner La sortie peut montrer gitlab-runner comme utilisateur. Vérifiez à quels groupes cet utilisateur appartient : groups gitlab-runner Si l'utilisateur du runner est dans le groupe docker , il a effectivement un accès de niveau root à l'hôte car Docker peut monter le système de fichiers de l'hôte. C'est une mauvaise configuration courante. Nous y remédierons dans la section sur le contrôle d'accès. ### Enregistrer une base de référence Avant d'apporter des modifications, créez un instantané de référence : sudo cp /etc/gitlab-runner/config.toml /etc/gitlab-runner/config.toml.bak.$(date +%Y%m%d) sudo gitlab-runner --version > runner_version_baseline.txt sudo systemctl status gitlab-runner > runner_service_baseline.txt Cela vous permet de comparer et de revenir en arrière si nécessaire. ## Chemin de configuration sûr Le durcissement de GitLab Runner implique de modifier son config.toml et éventuellement son unité de service. L'objectif est de minimiser les privilèges, désactiver les fonctionnalités inutilisées et appliquer des valeurs par défaut sécurisées. ### Sauvegarder et modifier la configuration Sauvegardez toujours avant de modifier : sudo cp /etc/gitlab-runner/config.toml /etc/gitlab-runner/config.toml.backup Modifiez avec votre éditeur préféré : sudo nano /etc/gitlab-runner/config.toml ### Durcir la configuration globale Dans la section [[runners]] , considérez ces paramètres : - concurrent : limite le nombre de tâches qu'un runner peut exécuter simultanément. Le réduire diminue le risque d'épuisement des ressources. Exemple : concurrent = 2 - check_interval : fréquence à laquelle le runner vérifie les nouvelles tâches. Un intervalle plus court (par exemple, 3 secondes) réduit la latence des tâches mais augmente la charge. - log_level : réglez sur info ou warn pour un fonctionnement normal ; évitez debug en production car il peut enregistrer des données sensibles. - sentry_dsn : si vous utilisez Sentry pour le suivi des erreurs, assurez-vous que le DSN ne contient pas de secret dans le fichier de configuration. Utilisez plutôt des variables d'environnement. Exemple d'extrait : concurrent = 2 check_interval = 3 log_level = "info" ### Désactiver les exécuteurs inutilisés Si vous n'utilisez que l'exécuteur Docker, assurez-vous que l'exécuteur shell n'est pas configuré. Supprimez ou commentez toutes les entrées [[runners]] supplémentaires dont vous n'avez pas besoin. Chaque entrée de runner augmente la surface d'attaque. ### Restreindre les capacités de l'exécuteur Docker Pour l'exécuteur Docker, vous pouvez limiter les capacités et les ressources des conteneurs. Dans la section [runners.docker] : [runners.docker] image = "alpine:latest" privileged = false disable_cache = false volumes = ["/cache"] shm_size = 0 cap_drop = ["ALL"] cap_add = ["NET_BIND_SERVICE"] devices = [] allowed_images = ["alpine:*", "debian:*"] allowed_services = [] Paramètres clés : - privileged = false : ne jamais exécuter de conteneurs privilégiés sauf en cas de nécessité absolue. Les conteneurs privilégiés ont toutes les capacités et peuvent accéder aux périphériques de l'hôte. - cap_drop = ["ALL"] et cap_add uniquement ce qui est nécessaire : cela limite les capacités Linux à l'intérieur des conteneurs. - allowed_images limite les images Docker que les tâches peuvent utiliser. Cela empêche de tirer des images arbitraires qui pourraient contenir du code malveillant. - disallowed_images peut être ajouté avec un tableau de noms d'images (par exemple, ["ubuntu:latest"] ) pour bloquer des images spécifiques. ### Restreindre l'accès réseau pour Docker Vous pouvez désactiver l'accès réseau pour les tâches qui n'en ont pas besoin : [runners.docker] network_mode = "none" Si les tâches ont besoin du réseau, utilisez un réseau Docker défini par l'utilisateur avec une sortie limitée. ### Durcir l'unité de service du runner Si le runner est installé en tant que service système, vous pouvez ajouter des directives de sécurité. Modifiez le fichier de service avec : sudo systemctl edit gitlab-runner Ajoutez des directives comme : [Service] # Empêcher le service d'acquérir de nouveaux privilèges NoNewPrivileges=true # Restreindre l'accès au système de fichiers ProtectSystem=strict ProtectHome=true # /tmp privé PrivateTmp=true # Limiter les capacités CapabilityBoundingSet=CAP_NET_BIND_SERVICE Après modification, rechargez et redémarrez : sudo systemctl daemon-reload sudo systemctl restart gitlab-runner Vérifiez que le service est en cours d'exécution : sudo systemctl status gitlab-runner La sortie attendue inclut Active: active (running) . ### Vérifier la configuration après les modifications Exécutez la vérification intégrée du runner : sudo gitlab-runner verify Sortie attendue : Runtime platform arch=amd64 os=linux pid=5678 revision=4b8e4c1f version=16.11.0 Running in system-mode. Verifying runner... is alive runner=xxxxxx Si vous voyez des erreurs comme ERROR: Verifying runner... failed , vérifiez la syntaxe du fichier de configuration et la connectivité réseau. ## Contrôle d'accès et permissions Contrôler qui peut utiliser le runner et à quoi le runner peut accéder est crucial. GitLab fournit plusieurs couches de contrôle d'accès. ### Enregistrement du runner et accès au projet Par défaut, toute personne ayant accès à un projet peut enregistrer un runner pour ce projet si elle dispose de la permission Gérer les runners du projet . Pour réduire le risque, limitez l'enregistrement des runners aux administrateurs. Dans GitLab, allez dans Zone d'administration > Paramètres > CI/CD > Runners et décochez « Autoriser quiconque à enregistrer des runners » (pour les autogérés) ou définissez les permissions appropriées sur GitLab.com. ### Utiliser des runners protégés Les runners protégés n'exécutent des tâches que sur des branches ou des tags protégés. Cela restreint l'exécution à du code de confiance. Pour protéger un runner : - Allez dans les Paramètres > CI/CD > Runners de votre projet. - Trouvez le runner et cliquez sur l'icône en forme de crayon. - Cochez « Protégé » et éventuellement « Exécuter les tâches non taguées ». Alternativement, dans config.toml , vous pouvez définir : [[runners]] name = "ProtectedRunner" url = "https://gitlab.example.com" token = "VOTRE_JETON_RUNNER" executor = "docker" protected = true Remarque : Le drapeau protected dans config.toml est déprécié au profit des paramètres côté GitLab. Utilisez l'interface utilisateur ou l'API pour gérer la protection. ### Restreindre le runner à des projets ou groupes spécifiques Vous pouvez limiter un runner à des projets ou groupes spécifiques. Dans config.toml , utilisez limit pour restreindre le nombre de projets, mais l'affectation réelle se fait dans GitLab. Dans l'interface GitLab, vous pouvez affecter un runner à un projet ou à un groupe. Les runners de groupe sont partagés entre tous les projets d'un groupe, ce qui peut être trop large. Préférez les runners spécifiques à un projet pour les projets à haute sécurité. ### Permissions au niveau du système d'exploitation Assurez-vous que l'utilisateur du runner ( gitlab-runner ) n'a pas de privilèges inutiles : - Retirez-le du groupe docker si vous utilisez l'exécuteur Docker avec le socket du démon Docker. - Ne l'ajoutez pas aux sudoers . - Définissez un shell fort : sudo chsh -s /usr/sbin/nologin gitlab-runner si le runner n'a pas besoin d'un accès shell. Vérifiez l'accès sudo : sudo -l -U gitlab-runner La sortie attendue doit montrer aucune permission sudo (ou seulement des permissions limitées). ### Contrôle d'accès réseau Utilisez des règles de pare-feu pour restreindre le trafic sortant de l'hôte du runner vers uniquement les points de terminaison nécessaires (serveur GitLab, registre Docker, etc.). Par exemple, avec ufw : sudo ufw allow out to port 443 proto tcp sudo ufw allow out to port 443 proto tcp sudo ufw default deny outgoing sudo ufw enable Remplacez les espaces réservés par les adresses IP réelles. Vérifiez avec : sudo ufw status verbose ## Gestion des secrets dans GitLab Runner Les secrets sont souvent nécessaires dans les tâches CI/CD (clés API, informations d'identification de déploiement, etc.). GitLab Runner doit les gérer en toute sécurité. ### Utiliser les variables CI/CD de GitLab Stockez les secrets en tant que variables CI/CD protégées et masquées dans GitLab, ne les codez jamais en dur dans .gitlab-ci.yml ou config.toml . Pour ajouter une variable : - Allez dans Paramètres > CI/CD > Variables . - Ajoutez une variable (par exemple, DEPLOY_TOKEN ) et définissez-la comme « Masquée » et éventuellement « Protégée ». Le masquage empêche la valeur d'apparaître dans les journaux de tâches. Les variables protégées ne sont transmises qu'aux tâches sur des branches ou des tags protégés. ### Éviter les secrets dans config.toml Le jeton d'enregistrement du runner et le jeton d'authentification sont dans config.toml . Assurez-vous que les permissions du fichier sont restrictives : sudo chmod 600 /etc/gitlab-runner/config.toml sudo chown root:root /etc/gitlab-runner/config.toml Si vous devez stocker d'autres secrets pour le runner (par exemple, les informations d'identification du registre Docker), utilisez des variables d'environnement ou des fichiers de configuration Docker avec des permissions restreintes. ### Utiliser des gestionnaires de secrets externes Pour des besoins avancés, intégrez avec Vault ou des gestionnaires de secrets cloud. GitLab prend en charge l'intégration Vault pour les tâches CI/CD. Le runner récupère les secrets au moment de l'exécution, ainsi ils n'apparaissent jamais dans la configuration du runner. Exemple de configuration Vault dans .gitlab-ci.yml : job: secrets: DATABASE_PASSWORD: vault: secret/data/production/db/password Cela nécessite de configurer Vault et d'authentifier le runner. ### Rotation des clés Faites régulièrement tourner les jetons d'enregistrement du runner et tous les secrets stockés. Pour réinitialiser le jeton d'authentification d'un runner : - Dans GitLab, allez dans les paramètres du runner. - Cliquez sur « Réinitialiser le jeton d'authentification ». - Mettez à jour le token dans config.toml avec la nouvelle valeur. Cela invalide tout jeton divulgué. ## Vérification et diagnostics Après le durcissement, vous devez vérifier que le runner fonctionne toujours et que les contrôles de sécurité sont efficaces. ### Exécuter un pipeline de test Créez un .gitlab-ci.yml simple dans un projet de test : test_job: script: - echo "Le runner fonctionne" - whoami - env | sort Poussez vers le projet et observez la tâche. La sortie de whoami vous indique l'utilisateur à l'intérieur du conteneur (par exemple, root pour les conteneurs Docker). Si vous attendiez un non-root, ajustez l'image Docker ou la configuration du runner. La sortie de env peut révéler des secrets. Assurez-vous que les variables masquées apparaissent comme [MASKED] . ### Vérifier les journaux du runner Les journaux du runner peuvent montrer des erreurs ou des problèmes de sécurité. Consultez les journaux : sudo journalctl -u gitlab-runner -f Recherchez des avertissements concernant les permissions, les échecs réseau ou les erreurs de configuration. ### Valider la sécurité du conteneur Docker Si vous utilisez l'exécuteur Docker, inspectez un conteneur de tâche en cours d'exécution pour confirmer les paramètres : docker inspect | jq '.[0].HostConfig.Privileged, .[0].HostConfig.CapDrop, .[0].HostConfig.CapAdd' La sortie attendue doit montrer false pour Privileged et les capacités appropriées. ### Exécuter des scanners de sécurité Utilisez des outils comme trivy pour scanner l'hôte du runner et les images Docker à la recherche de vulnérabilités : trivy fs / trivy image alpine:latest Traitez toutes les découvertes critiques. ### Tester le contrôle d'accès Essayez de déclencher une tâche depuis une branche non autorisée si vous utilisez des runners protégés. La tâche ne doit pas s'exécuter. Essayez également d'enregistrer un nouveau runner avec un compte non administrateur ; cela doit être refusé si l'enregistrement est restreint. ## Modes de défaillance et reprise Même avec une planification minutieuse, les choses peuvent casser. Soyez prêt à diagnostiquer et à récupérer. ### Erreur de syntaxe de configuration Si config.toml a une erreur de syntaxe, le runner ne démarre pas. Symptôme : systemctl status montre un échec, et les journaux affichent des erreurs d'analyse TOML. Récupération : sudo gitlab-runner verify Cela peut montrer l'erreur. Corrigez la syntaxe ou restaurez la sauvegarde : sudo cp /etc/gitlab-runner/config.toml.backup /etc/gitlab-runner/config.toml sudo systemctl restart gitlab-runner ### Le runner ne peut pas se connecter à GitLab Si les restrictions réseau bloquent l'accès, les tâches échouent avec des messages comme ERROR: Registering runner... failed ou Job failed: couldn't execute command . Vérifiez la connectivité : curl -v https://gitlab.example.com/api/v4/runners Si bloqué, ajustez les règles du pare-feu. ### Problèmes avec le démon Docker Si le runner ne peut pas tirer des images ou démarrer des conteneurs, vérifiez l'état de Docker : sudo systemctl status docker docker ps Assurez-vous que l'utilisateur du runner peut accéder à Docker si vous utilisez le socket. Si vous avez retiré le runner du groupe docker, mais que l'exécuteur Docker a toujours besoin d'un accès au socket, vous devrez peut-être utiliser un contexte Docker séparé ou exécuter le runner en tant qu'utilisateur avec les permissions appropriées. ### Tentative d'élévation de privilèges Si une tâche essaie d'utiliser le mode privilégié et échoue, c'est un bon signe. Si elle réussit de manière inattendue, vérifiez votre config.toml pour privileged = true et changez-le en false . ### Fuite de secrets Si un secret apparaît dans les journaux de tâches, immédiatement : - Révoquez le secret de tous les systèmes. - Générez une nouvelle valeur. - Mettez à jour la variable GitLab (assurez-vous que « Masquée » est cochée). - Enquêtez sur la raison de la fuite (par exemple, journalisation de débogage, echo $SECRET ). - Envisagez d'utiliser set -x uniquement dans des contextes sûrs. ### Reprise après échec du service Si le service du runner échoue après le durcissement du système (par exemple, ProtectSystem=strict ), assouplissez progressivement les paramètres du service. Par exemple, vous devrez peut-être autoriser les écritures dans certains répertoires : [Service] ReadWritePaths=/var/lib/gitlab-runner Puis rechargez et redémarrez. ## Pièges courants et comment les éviter De nombreux problèmes de sécurité proviennent de malentendus ou de raccourcis. Voici les erreurs les plus courantes. ### Exécuter des conteneurs Docker privilégiés Pourquoi cela arrive : Les développeurs activent souvent le mode privilégié pour résoudre des problèmes de permissions ou pour permettre Docker-in-Docker. Pourquoi c'est dangereux : Les conteneurs privilégiés peuvent accéder aux périphériques de l'hôte et échapper à l'isolation du conteneur. Comment l'éviter : Utilisez privileged = false et ajoutez uniquement les capacités nécessaires. Pour Docker-in-Docker, envisagez d'utiliser le service docker avec network_mode = "host" et un montage du socket du démon Docker, ou utilisez Kaniko pour construire des images sans démon. ### Utiliser l'exécuteur shell inutilement Pourquoi cela arrive : C'est le plus simple à configurer, mais il exécute les tâches directement sur l'hôte avec des privilèges élevés. Pourquoi c'est dangereux : Une tâche malveillante peut compromettre l'hôte. Comment l'éviter : Préférez les exécuteurs Docker ou Kubernetes. Si vous devez utiliser le shell, exécutez le runner en tant qu'utilisateur dédié avec des permissions minimales et utilisez un environnement propre. ### Laisser l'enregistrement ouvert par défaut Pourquoi cela arrive : Les paramètres par défaut peuvent permettre à toute personne ayant accès au projet d'enregistrer un runner. Pourquoi c'est dangereux : Un attaquant avec un accès de bas niveau peut enregistrer un runner qui exécute des tâches sur son infrastructure, volant potentiellement du code ou des secrets. Comment l'éviter : Restreignez l'enregistrement des runners aux administrateurs. ### Coder en dur les secrets dans .gitlab-ci.yml ou config.toml Pourquoi cela arrive : C'est rapide et facile pour les développeurs. Pourquoi c'est dangereux : Les secrets finissent dans le contrôle de version ou les fichiers de configuration qui peuvent être exposés. Comment l'éviter : Utilisez toujours les variables CI/CD de GitLab, masquées et protégées. ### Ignorer les mises à jour du runner Pourquoi cela arrive : Peur de casser des choses ou manque de temps. Pourquoi c'est dangereux : Les runners obsolètes ont des vulnérabilités connues. Comment l'éviter : Abonnez-vous aux annonces de sécurité de GitLab et planifiez des mises à jour régulières. Testez les mises à jour en préproduction. ### Permissions de fichiers trop permissives Pourquoi cela arrive : Chmod 777 pour résoudre les problèmes d'accès. Pourquoi c'est dangereux : N'importe qui sur le système peut lire les jetons. Comment l'éviter : Définissez des permissions minimales ( 600 pour la configuration, 700 pour les répertoires). ### Ne pas surveiller l'activité du runner Pourquoi cela arrive : Configurer et oublier. Pourquoi c'est dangereux : Les anomalies passent inaperçues. Comment l'éviter : Activez la journalisation, intégrez avec des outils de surveillance et définissez des alertes pour les échecs de tâches ou les activités inhabituelles. ## Liste de contrôle opérationnelle Cette liste de contrôle résume les étapes clés de durcissement et fournit un processus reproductible pour maintenir la sécurité. Attribuez un responsable à chaque élément et examinez périodiquement (par exemple, mensuellement ou trimestriellement).
ÉlémentActionVérificationResponsableFréquence de revue
Version du runnerVérifier gitlab-runner --versionLa version est la dernière stableIngénieur DevOps (Priya Shah)Mensuelle
Permissions du fichier de configurationsudo chmod 600 /etc/gitlab-runner/config.tomlls -l montre -rw-------Administrateur système (Alex Chen)Mensuelle
Mode privilégiéAssurer privileged = false dans config.tomlgrep privileged /etc/gitlab-runner/config.tomlIngénieur DevOpsMensuelle
Enregistrement du runnerRestreindre aux administrateurs dans les paramètres GitLabAucun non-admin ne peut enregistrerAdministrateur GitLab (Jordan Lee)Trimestrielle
SecretsTous les secrets dans les variables GitLab, masqués/protégésAucun secret dans le code ou les journauxResponsable sécurité (Sam Rivera)Mensuelle
Privilèges de l'utilisateur du runnerVérifier les groupes et l'accès sudogroups gitlab-runner et sudo -l -U gitlab-runner montrent un accès limitéAdministrateur systèmeMensuelle
Restrictions réseauLes règles de pare-feu limitent le trafic sortantufw status ne montre que les destinations autoriséesAdministrateur réseau (Casey Morgan)Trimestrielle
Sauvegarde et repriseLa sauvegarde de configuration existe et la restauration est testéeEffectuer un exercice de restauration en préproductionIngénieur DevOpsSemestrielle
SurveillanceLes journaux et métriques sont surveillésLes alertes se déclenchent lors d'événements de testSRE (Taylor Kim)Mensuelle
Responsables imputables : Chaque élément a un seul responsable nommé (par exemple, Priya Shah, ingénieur DevOps). Les responsables sont chargés d'exécuter l'action et de rendre compte de l'état lors de la réunion mensuelle de revue de sécurité. La réunion de revue garantit que les éléments ne sont pas oubliés et s'adapte aux nouvelles menaces. ## Conclusion Le durcissement de GitLab Runner est un processus continu, pas une tâche ponctuelle. En suivant les étapes de ce guide, vous réduisez le risque de fuite d'informations d'identification, d'exécution de code non autorisée et de compromission de l'infrastructure. Commencez par un inventaire des versions, verrouillez les configurations, appliquez des contrôles d'accès, gérez correctement les secrets et vérifiez tout avec des tests concrets. En cas de défaillance, ayez un plan de reprise prêt. Comme prochaine étape, choisissez un élément à faible risque de la liste de contrôle, mettez-le en œuvre et observez les résultats. Par exemple, définissez privileged = false sur un runner de test et exécutez un pipeline qui nécessitait auparavant des privilèges. Ajustez en conséquence. Puis progressez graduellement dans le reste. Révisez votre posture de sécurité mensuellement et restez informé des nouvelles fonctionnalités et vulnérabilités de GitLab Runner. Un flux de travail de sécurité fiable rend les échecs visibles, protège les valeurs sensibles et définit la vérification de la reprise avant qu'un incident ne force la décision.