Date de publication : 8 juin 2026
Temps de lecture : 14 min
Découvrez comment l'équipe Signals Engineering de GitLab a conçu le framework WATCH pour valider en continu son pipeline de surveillance de sécurité.

Lorsqu'il s'agit de maintenir un système d'alerte sain au sein de votre centre des opérations de sécurité (SOC), le réglage des faux positifs ne suffit pas à lui seul. Un aspect souvent négligé de ce système est de s'assurer que les détections critiques, celles qui se déclenchent rarement, n'ont pas tout simplement cessé de fonctionner sans que personne ne s'en aperçoive.
Chez GitLab, l'équipe Signals Engineering teste les détections en simulant des comportements malveillants réels sur une infrastructure qui nous appartient, afin de valider le fonctionnement de bout en bout de nos détections : de la source des logs à l'ingestion, en passant par le système de gestion des informations et des événements de sécurité (SIEM), jusqu'au routage des alertes via notre système Security Orchestration, Automation and Response (SOAR). C'est l'approche adoptée par les outils commerciaux de simulation de brèches et d'attaques, mais ces solutions sont coûteuses, génériques et inadaptées à notre pile de détection spécifique. Nous avons donc construit notre propre framework entièrement automatisé, que nous avons baptisé WATCH (Weekly Attack Testing for Continuous Health).
Dans cet article, vous découvrirez pourquoi nous avons développé ce framework, comment il fonctionne et comment l'utiliser dans votre propre environnement.
Entre les modifications de schéma de logs, les mises à jour du SIEM et les erreurs de configuration des pipelines, il existe une multitude de façons pour que vos détections échouent en silence, mais une seule pour qu’elles se déclenchent comme prévu. Face à cette situation, une conclusion s'impose : il nous faut déclencher d'anciennes détections. Cette solution soulève cependant les questions suivantes : « Comment déclencher concrètement des détections ? » et « À quelle fréquence ? »
Une première approche consiste à réintroduire dans votre SIEM des logs qui simulent un comportement malveillant, puis à vérifier si votre règle de détection identifie le faux incident et déclenche une alerte. Cette approche, en plus de ne pas prouver le fonctionnement de la détection en conditions réelles, ne valide pas l'une des étapes les plus sujettes aux erreurs du cycle de vie des alertes : l'ingestion des logs (c'est-à-dire de la source du log au SIEM).
Nous avons précédemment décrit comment notre système GitLab Universal Automated Response and Detection (GUARD) automatise la création et le déploiement des détections via un pipeline de détections en tant que code (DaC), ainsi que le routage et le classement des alertes via notre SOAR. Nos pipelines DaC résolvent le problème de la validation du déploiement d'une détection sans erreur, mais ne répondent pas à la question de savoir si cette détection se déclenchera réellement lorsque le comportement ciblé se produira en conditions réelles.
Le framework WATCH comble cette lacune : il s'agit de la couche de validation continue qui confirme que nos détections fonctionnent correctement.
À un niveau global, le framework WATCH fonctionne en exécutant des simulations d'attaques scriptées dans notre environnement de préproduction, puis en vérifiant que les alertes attendues se propagent à travers l'ensemble de notre pile de surveillance de sécurité : le SIEM pour les règles de détection, le SOAR pour le routage des alertes, et enfin les tableaux de bord utilisés par notre équipe pour surveiller l'état des détections.
Le cycle de vie d'un test WATCH se déroule comme suit :
WATCH s'appuie sur GitLab CI/CD et l'utilise comme colonne vertébrale d'orchestration à travers trois étapes de pipeline.
L'étape schedule_pipelines s'exécute chaque semaine et gère la répartition des tests. Elle repère tous les tests actifs, les regroupe par lots et crée des pipelines planifiés configurés pour s'exécuter à des moments aléatoires au cours de la semaine. Chaque pipeline planifié reçoit une variable TESTS_TO_RUN qui précise les tests à exécuter.
L'étape run_tests est celle où la simulation d'attaque a lieu. Elle exécute les tests assignés au pipeline en cours, enregistre les statistiques d'exécution dans detection_status.json et consigne les identifiants des enregistrements SOAR pour permettre la corrélation des alertes en aval.
L'étape pages gère la vérification et le reporting. Elle interroge notre SOAR pour confirmer que les alertes ont été générées et correctement acheminées, met à jour les métadonnées de détection avec les résultats de vérification et déploie le tableau de bord GitLab Pages avec les derniers résultats de tests.
Voici un exemple de fichier de configuration GitLab CI/CD gitlab-ci.yml pour le pipeline WATCH :
spec:
inputs:
weekly_scheduling:
type: boolean
default: false
description: "Enable weekly scheduling of detection tests."
update_pages:
type: boolean
default: false
description: "For triggering the update of GitLab Pages dashboard."
---
# Specify the Docker image to use for the job
image: python:3.12
stages:
- schedule_pipelines
- run_tests
- pages
# Job to manage scheduled pipelines (runs when weekly_scheduling input is true)
manage_scheduled_pipelines:
stage: schedule_pipelines
script:
- pip install -r requirements.txt
- python scripts/manage_scheduled_pipelines.py
rules:
- if: $TESTS_TO_RUN == null && $CI_PIPELINE_SOURCE == "schedule" && [[ inputs.weekly_scheduling ]] == true
when: on_success
- when: never
# Job to run detection tests, save tines_record_id to detection_status.json, and commit
run_detection_tests:
stage: run_tests
script:
- pip install -r requirements.txt
- python main.py --prod --save-stats --scheduled-tests
rules:
- if: $TESTS_TO_RUN
when: on_success
- when: never
# Job to verify alerts, update detection_status.json, commit, and deploy pages
pages:
stage: pages
script:
- pip install -r requirements.txt
- python scripts/verify_and_update_detections.py --tines-api-key ${TINES_API_KEY}
- mkdir -p public/data
- cp detection_status.json public/data/
- cp -r static/* public/
pages: true # Required for GitLab 17.9+ to trigger Pages deployment
artifacts:
paths:
- public
rules:
- if: $TESTS_TO_RUN == null && [[ inputs.update_pages ]] == true
when: on_success
- when: never
L'une des priorités de conception de WATCH était de faciliter l'ajout de nouveaux tests par n'importe quel membre de l'équipe Signals Engineering ou SIRT. Le framework fournit une classe abstraite BaseSecurityTest qui prend en charge toutes les tâches répétitives (génération de l'identifiant de test, gestion de l'identité de l'acteur, coordination avec le SOAR) de sorte que les auteurs de tests n'ont qu'à se concentrer sur trois aspects : la préparation de l'environnement de test, l'exécution du comportement malveillant simulé et le nettoyage post-test.
class BaseSecurityTest(ABC):
def __init__(self, config = {}, test_id: Optional[str] = None):
self.test_id = test_id or str(uuid.uuid4())
self.test_name = self.__class__.__name__
self.expected_detections = {}
self.actor_id = config.get('gitlab', {}).get(
'default_actor_id',
"sirt_detection_test_user_" + self.test_id[:8]
)
self.isActive = True
self.test_run_time = 300
self.config = config
@abstractmethod
def setup(self) -> bool:
"""Prepare test environment and resources"""
@abstractmethod
def execute(self) -> Dict[str, Any]:
"""Execute the malicious behavior simulation"""
@abstractmethod
def cleanup(self) -> bool:
"""Clean up test environment and resources"""
L'élément de configuration clé est le dictionnaire expected_detections, qui associe les noms de règles SIEM des détections attendues à l'identité de l'acteur et à l'heure d'arrivée prévue de l'alerte. Un nouveau test est simplement un fichier Python dans le répertoire tests/ qui hérite de BaseSecurityTest, définit son comportement simulé et déclare les détections qu'il prévoit de déclencher. Le runner de tests le détecte automatiquement lors de la prochaine exécution planifiée.
Cette interface à faible friction est essentielle, car les tests de détection ne fonctionnent en tant que pratique que si l'équipe rédige réellement des tests. Si l'ajout d'un test nécessite de comprendre l'intégralité des mécanismes internes du pipeline, personne ne le fera. Le contrat simple consistant à implémenter setup, execute et cleanup, et à déclarer les détections attendues, fait également des tests WATCH d'excellents candidats pour GitLab Duo, l'assistant d'IA de GitLab. Il vous suffit d'indiquer à GitLab Duo la classe de base et un prompt tel que « Crée-moi un test qui clone un grand nombre de projets à partir d'un groupe cible » ou « Crée-moi un test qui accède à toutes les variables CI de ce projet via GraphQL », voire « Renomme tous ces projets pour utiliser le même schéma de nommage ». GitLab Duo peut alors générer un test WATCH fonctionnel qui s'intègre directement au framework et simplifie encore davantage l'accessibilité. Un ingénieur qui souhaite tester une détection peut rapidement passer de l'idée à un test opérationnel, car GitLab Duo prend en charge l'essentiel de l'implémentation.
Astuce : pour renforcer l'efficacité de GitLab Duo, nous avons utilisé l'agent Skills, qui est idéal pour définir des normes et des procédures pour les tâches récurrentes comme la rédaction de tests. Dans le répertoire de notre projet se trouve un dossier skills/WATCH-test-creator contenant un fichier SKILL.md qui décrit les caractéristiques d'un bon test, les fonctions utilitaires disponibles et la finalité du projet. Ce fichier est lu immédiatement après la saisie d'un prompt comme ceux mentionnés ci-dessus, ce qui évite de devoir rappeler constamment à GitLab Duo le contexte de travail et la méthodologie à suivre. Surtout, les résultats obtenus sont cohérents et de meilleure qualité. Voici un extrait de ce fichier :
---
name: WATCH-test-creator
description: Create WATCH (Orchestrated Offensive Penetration Simulator) security detection tests that simulate malicious behavior on GitLab infrastructure to validate SIEM detection rules and alerting pipelines.
---
## WATCH Test Creator
You are an expert at writing security detection tests for the WATCH framework. WATCH tests simulate malicious activities on GitLab-owned infrastructure to verify that the SecOps security monitoring stack (Elastic SIEM, Tines SOAR, alerting rules) properly detects and responds to threats.
### Architecture Overview
```
Project Root
├── core/
│ ├── base_test.py # Abstract base class all tests inherit from
│ ├── test_runner.py # Auto-discovers and executes tests
│ └── webhook_manager.py # Tines/SOAR notification integration
├── tests/
│ ├── gitlab/ # GitLab-specific detection tests
│ └── gcp/ # GCP-specific detection tests
├── utils/
│ ├── gitlab_helper.py # GitLab API wrapper (users, projects, tokens, webhooks, OAuth)
│ └── crypto_utils.py # Password generation utility
├── config/
│ ├── settings.py # Config loader (reads YAML + GITLAB_ADMIN_PAT env var)
│ └── environments/
│ ├── dev.yaml # Local GDK config
│ └── prod.yaml # Production staging.gitlab.com config
├── main.py # Entry point with CLI args
└── detection_status.json # Test results and detection metadata
```

WATCH déploie également deux tableaux de bord interactifs via GitLab Pages qui offrent à l'équipe une visibilité en temps réel sur l'état des détections.
Ces tableaux de bord ont remplacé un processus auparavant manuel qui consistait à consulter les logs des pipelines et les requêtes SIEM pour déterminer si nos détections étaient opérationnelles.
Comme le reste de GUARD, WATCH s'appuie fortement sur GitLab en tant que plateforme :
La mise en place du framework WATCH a transformé la relation de notre équipe avec la qualité des détections, passant d'une posture réactive à une posture proactive. Avant WATCH, une détection défaillante ne se manifestait que lors d'un incident, lorsque l'alerte attendue était absente, soit le pire moment possible pour découvrir une lacune. Désormais, nous recevons des mises à jour régulières sur l'état de santé de nos détections et savons quand elles cessent de fonctionner avant qu'un problème réel ne survienne. C'est la garantie que les nouvelles détections développées ne seront pas défaillantes puis oubliées.
Un autre avantage de WATCH est l'enregistrement des tactiques, techniques et procédures (TTP) utilisées par notre red team lors d'opérations flash. Une fois les détections implémentées et l'analyse rétrospective d'une opération de test de pénétration réalisée, WATCH peut être utilisé pour rejouer les TTP utilisées afin de valider ces détections. En substance, WATCH transforme les tests atomiques de détection en TTP réutilisables.
Si vous gérez un SOC et que vous comptez sur les détections SIEM pour identifier les menaces, la question n'est pas de savoir si vos détections échoueront, mais si vous le saurez quand cela arrivera. Vous n'avez pas besoin d'une plateforme commerciale de simulation de brèches et d'attaques pour commencer à répondre à cette question. Un environnement sandbox, un pipeline CI/CD et un framework de scripts de simulation d'attaques sont d'excellents points de départ.
Commencez à construire votre propre framework de tests de détection en essayant gratuitement GitLab Ultimate.
Laboratoires de sécurité

Laboratoires de sécurité

Laboratoires de sécurité

Cet article de blog vous a plu ? Vous avez des questions ou des retours à nous faire ? Donnez votre avis en créant un nouveau sujet sur le forum de la communauté GitLab.
Faites-nous part de vos commentaires