Aller au contenu
CI/CD & Automatisation medium

Plumber : Vos pipelines GitLab CI/CD sont-ils conformes ?

18 min de lecture

Logo Plumber

Plumber scanne vos pipelines GitLab CI/CD et génère un score de conformité de 0 à 100%. Il détecte automatiquement les problèmes de sécurité : images Docker avec tags mutables (latest), registries non autorisés, branches non protégées, includes obsolètes, jobs hardcodés.

Deux modes d’utilisation :

  • CLI open-source — Pour les développeurs. Scan ponctuel en ligne de commande, intégration CI via composant GitLab.
  • Platform — Pour les équipes. Interface web, inventaire multi-projets, analyses planifiées, gestion des issues, RBAC.
CritèreCLI open-sourcePlatform
Cas d’usageScan ponctuel, intégration CI, projet uniqueInventaire centralisé, multi-projets, gouvernance
InstallationBinaire local ou image DockerDocker Compose / Kubernetes
ConfigurationFichier .plumber.yamlInterface web + policies
Contrôles8 contrôles de base15+ contrôles (variables, secrets, MR, quotas)
RésultatsTerminal / JSONDashboard web, historique, exports
CoûtGratuit (MPL-2.0)Free tier / Enterprise

Recommandation :

SituationMode conseillé
Je veux tester Plumber rapidementCLI
J’ai 1-2 projets, équipe uniqueCLI + composant GitLab CI
J’ai 10+ projets, besoin de reportingPlatform Free
Conformité réglementaire, audit, RBACPlatform Enterprise

La CLI est idéale pour les développeurs qui veulent un scan rapide ou intégrer Plumber dans leur pipeline GitLab.

Fenêtre de terminal
mise use -g github:getplumber/plumber

Vérification :

Fenêtre de terminal
plumber version
# plumber version 0.1.32

Plumber nécessite un token GitLab avec les scopes read_api et read_repository :

  1. Créer le token

    Allez dans GitLab → User Settings → Access Tokens ou utilisez ce lien direct.

  2. Sélectionner les scopes

    • read_api : accès en lecture à l’API
    • read_repository : accès au contenu du dépôt
  3. Exporter le token

    Fenêtre de terminal
    export GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx

Depuis un dépôt Git local (détection automatique) :

Fenêtre de terminal
cd mon-projet
plumber analyze

Sur un projet distant :

Fenêtre de terminal
plumber analyze --gitlab-url https://gitlab.com --project mongroupe/monprojet
Auto-detected GitLab URL: https://gitlab.com
Auto-detected project: Bob74/test-gitlab-srt
Using configuration: .plumber.yaml
Analyzing project: Bob74/test-gitlab-srt on https://gitlab.com
Project: Bob74/test-gitlab-srt
──────────────────────────────────────────────────
Container images must not use forbidden tags (100.0% compliant)
──────────────────────────────────────────────────
Total Images: 11
Using Forbidden Tags: 0
──────────────────────────────────────────────────
Branch must be protected (0.0% compliant)
──────────────────────────────────────────────────
Total Branches: 2
Protected Branches: 1
Unprotected: 1
Issues Found:
• Branch 'main' is not protected
────────────────────
Summary
────────────────────
Status: FAILED ✗
Compliance
╔════════════════════════════════════════════════════╤════════════╤══════════╗
║ Control │ Compliance │ Status ║
╟────────────────────────────────────────────────────┼────────────┼──────────╢
║ Container images must not use forbidden tags │ 100.0% │ ✓ ║
║ Container images must come from authorized sources │ 100.0% │ ✓ ║
║ Branch must be protected │ 0.0% │ ✗ ║
║ Pipeline must not include hardcoded jobs │ 0.0% │ ✗ ║
╟────────────────────────────────────────────────────┼────────────┼──────────╢
║ Total (required: 100%) │ 66.7% │ ✗ ║
╚════════════════════════════════════════════════════╧════════════╧══════════╝
Error: compliance 66.7% is below threshold 100.0%
ContrôleDescription
containerImageMustNotUseForbiddenTagsDétecte les images avec tags mutables (latest, dev)
containerImageMustComeFromAuthorizedSourcesVérifie que les images viennent de registries autorisés
branchMustBeProtectedS’assure que les branches critiques sont protégées
pipelineMustNotIncludeHardcodedJobsDétecte les jobs définis directement dans .gitlab-ci.yml
includesMustBeUpToDateVérifie que les includes utilisent la dernière version
includesMustNotUseForbiddenVersionsDétecte les includes avec versions mutables (main, HEAD)
pipelineMustIncludeComponentVérifie la présence de composants requis
pipelineMustIncludeTemplateVérifie la présence de templates requis

Générer la configuration par défaut :

Fenêtre de terminal
plumber config generate

Voir la configuration effective :

Fenêtre de terminal
plumber config view

Structure du fichier .plumber.yaml :

.plumber.yaml
version: "1.0"
controls:
# Tags d'images interdits
containerImageMustNotUseForbiddenTags:
enabled: true
tags:
- latest
- dev
- main
# Registries autorisés
containerImageMustComeFromAuthorizedSources:
enabled: true
trustDockerHubOfficialImages: true
trustedUrls:
- $CI_REGISTRY_IMAGE:*
- registry.gitlab.com/security-products/*
# Protection des branches
branchMustBeProtected:
enabled: true
defaultMustBeProtected: true
namePatterns:
- main
- release/*
allowForcePush: false
minMergeAccessLevel: 30 # Developer
minPushAccessLevel: 40 # Maintainer
# Pas de jobs hardcodés
pipelineMustNotIncludeHardcodedJobs:
enabled: true
# Includes à jour
includesMustBeUpToDate:
enabled: true
# Versions d'includes interdites
includesMustNotUseForbiddenVersions:
enabled: true
forbiddenVersions:
- latest
- main
- HEAD
# Composants requis (désactivé par défaut)
pipelineMustIncludeComponent:
enabled: false
requiredGroups: []
# Templates requis (désactivé par défaut)
pipelineMustIncludeTemplate:
enabled: false
requiredGroups: []
OptionDéfautDescription
--gitlab-urlAuto-détectéURL de l’instance GitLab
--projectAuto-détectéChemin du projet (groupe/projet)
--config.plumber.yamlChemin du fichier de configuration
--threshold100Score minimum pour passer (0-100)
--branchBranche par défautBranche à analyser
--output-Fichier JSON de sortie
--printtrueAfficher la sortie texte

Codes de sortie : 0 = conformité ≥ threshold, 1 = échec ou erreur.

Avec le composant officiel (recommandé) :

.gitlab-ci.yml
include:
- component: gitlab.com/getplumber/plumber/plumber@v0.1.32

Le composant s’exécute automatiquement sur la branche par défaut, les tags et les merge requests.

Avec options :

.gitlab-ci.yml
include:
- component: gitlab.com/getplumber/plumber/plumber@v0.1.32
inputs:
threshold: 80
config_file: configs/my-plumber.yaml
verbose: true

Avec Docker directement :

.gitlab-ci.yml
compliance:
stage: validate
image: getplumber/plumber:0.1.32
script:
- plumber analyze --threshold 80
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

Pour une instance GitLab auto-hébergée :

  1. Importer le projet gitlab.com/getplumber/plumber vers votre instance

  2. Activer CI/CD Catalog dans Settings → General → Visibility

  3. Créer un tag pour publier : git tag v0.1.32 && git push origin v0.1.32

  4. Utiliser le composant local :

    include:
    - component: gitlab.example.com/chemin/plumber/plumber@v0.1.32

La Platform est une interface web qui étend les capacités de la CLI pour les équipes ayant plusieurs projets à gérer.

Dashboard Plumber Platform avec la policy OWASP Top 10 CI/CD

BesoinCLI suffit ?Platform nécessaire ?
Scanner 1-2 projets ponctuellement
Intégrer dans un pipeline CI
Voir l’historique de conformité
Gérer 10+ projets⚠️ Fastidieux
Tracker les issues et leur résolution
Générer des rapports pour audit
Contrôler variables CI/CD et secrets
RBAC et permissions par équipe

La Platform ajoute des contrôles absents de la CLI :

CatégorieContrôleDescription
Variables CI/CDVariables protégéesVérifie le flag “protected”
Variables CI/CDVariables masquéesVérifie le flag “masked”
SecretsSecrets dans la configDétecte via Gitleaks
Merge RequestsRègles d’approbationVérifie les approval rules
Merge RequestsSettings MRSquash, FF, etc.
AccèsQuotas de membresLimite projet/groupe
PipelinePhases requisesStages obligatoires
SécuritéSecurity Policy sourcePolitiques de sécurité

La Platform organise les contrôles en policies (ensembles de contrôles thématiques). Trois templates sont disponibles :

Policy templateDescription
OWASPOWASP Top 10 CI/CD Security Risks
ISO27001 & ISO27002Conformité aux contrôles de l’ISO/IEC 27001:2022 Annex A
SecNumCloud (SnC)Conformité aux exigences de l’ANSSI pour les prestataires de services cloud
CatégorieRisques couvertsContrôles associés
CICD-SEC-1, CICD-SEC-2Flow Control, Access ManagementBranch protection, quotas membres
CICD-SEC-3, CICD-SEC-4, CICD-SEC-7Dependency Chain, Poisoned Pipeline, Insecure ConfigImages autorisées, includes épinglés
CICD-SEC-6Credential HygieneVariables protégées/masquées, secrets dans config

Chaque problème détecté devient une issue :

StatutSignification
DetectedProblème détecté au dernier scan
In progressEn cours de correction
DismissedIgnoré volontairement (exception documentée)
FixedCorrigé et vérifié
RôleVoir issuesModifier statutGérer contrôlesAdmin
Admin
Maintainer
Member

Les permissions sont synchronisées avec GitLab.

  1. Cloner le repo

    Fenêtre de terminal
    git clone https://github.com/getplumber/platform.git plumber-platform
    cd plumber-platform
    cp .env.example .env
  2. Créer une application OAuth sur GitLab

    Allez dans Settings → Applications de votre groupe GitLab.

    ChampValeur
    NamePlumber Platform
    Redirect URIhttp://localhost:3001/api/auth/gitlab/callback
    Confidential✅ Coché
    Scopesapi uniquement
  3. Configurer .env

    Fenêtre de terminal
    # Générer des secrets
    SECRET_KEY=$(openssl rand -hex 32)
    DB_PASSWORD=$(openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 32)
    # Configurer
    sed -i "s|SECRET_KEY=.*|SECRET_KEY=\"$SECRET_KEY\"|" .env
    sed -i "s|JOBS_DB_PASSWORD=.*|JOBS_DB_PASSWORD=\"$DB_PASSWORD\"|" .env
    sed -i "s|JOBS_REDIS_PASSWORD=.*|JOBS_REDIS_PASSWORD=\"$DB_PASSWORD\"|" .env
    sed -i "s|JOBS_GITLAB_URL=.*|JOBS_GITLAB_URL=\"https://gitlab.com\"|" .env
    sed -i "s|ORGANIZATION=.*|ORGANIZATION=\"MON-GROUPE\"|" .env
    # OAuth (remplacer par vos valeurs)
    sed -i "s|GITLAB_OAUTH2_CLIENT_ID=.*|GITLAB_OAUTH2_CLIENT_ID=\"votre-client-id\"|" .env
    sed -i "s|GITLAB_OAUTH2_CLIENT_SECRET=.*|GITLAB_OAUTH2_CLIENT_SECRET=\"votre-secret\"|" .env
  4. Lancer en mode local

    Fenêtre de terminal
    docker compose -f compose.local.yml up -d
    ServiceURL
    Frontendhttp://localhost:3000
    Backend APIhttp://localhost:3001
  5. Se connecter

    Accédez à http://localhost:3000 et cliquez Sign in with GitLab.

Fenêtre de terminal
# Configurer le domaine
sed -i "s|FRONTEND_DOMAIN=.*|FRONTEND_DOMAIN=\"plumber.example.com\"|" .env
sed -i "s|API_DOMAIN=.*|API_DOMAIN=\"https://plumber.example.com\"|" .env
# Lancer avec Traefik + Let's Encrypt
docker compose up -d

Les pipelines CI/CD concentrent les accès critiques : secrets, droits de publication, déploiement en production. Ils sont devenus une cible prioritaire des attaquants.

GitLab CI/CD accepte des configurations dangereuses sans warning :

  • Image python:latest → Tag mutable, peut changer à tout moment
  • Include vers main → Version non épinglée
  • Branche non protégée → Push malveillant possible

Plumber détecte ces problèmes avant qu’ils ne surviennent.

Vecteur d’attaqueContrôle PlumberProtection
Image empoisonnéecontainerImageMustComeFromAuthorizedSourcesBloque registries non approuvés
Tag mutablecontainerImageMustNotUseForbiddenTagsInterdit latest, dev
Include modifiéincludesMustNotUseForbiddenVersionsExige versions épinglées
Push non autorisébranchMustBeProtectedVérifie protection branches

Sur un projet existant :

Fenêtre de terminal
plumber analyze --threshold 50

Puis augmentez jusqu’à 100%.

controls:
pipelineMustNotIncludeHardcodedJobs:
enabled: false # Notre équipe utilise des jobs hardcodés par choix
containerImageMustComeFromAuthorizedSources:
trustedUrls:
# Registry interne - validé par l'équipe sécurité le 2026-01-15
- registry.internal.example.com/*
pipelineMustIncludeComponent:
enabled: true
requiredGroups:
- ["components/sast/sast", "components/secret-detection/secret-detection"]

ProblèmeCauseSolution
GITLAB_TOKEN environment variable is requiredToken non définiexport GITLAB_TOKEN=glpat-xxx
401 UnauthorizedToken invalideVérifier scopes read_api + read_repository
403 Forbidden on MR settingsGitLab non-PremiumNormal, le scan continue
404 Not FoundProjet incorrectVérifier --project et --gitlab-url
ProblèmeCauseSolution
Containers redémarrentREPLACE_ME_* dans .envGénérer secrets avec openssl rand -hex 32
User role is No OneORGANIZATION est un userCréer un groupe GitLab
Activate your licensePas Owner/Maintainer du groupeVérifier droits sur le groupe
404 /groups/{org}/membersNamespace utilisateurUtiliser un groupe GitLab
invalid_redirect_uriMauvaise URI OAuthhttp://localhost:3001/api/auth/gitlab/callback
PostgreSQL auth failedAnciens credentialsdocker compose down -v puis relancer

  • CLI : pour les développeurs, scan ponctuel, intégration CI
  • Platform : pour les équipes, multi-projets, gouvernance
  • 8 contrôles CLI configurables via .plumber.yaml
  • 15+ contrôles Platform (variables, secrets, MR, quotas)
  • Composant GitLab : 2 lignes dans le pipeline
  • Threshold : échouer si score < X%
  • ORGANIZATION doit être un groupe GitLab, pas un user


Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.