La question d’un auditeur n’est jamais “est-ce que vous êtes sécurisés ?” mais “prouvez-le”. GitLab enregistre des centaines de types d’événements d’audit : qui a modifié une branche protégée, qui a approuvé un déploiement, qui a changé les permissions d’un runner. Ce guide vous montre comment exploiter ces mécanismes pour répondre aux exigences SOC 2, ISO 27001 ou NIS2 avec des données concrètes.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »À la fin de ce guide, vous saurez :
- Consulter les audit events de GitLab (projet, groupe, instance)
- Requêter l’API d’audit pour extraire des événements précis
- Mettre en place un compliance framework pour appliquer des politiques par projet
- Configurer des compliance pipelines pour forcer l’exécution de jobs de sécurité
- Streamer les événements vers un SIEM externe (Splunk, ELK, Datadog)
Dans quel contexte ?
Section intitulée « Dans quel contexte ? »L’audit et la conformité deviennent nécessaires quand :
- Un auditeur externe (SOC 2, ISO 27001) demande la preuve que les déploiements suivent un processus de validation
- Votre organisation est soumise à NIS2 et doit démontrer la traçabilité de sa chaîne logicielle
- Un incident de sécurité survient et vous devez reconstituer qui a fait quoi, quand
- Vous gérez des dizaines de projets et devez garantir que chacun applique les mêmes règles de sécurité
- Des développeurs contournent les contrôles (désactivation d’une branche protégée, suppression d’une approbation) et vous devez le détecter
Audit events : ce que GitLab enregistre
Section intitulée « Audit events : ce que GitLab enregistre »Les trois niveaux d’audit
Section intitulée « Les trois niveaux d’audit »GitLab enregistre des événements à trois niveaux :
| Niveau | Visibilité | Exemples d’événements |
|---|---|---|
| Projet | Maintainer+ | MR mergée, pipeline lancé, variable modifiée, branche protégée changée |
| Groupe | Owner | Membre ajouté/retiré, permission changée, runner partagé configuré |
| Instance | Admin | Utilisateur créé, 2FA désactivé, paramètre global modifié |
Consulter les audit events
Section intitulée « Consulter les audit events »Projet : Settings → General → Audit events (GitLab Premium+).
Vous voyez un journal chronologique avec l’auteur, l’action et la cible.
# Audit events d'un projet (30 derniers jours)curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \ "$GITLAB_URL/api/v4/projects/$PROJECT_ID/audit_events?created_after=2026-03-16"Résultat :
[ { "id": 1234, "author_id": 42, "entity_id": 7, "entity_type": "Project", "details": { "change": "protected_branch", "from": "", "to": "main", "author_name": "Alice Martin", "target_details": "main", "custom_message": "Protected branch main: allowed to push changed from Developers + Maintainers to No one" }, "created_at": "2026-03-20T14:32:00Z" }]Événements critiques à surveiller
Section intitulée « Événements critiques à surveiller »| Événement | Pourquoi le surveiller | Catégorie |
|---|---|---|
protected_branch_created / removed | Quelqu’un a modifié la politique de branches | Contrôle d’accès |
approval_rule_created / deleted | Les règles d’approbation MR ont changé | Processus de validation |
environment_protected / unprotected | L’environnement de production a perdu sa protection | Déploiement |
variable_created / updated / deleted | Un secret CI a été modifié | Secrets |
runner_registration | Un nouveau runner a été enregistré | Infrastructure |
member_added / removed | Les permissions d’accès au projet ont changé | Contrôle d’accès |
deploy_key_added | Une clé de déploiement a été ajoutée | Accès externe |
merge_request_approved | Une MR a été approuvée (par qui ?) | Traçabilité |
pipeline_schedule_created | Un pipeline planifié a été créé | Automatisation |
Requêter l’API d’audit
Section intitulée « Requêter l’API d’audit »Questions typiques d’un auditeur
Section intitulée « Questions typiques d’un auditeur »Les auditeurs posent des questions précises. Voici comment y répondre avec l’API :
“Qui a modifié les branches protégées ce mois-ci ?”
curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \ "$GITLAB_URL/api/v4/projects/$PROJECT_ID/audit_events?created_after=2026-03-01" \ | jq '[.[] | select(.details.change == "protected_branch")] | .[] | {date: .created_at, author: .details.author_name, action: .details.custom_message}'“Qui a approuvé les MR déployées en production ?”
# Lister les MR mergées sur main ce moiscurl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \ "$GITLAB_URL/api/v4/projects/$PROJECT_ID/merge_requests?state=merged&target_branch=main&updated_after=2026-03-01" \ | jq '.[] | {iid: .iid, title: .title, merged_by: .merged_by.name, approved_by: [.approved_by[].user.name]}'“Y a-t-il eu des déploiements pendant le freeze ?”
curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \ "$GITLAB_URL/api/v4/projects/$PROJECT_ID/deployments?environment=production&updated_after=2026-03-28&updated_before=2026-04-02" \ | jq '.[] | {id: .id, created_at: .created_at, status: .status, deployed_by: .deployable.user.name}'Script d’audit automatisé
Section intitulée « Script d’audit automatisé »Pour générer un rapport d’audit régulier :
#!/usr/bin/env bash# audit-report.sh — Rapport d'audit mensuel pour un projet GitLabset -euo pipefail
PROJECT_ID="${1:?Usage: $0 <project_id>}"SINCE=$(date -d "30 days ago" +%Y-%m-%d)API="$GITLAB_URL/api/v4/projects/$PROJECT_ID"AUTH="PRIVATE-TOKEN: $GITLAB_TOKEN"
echo "=== Rapport d'audit — Projet $PROJECT_ID — depuis $SINCE ==="
echo ""echo "--- Modifications de branches protégées ---"curl -s -H "$AUTH" "$API/audit_events?created_after=$SINCE" \ | jq -r '.[] | select(.details.change == "protected_branch") | "\(.created_at) | \(.details.author_name) | \(.details.custom_message)"'
echo ""echo "--- Modifications de variables CI ---"curl -s -H "$AUTH" "$API/audit_events?created_after=$SINCE" \ | jq -r '.[] | select(.details.change == "ci_variable") | "\(.created_at) | \(.details.author_name) | \(.details.custom_message)"'
echo ""echo "--- Déploiements en production ---"curl -s -H "$AUTH" "$API/deployments?environment=production&updated_after=$SINCE" \ | jq -r '.[] | "\(.created_at) | \(.deployable.user.name // "système") | \(.status) | ref:\(.ref)"'
echo ""echo "--- MR mergées sur main ---"curl -s -H "$AUTH" "$API/merge_requests?state=merged&target_branch=main&updated_after=$SINCE" \ | jq -r '.[] | "!\(.iid) | \(.merged_at) | \(.merged_by.name) | \(.title)"'Compliance frameworks
Section intitulée « Compliance frameworks »Le mécanisme
Section intitulée « Le mécanisme »Un compliance framework est un label appliqué à un projet pour indiquer qu’il est soumis à une politique spécifique. Il sert deux objectifs :
- Visibilité : identifier rapidement quels projets sont soumis à quelle réglementation
- Enforcement : attacher un compliance pipeline qui s’exécute automatiquement
Créer un compliance framework
Section intitulée « Créer un compliance framework »-
Créer le framework au niveau du groupe
Group → Settings → General → Compliance frameworks → New framework.
Champ Exemple Name SOC 2 — Production Description Projets soumis aux contrôles SOC 2 Type II Color #FF0000 Compliance pipeline URL du fichier .gitlab-ci.ymlde conformité -
Attacher le framework à un projet
Project → Settings → General → Compliance framework → sélectionner le framework.
Le label apparaît sur la page du projet et dans les listes de projets.
-
Vérifier via l’API
Fenêtre de terminal curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \"$GITLAB_URL/api/v4/projects/$PROJECT_ID" \| jq '.compliance_frameworks'Résultat attendu :
["SOC 2 — Production"]
Compliance pipelines
Section intitulée « Compliance pipelines »Le problème
Section intitulée « Le problème »Un développeur peut modifier ou supprimer les jobs de sécurité dans son .gitlab-ci.yml. Les includes partagés peuvent être commentés. Rien ne garantit que le scan de vulnérabilités s’exécute réellement.
La solution : compliance pipeline
Section intitulée « La solution : compliance pipeline »Un compliance pipeline est un .gitlab-ci.yml maintenu par l’équipe sécurité, exécuté automatiquement sur tout projet attaché à un compliance framework. Le développeur ne peut pas le modifier ni le désactiver.
stages: - compliance-check - .pre - build - test - deploy - .post - compliance-report
# Ce job s'exécute AVANT le pipeline du développeurcompliance-secret-scan: stage: compliance-check image: name: zricethezav/gitleaks:latest entrypoint: [""] script: - gitleaks detect --source . --verbose --exit-code 1 allow_failure: false
# Ce job s'exécute APRÈS le pipeline du développeurcompliance-report: stage: compliance-report image: alpine:3.20 script: - echo "Pipeline $CI_PIPELINE_ID — Projet $CI_PROJECT_PATH" - echo "Commit $CI_COMMIT_SHA — Auteur $GITLAB_USER_NAME" - echo "Branche $CI_COMMIT_BRANCH — Ref $CI_COMMIT_REF_NAME" - echo "Compliance check passed at $(date -u)" artifacts: paths: - compliance-*.log expire_in: 1 yearComment ça fonctionne
Section intitulée « Comment ça fonctionne »Le compliance pipeline remplace le pipeline du projet. Il utilise include: pour incorporer le .gitlab-ci.yml du développeur entre ses propres stages :
include: - project: '$CI_PROJECT_PATH' ref: '$CI_COMMIT_SHA' file: '.gitlab-ci.yml'
stages: - compliance-check - build - test - deploy - compliance-report
compliance-secret-scan: stage: compliance-check # ... (comme ci-dessus)
compliance-report: stage: compliance-report # ... (comme ci-dessus)Le développeur garde la main sur ses stages build, test, deploy. L’équipe sécurité contrôle les stages compliance-check et compliance-report.
Streaming audit events
Section intitulée « Streaming audit events »Envoyer les événements vers un SIEM
Section intitulée « Envoyer les événements vers un SIEM »Pour une surveillance continue, GitLab peut streamer les audit events vers une destination externe :
-
Configurer la destination
Group → Settings → General → Audit events → Streaming → Add streaming destination.
Champ Valeur Destination URL https://siem.example.com/api/gitlab-eventsVerification token Token partagé pour authentifier les requêtes -
Format des événements
GitLab envoie un POST HTTP avec un payload JSON pour chaque événement :
{"id": 5678,"author_id": 42,"entity_id": 7,"entity_type": "Project","event_type": "audit_events","details": {"change": "protected_branch","from": "Developers + Maintainers","to": "No one","author_name": "Alice Martin","target_details": "main"},"created_at": "2026-04-15T10:30:00Z"} -
Vérifier la réception
Utilisez un endpoint de test pour valider le flux :
Fenêtre de terminal # Lister les destinations de streamingcurl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \"$GITLAB_URL/api/v4/groups/$GROUP_ID/audit_events/streaming/destinations"
Destinations courantes
Section intitulée « Destinations courantes »| SIEM | Méthode | Configuration |
|---|---|---|
| Splunk | HTTP Event Collector | URL HEC + token |
| ELK / OpenSearch | Endpoint HTTP | Logstash HTTP input ou direct Elasticsearch |
| Datadog | HTTP Log endpoint | https://http-intake.logs.datadoghq.eu/api/v2/logs + API key |
| Google Chronicle | Webhook | Ingestion API endpoint |
Tableau de bord de conformité
Section intitulée « Tableau de bord de conformité »Construire un rapport de conformité projet
Section intitulée « Construire un rapport de conformité projet »Combinez les données d’audit avec les informations de configuration pour produire un score de conformité :
#!/usr/bin/env bash# compliance-score.sh — Score de conformité d'un projet GitLabset -euo pipefail
PROJECT_ID="${1:?Usage: $0 <project_id>}"API="$GITLAB_URL/api/v4/projects/$PROJECT_ID"AUTH="PRIVATE-TOKEN: $GITLAB_TOKEN"score=0total=0
check() { local label="$1" result="$2" total=$((total + 1)) if [[ "$result" == "true" ]]; then score=$((score + 1)) echo " [OK] $label" else echo " [KO] $label" fi}
echo "=== Compliance score — Projet $PROJECT_ID ==="
# Branche main protégée ?main_protected=$(curl -s -H "$AUTH" "$API/protected_branches" \ | jq 'any(.[]; .name == "main")')check "Branche main protégée" "$main_protected"
# Force push interdit ?no_force=$(curl -s -H "$AUTH" "$API/protected_branches" \ | jq '[.[] | select(.name == "main")] | .[0].allow_force_push == false')check "Force push interdit sur main" "$no_force"
# Tags protégés ?tags_protected=$(curl -s -H "$AUTH" "$API/protected_tags" \ | jq 'length > 0')check "Tags protégés configurés" "$tags_protected"
# MR obligatoire sur main ?no_push=$(curl -s -H "$AUTH" "$API/protected_branches" \ | jq '[.[] | select(.name == "main")] | .[0].push_access_levels | any(.[]; .access_level == 0)')check "Push direct interdit sur main" "$no_push"
# Approbation MR requise ?approvals=$(curl -s -H "$AUTH" "$API/approval_rules" \ | jq 'any(.[]; .approvals_required > 0)')check "Approbation MR requise" "$approvals"
# Pipeline actif ?has_pipeline=$(curl -s -H "$AUTH" "$API/pipelines?per_page=1&status=success" \ | jq 'length > 0')check "Pipeline CI actif" "$has_pipeline"
echo ""echo "Score : $score / $total"Résultat attendu :
=== Compliance score — Projet 42 === [OK] Branche main protégée [OK] Force push interdit sur main [KO] Tags protégés configurés [OK] Push direct interdit sur main [KO] Approbation MR requise [OK] Pipeline CI actif
Score : 4 / 6Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Correction |
|---|---|---|
Audit events vides (API retourne []) | Tier CE sans Premium | Mettre à niveau ou utiliser l’API MR/deployments comme alternative |
| Compliance framework non disponible | GitLab Ultimate requis | Utiliser des topics + includes partagés comme alternative |
| Streaming : pas de réception côté SIEM | URL incorrecte ou token invalide | Tester avec curl direct, vérifier les logs SIEM |
| Compliance pipeline ne se déclenche pas | Framework non attaché au projet | Vérifier Settings → General → Compliance framework |
Script audit-report.sh : jq: error | Pas d’événements pour le filtre | Ajouter // empty au filtre jq pour gérer les résultats vides |
403 Forbidden sur /audit_events | Token sans droits admin ou Owner | Utiliser un token Maintainer pour les events projet, Owner pour groupe |
| Événements manquants dans le journal | Rétention par défaut limitée | Configurer la rétention dans Admin → Settings (instance) |
À retenir
Section intitulée « À retenir »L’audit et la conformité dans GitLab CI reposent sur cinq principes :
- Tout est enregistré : GitLab trace les modifications de branches protégées, de variables, de permissions, de runners. Ces événements sont votre source de vérité pour répondre aux auditeurs.
- L’API est votre outil d’investigation : l’interface montre un journal, l’API permet des requêtes ciblées. Automatisez les rapports avec des scripts pour ne pas dépendre d’une consultation manuelle.
- Les compliance frameworks imposent des politiques : attacher un framework à un projet garantit que le compliance pipeline s’exécute, sans dépendre de la bonne volonté du développeur (GitLab Ultimate).
- Le streaming transforme l’audit en surveillance : envoyer les événements vers un SIEM permet de détecter les anomalies en temps réel, pas lors de l’audit annuel.
- La conformité se mesure : un score de conformité par projet, calculé automatiquement, permet d’identifier les projets à risque avant l’auditeur.
- Audit events — GitLab Docs
- Audit events API — GitLab Docs
- Compliance frameworks — GitLab Docs
- Compliance pipelines — GitLab Docs
- Audit event streaming — GitLab Docs
- SOC 2 compliance with GitLab — GitLab
Testez vos connaissances
Section intitulée « Testez vos connaissances »Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications