Aller au contenu
CI/CD & Automatisation medium

Plumber : Scanner de conformité pour pipelines GitLab CI/CD

26 min de lecture

Logo Plumber

Plumber scanne vos pipelines GitLab CI/CD et génère un score de conformité de 0 à 100%. Il produit également un PBOM (Pipeline Bill of Materials) — l’inventaire complet de vos dépendances CI/CD : images Docker, composants GitLab, templates et includes. Ce PBOM peut ensuite être analysé par des outils de sécurité comme Grype ou Trivy.

Plumber 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, génération de PBOM, 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.41
# commit: 5a2a3aa3b67c8489289bf98f47f9494f386f6458
# built: 2026-02-12T12:55:08Z

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
# Exiger que toutes les images soient épinglées par digest (sha256)
# Ex: alpine@sha256:abc123... au lieu de alpine:3.19
containerImagesMustBePinnedByDigest: false
# Registries autorisés
containerImageMustComeFromAuthorizedSources:
enabled: true
trustDockerHubOfficialImages: true
trustedUrls:
- $CI_REGISTRY_IMAGE:*
- registry.gitlab.com/security-products/*
- getplumber/plumber:*
# 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
defaultBranchIsForbiddenVersion: false
# Composants requis (expression booléenne ou tableau)
pipelineMustIncludeComponent:
enabled: false
# Syntaxe expression (AND/OR) :
# required: components/sast/sast AND components/secret-detection/secret-detection
# Syntaxe tableau (OR de ANDs) :
requiredGroups: []
# Templates requis
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 (résultats)
--pbom-Fichier PBOM natif Plumber
--pbom-cyclonedx-Fichier PBOM au format CycloneDX (pour Grype, Trivy)
--printtrueAfficher la sortie texte
--verbosefalseMode debug

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

Depuis la version 0.1.41, Plumber peut analyser votre .gitlab-ci.yml local avant de le pousser sur GitLab. Cela permet de détecter les problèmes de conformité sans créer de commit.

Fenêtre de terminal
# Plumber utilise automatiquement le fichier local si vous êtes dans le repo
cd mon-projet
plumber analyze

Ordre de priorité pour la source du .gitlab-ci.yml :

  1. --branch spécifié → utilise le fichier distant de cette branche
  2. Dans un repo Git correspondant au projet → utilise le fichier local
  3. Sinon → utilise le fichier distant de la branche par défaut

Le PBOM (Pipeline Bill of Materials) est un inventaire complet de toutes les dépendances de votre pipeline CI/CD : images Docker, composants GitLab CI, templates et includes. C’est l’équivalent d’un SBOM (Software Bill of Materials) mais pour votre infrastructure CI/CD.

BesoinPBOM apporte
InventaireListe exhaustive des images et includes utilisés
ConformitéPreuve documentée des outils utilisés dans vos pipelines
AuditHistorique des versions et sources
Drift detectionSuivi des changements dans le temps (via Dependency-Track)

Plumber génère le PBOM en deux formats :

FormatFlagUsage
Plumber natif--pbom <fichier>Inventaire détaillé avec métadonnées de conformité
CycloneDX SBOM--pbom-cyclonedx <fichier>Intégration avec Grype, Trivy, Dependency-Track, GitLab
Fenêtre de terminal
# Générer les deux formats
plumber analyze \
--pbom pbom.json \
--pbom-cyclonedx cyclonedx-sbom.json
pbom.json
{
"pbomVersion": "1.0.0",
"generatedAt": "2026-02-15T18:35:11Z",
"project": {
"path": "mongroupe/monprojet",
"id": 12345678,
"gitlabUrl": "https://gitlab.com"
},
"containerImages": [
{
"image": "docker.io/python:3.11-slim",
"registry": "docker.io",
"name": "python",
"tag": "3.11-slim",
"jobs": ["unit-test", "deploy-staging"],
"authorized": true,
"forbiddenTag": false
}
],
"includes": [
{
"type": "component",
"location": "gitlab.com/components/sast/sast",
"version": "3.4.0",
"latestVersion": "3.4.0",
"upToDate": true,
"componentName": "sast",
"fromCatalog": true
}
],
"summary": {
"totalImages": 2,
"uniqueRegistries": 1,
"totalIncludes": 1,
"components": 1,
"templates": 0
}
}

Le format CycloneDX suit la spécification 1.5 et est compatible avec les outils de sécurité standard :

cyclonedx-sbom.json
{
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"serialNumber": "urn:uuid:16c5c32b-c05e-44f5-87c6-a4c2312e685e",
"version": 1,
"metadata": {
"timestamp": "2026-02-15T18:35:11Z",
"tools": [{ "vendor": "Plumber", "name": "plumber", "version": "0.1.41" }],
"component": {
"type": "application",
"name": "mongroupe/monprojet"
}
},
"components": [
{
"type": "container",
"bom-ref": "container:0",
"name": "python",
"version": "3.11-slim",
"purl": "pkg:docker/library/python@3.11-slim",
"properties": [
{ "name": "plumber:registry", "value": "docker.io" },
{ "name": "plumber:jobs", "value": "unit-test,deploy-staging" },
{ "name": "plumber:authorized", "value": "true" }
]
}
]
}

Le PBOM CycloneDX peut être analysé par des outils de sécurité pour détecter les vulnérabilités dans les images Docker référencées.

Grype est un scanner de vulnérabilités d’Anchore.

Fenêtre de terminal
# Installation
brew install grype
# ou
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
# Scanner le PBOM (préfixe sbom: requis)
grype sbom:cyclonedx-sbom.json
# Sortie JSON
grype sbom:cyclonedx-sbom.json -o json > vulnerabilities.json
# Échouer si vulnérabilités high/critical
grype sbom:cyclonedx-sbom.json --fail-on high

Sortie typique (peu ou pas de vulnérabilités attendues) :

✔ Vulnerability DB [updated]
✔ Scanned for vulnerabilities [0 vulnerability matches]
├── by severity: 0 critical, 0 high, 0 medium, 0 low, 0 negligible
No vulnerabilities found

Trivy est le scanner de sécurité d’Aqua Security.

Fenêtre de terminal
# Installation
brew install trivy
# ou
mise use -g trivy
# Scanner le PBOM
trivy sbom cyclonedx-sbom.json
# Format JSON
trivy sbom cyclonedx-sbom.json --format json > trivy-report.json
# Filtrer par sévérité
trivy sbom cyclonedx-sbom.json --severity HIGH,CRITICAL
# Échouer si vulnérabilités trouvées
trivy sbom cyclonedx-sbom.json --exit-code 1

Pour un scan complet des vulnérabilités, scannez les images Docker directement :

Fenêtre de terminal
# Extraire les images du PBOM et les scanner
jq -r '.containerImages[].image' pbom.json | while read image; do
echo "=== Scanning $image ==="
trivy image "$image"
done

Plumber s’intègre directement dans vos pipelines GitLab CI de plusieurs façons.

Avec le composant officiel (recommandé) :

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

Le composant s’exécute automatiquement sur la branche par défaut, les tags et les merge requests. Il génère automatiquement les fichiers PBOM (natif et CycloneDX) comme artifacts.

Avec options :

.gitlab-ci.yml
include:
- component: gitlab.com/getplumber/plumber/plumber@v0.1.41
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.41
script:
- plumber analyze --threshold 80 --pbom pbom.json --pbom-cyclonedx sbom.json
artifacts:
paths:
- pbom.json
- sbom.json
reports:
cyclonedx: sbom.json
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

Scanner les vulnérabilités du PBOM :

.gitlab-ci.yml
# Après le job plumber
scan-pbom:
stage: test
image: aquasec/trivy:latest
needs: ["plumber"]
script:
- trivy sbom plumber-cyclonedx-sbom.json --severity HIGH,CRITICAL --exit-code 1
allow_failure: true

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.41 && git push origin v0.1.41

  4. Utiliser le composant local :

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

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
  • PBOM : inventaire complet des dépendances CI/CD (images, components, templates)
  • CycloneDX : format standard pour intégration avec Grype, Trivy, Dependency-Track
  • 8 contrôles CLI configurables via .plumber.yaml
  • 15+ contrôles Platform (variables, secrets, MR, quotas)
  • Composant GitLab : 2 lignes dans le pipeline
  • Analyse locale : valider le .gitlab-ci.yml avant de pousser
  • 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.