Pourquoi la sécurité de GitLab CI est essentielle
Les pipelines GitLab CI/CD sont puissants — mais qui dit puissance dit risque. Une variable mal configurée peut exposer des secrets. Un runner non restreint peut exécuter du code malveillant. Un environnement non protégé peut permettre à un développeur junior de déployer directement en production. Ce cheat sheet vous fournit du YAML prêt à copier-coller pour chaque contrôle de sécurité critique de GitLab CI, des variables protégées à la fédération OIDC.
Ajoutez cette page à vos favoris. Utilisez-la comme référence à chaque fois que vous configurez un nouveau projet ou auditez un projet existant.
1. Variables protégées, masquées et cachées
Les variables CI/CD de GitLab contrôlent la manière dont les secrets circulent dans vos pipelines. Une mauvaise configuration est la cause numéro un des fuites de credentials en CI/CD. Chaque valeur sensible devrait être protégée (disponible uniquement sur les branches/tags protégés), masquée (cachée des logs de jobs) et, lorsque c’est possible, cachée (invisible dans l’interface utilisateur après création).
Définir des variables via l’API
# Créer une variable protégée + masquée via l'API GitLab
curl --request POST \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/variables" \
--form "key=AWS_SECRET_ACCESS_KEY" \
--form "value=$MY_SECRET" \
--form "protected=true" \
--form "masked=true" \
--form "variable_type=env_var"
Utiliser les variables dans .gitlab-ci.yml
variables:
# Les variables de groupe ou de projet sont injectées automatiquement.
# Les variables de type fichier sont écrites dans un chemin temporaire.
DEPLOY_TOKEN:
description: "Token pour le déploiement en production"
value: "" # Intentionnellement vide — à définir dans CI/CD Settings
deploy_production:
stage: deploy
script:
- echo "Déploiement avec un token masqué..."
- ./deploy.sh --token "$DEPLOY_TOKEN"
rules:
- if: $CI_COMMIT_BRANCH == "main"
environment:
name: production
Règles clés :
- Ne codez jamais les secrets en dur dans
.gitlab-ci.yml— utilisez toujours les paramètres de variables CI/CD. - Définissez
protected=truepour que les secrets ne soient disponibles que sur les branches protégées. - Définissez
masked=truepour que les valeurs soient masquées dans les logs de jobs. - Utilisez des variables de groupe pour les secrets partagés entre projets (par ex., credentials cloud).
2. Types de runners et restriction de portée
Les runners exécutent vos jobs CI/CD. Si n’importe quel runner peut récupérer n’importe quel job, une merge request malveillante pourrait exfiltrer des secrets depuis un runner de production. Une restriction de portée adéquate est essentielle.
Enregistrement d’un runner avec des tags et une protection
# Enregistrer un runner limité aux branches protégées uniquement
gitlab-runner register \
--non-interactive \
--url "https://gitlab.example.com" \
--token "$RUNNER_REG_TOKEN" \
--executor docker \
--docker-image alpine:latest \
--tag-list "production,protected" \
--access-level ref_protected
Restreindre les jobs à des runners spécifiques
# .gitlab-ci.yml — s'assurer que les jobs de production ne s'exécutent que sur des runners protégés
deploy_production:
stage: deploy
tags:
- production
- protected
script:
- kubectl apply -f k8s/production/
rules:
- if: $CI_COMMIT_BRANCH == "main"
environment:
name: production
# Les jobs de développement utilisent un runner séparé et non privilégié
test:
stage: test
tags:
- shared
- development
script:
- pytest tests/
Bonnes pratiques :
- Utilisez
--access-level ref_protectedpour restreindre les runners aux branches et tags protégés. - Utilisez des runners spécifiques au projet pour les charges de travail sensibles — ne partagez jamais les runners de production entre des projets sans lien.
- Préférez les runners éphémères (exécuteurs Docker, Kubernetes) afin que l’environnement soit détruit après chaque job.
- Désactivez les shared runners sur les projets qui gèrent des déploiements sensibles.
3. Environnements protégés avec approbations
Les environnements protégés ajoutent une validation humaine avant les déploiements. C’est votre dernière ligne de défense contre les modifications non autorisées en production.
Configuration des environnements dans .gitlab-ci.yml
# .gitlab-ci.yml — déploiement avec protection de l'environnement
deploy_staging:
stage: deploy
script:
- ./deploy.sh staging
environment:
name: staging
url: https://staging.example.com
rules:
- if: $CI_COMMIT_BRANCH == "main"
deploy_production:
stage: deploy
script:
- ./deploy.sh production
environment:
name: production
url: https://example.com
deployment_tier: production
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: manual
allow_failure: false
Configurer les règles d’approbation via l’API
# Protéger l'environnement de production avec des approbations obligatoires
curl --request POST \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/protected_environments" \
--data '{"name": "production", "deploy_access_levels": [{"group_id": 9899826}], "required_approval_count": 2, "approval_rules": [{"group_id": 9899826, "required_approvals": 2}]}'
Configurez cela dans Settings > CI/CD > Protected Environments dans l’interface GitLab. Exigez au minimum deux approbations pour les déploiements en production. Restreignez l’accès au déploiement à des groupes ou utilisateurs spécifiques — jamais « All maintainers ».
4. Restriction de portée du CI_JOB_TOKEN
CI_JOB_TOKEN est un token automatique que GitLab injecte dans chaque job. Par défaut, il peut accéder à d’autres projets de votre groupe — un risque sérieux de mouvement latéral. Depuis GitLab 16.0, vous devez restreindre sa portée.
Restreindre l’accès du token
# Vérifier la portée d'accès actuelle du CI_JOB_TOKEN
curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/job_token_scope"
# Limiter le CI_JOB_TOKEN à l'accès à des projets spécifiques uniquement
curl --request PATCH \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/job_token_scope" \
--data '{"enabled": true}'
# Ajouter un projet à la liste d'autorisation
curl --request POST \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/job_token_scope/allowlist" \
--data '{"target_project_id": 12345}'
Utiliser CI_JOB_TOKEN de manière sécurisée dans les pipelines
# .gitlab-ci.yml — utiliser CI_JOB_TOKEN pour des déclenchements cross-project
trigger_deploy:
stage: deploy
trigger:
project: my-group/deploy-project
branch: main
strategy: depend
# CI_JOB_TOKEN est utilisé automatiquement pour le déclenchement.
# Le projet cible doit autoriser le token de ce projet.
Règles clés : Activez la limitation de portée du CI/CD job token sur chaque projet. N’autorisez que les projets spécifiques qui ont véritablement besoin d’un accès cross-project. Auditez les listes d’autorisation chaque trimestre.
5. id_tokens OIDC pour AWS et GCP
La fédération OIDC élimine totalement les credentials cloud à longue durée de vie de vos variables CI/CD. GitLab émet un JWT à courte durée de vie, et votre fournisseur cloud l’échange contre des credentials temporaires. C’est le standard de référence pour l’authentification cloud dans les pipelines.
Fédération OIDC avec AWS
# .gitlab-ci.yml — authentification OIDC avec AWS
deploy_aws:
stage: deploy
image: amazon/aws-cli:latest
id_tokens:
GITLAB_OIDC_TOKEN:
aud: https://gitlab.example.com
variables:
ROLE_ARN: arn:aws:iam::123456789012:role/gitlab-ci-deploy
script:
- >
export $(printf "AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s AWS_SESSION_TOKEN=%s"
$(aws sts assume-role-with-web-identity
--role-arn $ROLE_ARN
--role-session-name "GitLabCI-${CI_PROJECT_ID}-${CI_PIPELINE_ID}"
--web-identity-token "$GITLAB_OIDC_TOKEN"
--duration-seconds 3600
--query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]'
--output text))
- aws s3 sync ./build s3://my-production-bucket/
rules:
- if: $CI_COMMIT_BRANCH == "main"
environment:
name: production
Fédération d’identité de charge de travail GCP
# .gitlab-ci.yml — authentification OIDC avec GCP
deploy_gcp:
stage: deploy
image: google/cloud-sdk:latest
id_tokens:
GITLAB_OIDC_TOKEN:
aud: https://gitlab.example.com
script:
- echo "$GITLAB_OIDC_TOKEN" > /tmp/gitlab_token.txt
- >
gcloud iam workload-identity-pools create-cred-config
projects/$GCP_PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_ID/providers/$PROVIDER_ID
--service-account="$GCP_SERVICE_ACCOUNT"
--output-file=/tmp/gcp_creds.json
--credential-source-file=/tmp/gitlab_token.txt
- export GOOGLE_APPLICATION_CREDENTIALS=/tmp/gcp_creds.json
- gcloud config set project $GCP_PROJECT_ID
- gcloud run deploy my-service --image gcr.io/$GCP_PROJECT_ID/my-app:$CI_COMMIT_SHA
rules:
- if: $CI_COMMIT_BRANCH == "main"
environment:
name: production
Côté cloud, configurez la politique de confiance pour valider des claims comme project_path, ref et ref_protected afin que seuls des projets et des branches spécifiques puissent assumer le rôle.
6. Sécurité des pipelines de merge request
Les pipelines de merge request s’exécutent sur du code qui n’a pas encore été validé par une revue. Traitez-les comme non fiables. N’exposez jamais les secrets de production aux pipelines de MR.
# .gitlab-ci.yml — règles distinctes pour les pipelines de MR vs. de branche
test:
stage: test
script:
- pytest tests/
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
deploy_production:
stage: deploy
script:
- ./deploy.sh production
rules:
# Ne JAMAIS exécuter sur les pipelines de merge request
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
when: never
- if: $CI_COMMIT_BRANCH == "main"
environment:
name: production
Contrôles critiques :
- Utilisez
rules:pour garantir que les jobs de déploiement ne s’exécutent jamais sur les pipelinesmerge_request_event. - Exigez la réussite du pipeline avant la fusion (Settings > Merge Requests).
- Activez « Pipelines must succeed » et « All discussions must be resolved ».
- Envisagez d’activer les merged results pipelines pour tester l’état post-fusion.
7. Template de détection de secrets
Le scanner de détection de secrets intégré à GitLab intercepte les credentials accidentellement commités avant qu’ils n’atteignent la branche par défaut.
# .gitlab-ci.yml — inclure le template de détection de secrets
include:
- template: Jobs/Secret-Detection.gitlab-ci.yml
# Surcharger pour faire échouer le pipeline si des secrets sont détectés
secret_detection:
variables:
SECRET_DETECTION_HISTORIC_SCAN: "true" # Scanner l'historique complet de git
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
allow_failure: false # Bloquer le pipeline en cas de détection
Pour une analyse plus complète, ajoutez également les templates SAST et dependency scanning :
include:
- template: Jobs/Secret-Detection.gitlab-ci.yml
- template: Jobs/SAST.gitlab-ci.yml
- template: Jobs/Dependency-Scanning.gitlab-ci.yml
Consultez les résultats dans le Security Dashboard (disponible sur GitLab Ultimate) ou parsez les artefacts JSON dans les tiers inférieurs.
8. Push Rules
Les push rules appliquent des politiques au niveau Git — avant même que le code n’entre dans un pipeline. Utilisez-les pour empêcher l’envoi de secrets, imposer des standards de messages de commit et restreindre les types de fichiers.
# Définir les push rules via l'API
curl --request PUT \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/push_rule" \
--data '{"deny_delete_tag": true, "prevent_secrets": true, "commit_message_regex": "^(feat|fix|chore|docs|refactor|test|ci)\\(.*\\):.*", "max_file_size": 50, "member_check": true, "reject_unsigned_commits": true}'
Push rules recommandées :
prevent_secrets: true— Rejette les pushs contenant des fichiers qui ressemblent à des secrets (clés, tokens, certificats).reject_unsigned_commits: true— Exige des commits signés GPG (GitLab Premium+).commit_message_regex— Impose les messages de commit conventionnels pour des pistes d’audit propres.max_file_size— Empêche de commiter accidentellement de gros fichiers binaires.member_check: true— Rejette les commits provenant de non-membres du projet.
9. Timeouts de jobs et interruptible
Les jobs incontrôlés gaspillent des ressources et peuvent être exploités pour du cryptomining. Définissez des timeouts explicites et marquez les jobs non critiques comme interruptibles afin qu’ils soient annulés lorsqu’un nouveau pipeline démarre sur la même branche.
# .gitlab-ci.yml — timeouts et interruptible
default:
timeout: 30m # Timeout global par défaut pour tous les jobs
interruptible: true # Annuler les jobs en cours lorsqu'un nouveau commit est poussé
retry:
max: 1
when:
- runner_system_failure
- stuck_or_timeout_failure
test:
stage: test
timeout: 15m
interruptible: true
script:
- pytest tests/ --timeout=600
deploy_production:
stage: deploy
timeout: 20m
interruptible: false # Ne JAMAIS annuler un déploiement en production en cours
script:
- ./deploy.sh production
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: manual
environment:
name: production
Recommandations :
- Définissez un timeout au niveau projet dans Settings > CI/CD > General Pipelines (recommandé : 60 minutes maximum).
- Définissez des timeouts au niveau job plus courts que la valeur par défaut du projet.
- Marquez les jobs de test et de lint comme
interruptible: truepour économiser la capacité des runners. - Marquez les jobs de déploiement comme
interruptible: falsepour éviter les déploiements partiels. - Utilisez
retryuniquement pour les défaillances d’infrastructure transitoires — jamais pour les échecs de tests.
Tableau de référence rapide
| Contrôle | Où configurer | Tier minimum |
|---|---|---|
| Variables protégées/masquées | Settings > CI/CD > Variables | Free |
| Restriction des runners | Settings > CI/CD > Runners | Free |
| Environnements protégés | Settings > CI/CD > Protected Environments | Premium |
| Portée du CI_JOB_TOKEN | Settings > CI/CD > Token Access | Free |
| id_tokens OIDC | .gitlab-ci.yml |
Free |
| Détection de secrets | include: template |
Free (Ultimate pour le dashboard) |
| Push Rules | Settings > Repository > Push Rules | Premium |
| Timeouts de jobs | Settings > CI/CD + .gitlab-ci.yml |
Free |
Pour aller plus loin
Continuez à renforcer la sécurité de vos pipelines GitLab CI/CD avec ces ressources complémentaires :
- Guide de sécurité GitLab CI/CD — Un parcours complet de chaque paramètre de sécurité dans GitLab CI/CD.
- Bonnes pratiques de gestion des secrets CI/CD — Plongée en profondeur dans l’intégration de vault, la rotation et les secrets à moindre privilège.
- Authentification OIDC dans les pipelines CI/CD — Lab pas à pas pour configurer OIDC avec AWS, GCP et Azure.
- Checklist de sécurité des pipelines CI/CD — La checklist d’audit complète couvrant GitHub Actions, GitLab CI et Jenkins.
- Documentation officielle GitLab CI/CD — La référence officielle pour toutes les fonctionnalités de GitLab CI/CD.
La sécurité n’est pas une configuration ponctuelle — c’est une pratique continue. Revoyez vos paramètres de sécurité de pipeline chaque trimestre, effectuez la rotation des credentials, auditez les accès aux runners et maintenez votre instance GitLab à jour. Ce cheat sheet vous fournit les fondations. À vous maintenant de verrouiller vos pipelines.