Retour aux articles

Dockdock-Go – Gatekeeper de sécurité pour registres Harbor

Retour technique détaillé sur Dockdock-Go, un projet étudiant de Master 1 implémentant une analyse de sécurité multi-couches et un contrôle humain pour les registres de conteneurs Harbor

Level Sony
Sécurité Kubernetes Harbor Rust DevSecOps Sécurité des conteneurs
Dockdock-Go – Gatekeeper de sécurité pour registres Harbor
Table des matières

Cet article documente un projet étudiant de Master 1 réalisé en 2023–2024, rédigé en décembre 2024. Il offre une rétrospective technique honnête incluant les décisions d’architecture, les défis d’implémentation, la dette technique et les leçons apprises.


Rédigé en décembre 2024

Équipe : 4 étudiants (1× Rust backend, 2× infra/Kubernetes, 1× frontend/docs (moi))

Durée effective : ≈9 mois partagés avec cours et autres projets

Statut actuel : Proof-of-Concept fonctionnel en démo locale, non maintenu en production

1. Le vrai problème que l’on voulait résoudre

Dans la majorité des organisations qui utilisent Harbor comme registre privé :

  • Les développeurs (ou les pipelines CI) poussent des images directement
  • Le scan de vulnérabilités intégré (Trivy ou Clair) se déclenche souvent après le push
  • Il n’existe généralement aucune détection systématique de malware statique
  • L’analyse dynamique (runtime) est quasi inexistante avant admission
  • Il n’y a pas de point de contrôle humain obligatoire pour les images critiques
  • Les refus ne sont pas tracés de façon centralisée et exploitable

Objectifs que nous nous étions fixés :

  1. Imposer une demande explicite + approbation humaine avant toute admission dans un projet sensible
  2. Cumuler plusieurs couches d’analyse : vulnérabilités + malware statique + comportement runtime
  3. Centraliser les résultats et la décision dans l’interface Harbor existante
  4. Garder le système suffisamment léger pour rester réaliste en contexte étudiant

2. Architecture statique

Architecture globale de Dockdock-Go

3. Workflow détaillé (user)

Architecture globale de Dockdock-Go

sequenceDiagram
    participant Dev
    participant UI as Harbor UI + Dockdock-Go
    participant API
    participant Harbor
    participant K8s
    participant Dyn as Dynamic Service
    participant DB
    participant Analyst

    Dev->>UI: Soumet demande d'admission<br>image:tag · source · projet cible
    UI->>+API: POST /api/v1/requests {…}

    API->>Harbor: Réplication artifact → projet temporaire
    Note over API,Harbor: Opération asynchrone → polling statut

    API->>K8s: Crée Job YaraHunter avec image:tag
    K8s-->>API: Logs → PVC → API lit JSON/texte

    API->>Harbor: Déclenche scan → polling (5 s) jusqu'à 90 s max
    loop Polling résultats scan
        Harbor-->>API: Rapport Trivy complet
    end

    API->>Dyn: POST /analyze {image, tag, rules}
    Dyn-->>API: {flags runtime, logs?}

    API->>DB: INSERT request + analyses + flags<br>status = PENDING
    API-->>UI: 201 Created + refresh liste

    loop Décision humaine (minutes à jours)
        Analyst->>UI: Liste demandes en attente
        Analyst->>UI: Ouvre détails → flags agrégés + rapports bruts
        Analyst->>UI: PATCH /requests/{id} {status: APPROVED|REJECTED, comment?}
    end

    alt APPROVED
        API->>Harbor: Réplication finale temp → projet cible
        API->>DB: UPDATE status = ACCEPTED, approved_at = now()
    else REJECTED
        API->>DB: UPDATE status = REJECTED, rejected_at = now(), reason = …
        API->>Harbor: (option future) suppression artifact temp
    end

    API-->>UI: Mise à jour visible pour tous

4. Points d’implémentation marquants

Import obligatoire des images dans K3s

YaraHunter ne scanne que ce qui est présent localement → docker save | sudo k3s ctr images import - manuel obligatoire. Tentative d’automatisation via sidecar crictl pull → abandonnée (problèmes d’auth et de droits).

Normalisation des flags

Table flags unique :

- type (enum)

  • vuln : vulnérabilité détectée (CVE, dépendance, config, etc.)
  • malware : détection malware / IOC
  • dynamic : résultat d’analyse dynamique (sandbox, comportement)
  • policy : violation de règles (compliance, accès, secrets, etc.)
  • other : catégorie générique

Valeurs autorisées :

  • vuln | malware | dynamic | policy | other

- severity (low/medium/high/critical)

Niveau de gravité standardisé :

  • 🟢 low
  • 🟠 medium
  • 🔴 high
  • critical

- details (JSONB)

Données flexibles et typiées par convention selon type.

Exemples de clés utiles (selon le cas) :

{
  "title": "string",
  "description": "string",
  "source": "string",
  "confidence": 0.0,
  "timestamp": "2026-02-24T12:34:56Z",
  "cve": "CVE-2026-12345",
  "cwe": "CWE-79",
  "package": "string",
  "version": "string",
  "fix_version": "string",
  "ioc": {
    "hash": "string",
    "domain": "string",
    "ip": "string",
    "url": "string"
  },
  "policy_id": "string",
  "rule": "string",
  "control": "string",
  "evidence": [
    {
      "type": "log|snippet|stacktrace|file|command|http",
      "summary": "string",
      "data": "string",
      "path": "string",
      "line_start": 0,
      "line_end": 0,
      "timestamp": "2026-02-24T12:34:56Z"
    }
  ],
  "recommendation": "string",
  "references": ["https://example.com/reference-1", "https://example.com/reference-2"]
}

- raw_path (string)

Chemin optionnel vers l’artefact brut (ex: sur PVC) si besoin :

  • logs complets
  • dump sandbox
  • fichier suspect
  • rapport scanner original

Exemple :

  • /pvc/scans/2026-02-24/job-123/report.json
  • /pvc/artifacts/sample-abc123.bin

Polling Harbor scan

Boucle Tokio avec interval(5s) + compteur max → timeout configurable via variable d’environnement.

Parsing YaraHunter

Patch du binaire pour écrire un JSON structuré dans /output/report.json → monté via PVC (persistent volume claim) → lu par l’API.

Statut des images

Refactor tardif : déplacement du statut depuis table images vers static_analyses pour meilleure normalisation.

5. Limites structurelles & dette technique (état décembre 2024)

  • API complètement ouverte (pas d’authentification) → critique si exposée
  • Tout le workflow est synchrone dans la requête initiale → pas de file d’attente
  • Service d’analyse dynamique jamais terminé → réponses mockées
  • Dépendance forte au montage de ~/.kube/config → impossible multi-cluster sans rework
  • Aucune notification (email / Slack / webhook) après décision
  • Frontend cassé dès qu’on upgrade Harbor au-delà de la v2.9
  • Tests : uniquement unitaires sur le domaine (~80 cas) → zéro test d’intégration / E2E
  • Pas de monitoring (logs structurés limités, zéro métrique Prometheus)

6. Ce que nous ferions radicalement différemment aujourd’hui

  1. Ne jamais patcher le frontend Harbor → privilégier webhooks + UI dédiée ou plugin
  2. Utiliser Kyverno ou OPA Gatekeeper pour des politiques d’admission Kubernetes natives
  3. Intégrer Cosign + Fulcio + Rekor (Sigstore) pour signature & SLSA attestations dès le départ
  4. Orchestrer les scans avec Argo Workflows ou Tekton Pipelines (visuel + retry + parallélisme)
  5. Ajouter Prometheus + Loki / Grafana dès les premiers jours
  6. Migrer vers axum au lieu d’Actix-web (plus maintenu et plus ergonomique)
  7. Rendre le malware scanner serverless (Keda / Knative) pour scale-to-zero
  8. Prévoir un CRD Kubernetes pour les demandes d’admission (operator pattern)

7. Conclusion – Valeur réelle du projet

Le code produit n’est pas industrialisable en l’état : c’est un POC ambitieux avec beaucoup de dette technique.

Mais le projet a été extrêmement formateur :

  • Comprendre les limites concrètes de Harbor en profondeur
  • Réaliser à quel point l’asynchrone et les files d’attente sont cruciaux dans les workflows de sécurité supply-chain
  • Apprendre que le “human approval gate” reste souvent plus puissant et flexible qu’un blocage 100 % automatique
  • Découvrir les pièges du patching d’un monolithe open-source (surtout le frontend)
  • Toucher à Rust en conditions réalistes, Kubernetes Jobs, reverse-engineering d’API tierces, parsing de rapports non structurés
  • Expérimenter la difficulté de coordonner 4 personnes sur un projet distribué avec des deadlines académiques

Si nous devions proposer une suite sérieuse aujourd’hui, nous partirions sur :

  • Harbor + webhooks
  • Kyverno / Gatekeeper pour admission policies
  • Argo Workflows pour orchestration des scans
  • UI légère dédiée (ou intégration dans Backstage / Port)
  • Sigstore complet pour la provenance

Mais pour un projet de fin de Master 1, nous sommes plutôt fiers du résultat : une démo qui fonctionne, qui impressionne les jurys et qui nous a appris énormément sur la sécurité des conteneurs et l’architecture de systèmes distribués.


Liens (archives non maintenues) :

Questions techniques bienvenues (schéma DB, extraits Rust, patch YaraHunter, etc.).

Bonne lecture et bons projets sécurité !

Commentaires