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.
Choisir son mode
Section intitulée « Choisir son mode »| Critère | CLI open-source | Platform |
|---|---|---|
| Cas d’usage | Scan ponctuel, intégration CI, projet unique | Inventaire centralisé, multi-projets, gouvernance |
| Installation | Binaire local ou image Docker | Docker Compose / Kubernetes |
| Configuration | Fichier .plumber.yaml | Interface web + policies |
| Contrôles | 8 contrôles de base | 15+ contrôles (variables, secrets, MR, quotas) |
| Résultats | Terminal / JSON | Dashboard web, historique, exports |
| Coût | Gratuit (MPL-2.0) | Free tier / Enterprise |
Recommandation :
| Situation | Mode conseillé |
|---|---|
| Je veux tester Plumber rapidement | CLI |
| J’ai 1-2 projets, équipe unique | CLI + composant GitLab CI |
| J’ai 10+ projets, besoin de reporting | Platform Free |
| Conformité réglementaire, audit, RBAC | Platform Enterprise |
Partie 1 : CLI open-source
Section intitulée « Partie 1 : CLI open-source »La CLI est idéale pour les développeurs qui veulent un scan rapide ou intégrer Plumber dans leur pipeline GitLab.
Installation
Section intitulée « Installation »mise use -g github:getplumber/plumberbrew tap getplumber/plumberbrew install plumber# Télécharger le binaireVERSION="0.1.32"OS=$(uname -s | tr '[:upper:]' '[:lower:]')ARCH=$(uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')curl -LO "https://github.com/getplumber/plumber/releases/download/v${VERSION}/plumber-${OS}-${ARCH}"curl -LO "https://github.com/getplumber/plumber/releases/download/v${VERSION}/checksums.txt"
# Vérifier l'intégrité (supply chain !)sha256sum -c checksums.txt --ignore-missing
# Installerchmod +x plumber-* && sudo mv plumber-${OS}-${ARCH} /usr/local/bin/plumber# Toujours épingler la version (pas de :latest !)docker pull getplumber/plumber:0.1.32Vérification :
plumber version# plumber version 0.1.32Configuration du token GitLab
Section intitulée « Configuration du token GitLab »Plumber nécessite un token GitLab avec les scopes read_api et read_repository :
-
Créer le token
Allez dans GitLab → User Settings → Access Tokens ou utilisez ce lien direct.
-
Sélectionner les scopes
read_api: accès en lecture à l’APIread_repository: accès au contenu du dépôt
-
Exporter le token
Fenêtre de terminal export GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx
Première analyse
Section intitulée « Première analyse »Depuis un dépôt Git local (détection automatique) :
cd mon-projetplumber analyzeSur un projet distant :
plumber analyze --gitlab-url https://gitlab.com --project mongroupe/monprojetExemple de sortie
Section intitulée « Exemple de sortie »Auto-detected GitLab URL: https://gitlab.comAuto-detected project: Bob74/test-gitlab-srtUsing configuration: .plumber.yamlAnalyzing 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%Les 8 contrôles CLI
Section intitulée « Les 8 contrôles CLI »| Contrôle | Description |
|---|---|
containerImageMustNotUseForbiddenTags | Détecte les images avec tags mutables (latest, dev) |
containerImageMustComeFromAuthorizedSources | Vérifie que les images viennent de registries autorisés |
branchMustBeProtected | S’assure que les branches critiques sont protégées |
pipelineMustNotIncludeHardcodedJobs | Détecte les jobs définis directement dans .gitlab-ci.yml |
includesMustBeUpToDate | Vérifie que les includes utilisent la dernière version |
includesMustNotUseForbiddenVersions | Détecte les includes avec versions mutables (main, HEAD) |
pipelineMustIncludeComponent | Vérifie la présence de composants requis |
pipelineMustIncludeTemplate | Vérifie la présence de templates requis |
Fichier de configuration
Section intitulée « Fichier de configuration »Générer la configuration par défaut :
plumber config generateVoir la configuration effective :
plumber config viewStructure du fichier .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: []Options de la commande analyze
Section intitulée « Options de la commande analyze »| Option | Défaut | Description |
|---|---|---|
--gitlab-url | Auto-détecté | URL de l’instance GitLab |
--project | Auto-détecté | Chemin du projet (groupe/projet) |
--config | .plumber.yaml | Chemin du fichier de configuration |
--threshold | 100 | Score minimum pour passer (0-100) |
--branch | Branche par défaut | Branche à analyser |
--output | - | Fichier JSON de sortie |
--print | true | Afficher la sortie texte |
Codes de sortie : 0 = conformité ≥ threshold, 1 = échec ou erreur.
Intégration GitLab CI
Section intitulée « Intégration GitLab CI »Avec le composant officiel (recommandé) :
include: - component: gitlab.com/getplumber/plumber/plumber@v0.1.32Le composant s’exécute automatiquement sur la branche par défaut, les tags et les merge requests.
Avec options :
include: - component: gitlab.com/getplumber/plumber/plumber@v0.1.32 inputs: threshold: 80 config_file: configs/my-plumber.yaml verbose: trueAvec Docker directement :
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_BRANCHGitLab Self-Hosted
Section intitulée « GitLab Self-Hosted »Pour une instance GitLab auto-hébergée :
-
Importer le projet
gitlab.com/getplumber/plumbervers votre instance -
Activer CI/CD Catalog dans Settings → General → Visibility
-
Créer un tag pour publier :
git tag v0.1.32 && git push origin v0.1.32 -
Utiliser le composant local :
include:- component: gitlab.example.com/chemin/plumber/plumber@v0.1.32
Partie 2 : Platform
Section intitulée « Partie 2 : Platform »La Platform est une interface web qui étend les capacités de la CLI pour les équipes ayant plusieurs projets à gérer.

Quand passer à la Platform ?
Section intitulée « Quand passer à la Platform ? »| Besoin | CLI 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 | ❌ | ✅ |
Contrôles supplémentaires Platform
Section intitulée « Contrôles supplémentaires Platform »La Platform ajoute des contrôles absents de la CLI :
| Catégorie | Contrôle | Description |
|---|---|---|
| Variables CI/CD | Variables protégées | Vérifie le flag “protected” |
| Variables CI/CD | Variables masquées | Vérifie le flag “masked” |
| Secrets | Secrets dans la config | Détecte via Gitleaks |
| Merge Requests | Règles d’approbation | Vérifie les approval rules |
| Merge Requests | Settings MR | Squash, FF, etc. |
| Accès | Quotas de membres | Limite projet/groupe |
| Pipeline | Phases requises | Stages obligatoires |
| Sécurité | Security Policy source | Politiques de sécurité |
Policies et templates de conformité
Section intitulée « Policies et templates de conformité »La Platform organise les contrôles en policies (ensembles de contrôles thématiques). Trois templates sont disponibles :
| Policy template | Description |
|---|---|
| OWASP | OWASP Top 10 CI/CD Security Risks |
| ISO27001 & ISO27002 | Conformité 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 |
OWASP Top 10 CI/CD (détail)
Section intitulée « OWASP Top 10 CI/CD (détail) »| Catégorie | Risques couverts | Contrôles associés |
|---|---|---|
| CICD-SEC-1, CICD-SEC-2 | Flow Control, Access Management | Branch protection, quotas membres |
| CICD-SEC-3, CICD-SEC-4, CICD-SEC-7 | Dependency Chain, Poisoned Pipeline, Insecure Config | Images autorisées, includes épinglés |
| CICD-SEC-6 | Credential Hygiene | Variables protégées/masquées, secrets dans config |
Gestion des issues
Section intitulée « Gestion des issues »Chaque problème détecté devient une issue :
| Statut | Signification |
|---|---|
| Detected | Problème détecté au dernier scan |
| In progress | En cours de correction |
| Dismissed | Ignoré volontairement (exception documentée) |
| Fixed | Corrigé et vérifié |
RBAC et permissions
Section intitulée « RBAC et permissions »| Rôle | Voir issues | Modifier statut | Gérer contrôles | Admin |
|---|---|---|---|---|
| Admin | ✅ | ✅ | ✅ | ✅ |
| Maintainer | ✅ | ✅ | ✅ | ❌ |
| Member | ✅ | ✅ | ❌ | ❌ |
Les permissions sont synchronisées avec GitLab.
Déploiement self-hosted
Section intitulée « Déploiement self-hosted »-
Cloner le repo
Fenêtre de terminal git clone https://github.com/getplumber/platform.git plumber-platformcd plumber-platformcp .env.example .env -
Créer une application OAuth sur GitLab
Allez dans Settings → Applications de votre groupe GitLab.
Champ Valeur Name Plumber PlatformRedirect URI http://localhost:3001/api/auth/gitlab/callbackConfidential ✅ Coché Scopes ✅ apiuniquement -
Configurer
.envFenêtre de terminal # Générer des secretsSECRET_KEY=$(openssl rand -hex 32)DB_PASSWORD=$(openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 32)# Configurersed -i "s|SECRET_KEY=.*|SECRET_KEY=\"$SECRET_KEY\"|" .envsed -i "s|JOBS_DB_PASSWORD=.*|JOBS_DB_PASSWORD=\"$DB_PASSWORD\"|" .envsed -i "s|JOBS_REDIS_PASSWORD=.*|JOBS_REDIS_PASSWORD=\"$DB_PASSWORD\"|" .envsed -i "s|JOBS_GITLAB_URL=.*|JOBS_GITLAB_URL=\"https://gitlab.com\"|" .envsed -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\"|" .envsed -i "s|GITLAB_OAUTH2_CLIENT_SECRET=.*|GITLAB_OAUTH2_CLIENT_SECRET=\"votre-secret\"|" .env -
Lancer en mode local
Fenêtre de terminal docker compose -f compose.local.yml up -dService URL Frontend http://localhost:3000 Backend API http://localhost:3001 -
Se connecter
Accédez à http://localhost:3000 et cliquez Sign in with GitLab.
# Configurer le domainesed -i "s|FRONTEND_DOMAIN=.*|FRONTEND_DOMAIN=\"plumber.example.com\"|" .envsed -i "s|API_DOMAIN=.*|API_DOMAIN=\"https://plumber.example.com\"|" .env
# Lancer avec Traefik + Let's Encryptdocker compose up -dhelm repo add plumber https://charts.getplumber.iohelm repo update
helm install plumber plumber/plumber \ --namespace plumber \ --create-namespace \ --set gitlab.url=https://gitlab.example.com \ --set organization=MON-GROUPE \ --set oauth.clientId=$OAUTH_CLIENT_ID \ --set oauth.clientSecret=$OAUTH_CLIENT_SECRETPourquoi auditer ses pipelines ?
Section intitulée « Pourquoi auditer ses pipelines ? »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’attaque | Contrôle Plumber | Protection |
|---|---|---|
| Image empoisonnée | containerImageMustComeFromAuthorizedSources | Bloque registries non approuvés |
| Tag mutable | containerImageMustNotUseForbiddenTags | Interdit latest, dev |
| Include modifié | includesMustNotUseForbiddenVersions | Exige versions épinglées |
| Push non autorisé | branchMustBeProtected | Vérifie protection branches |
Bonnes pratiques
Section intitulée « Bonnes pratiques »Commencer progressivement
Section intitulée « Commencer progressivement »Sur un projet existant :
plumber analyze --threshold 50Puis augmentez jusqu’à 100%.
Désactiver les contrôles non pertinents
Section intitulée « Désactiver les contrôles non pertinents »controls: pipelineMustNotIncludeHardcodedJobs: enabled: false # Notre équipe utilise des jobs hardcodés par choixDocumenter les exceptions
Section intitulée « Documenter les exceptions »containerImageMustComeFromAuthorizedSources: trustedUrls: # Registry interne - validé par l'équipe sécurité le 2026-01-15 - registry.internal.example.com/*Exiger des composants de sécurité
Section intitulée « Exiger des composants de sécurité »pipelineMustIncludeComponent: enabled: true requiredGroups: - ["components/sast/sast", "components/secret-detection/secret-detection"]Dépannage
Section intitulée « Dépannage »| Problème | Cause | Solution |
|---|---|---|
GITLAB_TOKEN environment variable is required | Token non défini | export GITLAB_TOKEN=glpat-xxx |
401 Unauthorized | Token invalide | Vérifier scopes read_api + read_repository |
403 Forbidden on MR settings | GitLab non-Premium | Normal, le scan continue |
404 Not Found | Projet incorrect | Vérifier --project et --gitlab-url |
Platform
Section intitulée « Platform »| Problème | Cause | Solution |
|---|---|---|
| Containers redémarrent | REPLACE_ME_* dans .env | Générer secrets avec openssl rand -hex 32 |
User role is No One | ORGANIZATION est un user | Créer un groupe GitLab |
Activate your license | Pas Owner/Maintainer du groupe | Vérifier droits sur le groupe |
404 /groups/{org}/members | Namespace utilisateur | Utiliser un groupe GitLab |
invalid_redirect_uri | Mauvaise URI OAuth | http://localhost:3001/api/auth/gitlab/callback |
| PostgreSQL auth failed | Anciens credentials | docker compose down -v puis relancer |
À retenir
Section intitulée « À retenir »- 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