Aller au contenu principal
SécuritéCloudSupply ChainDevSecOps

Scanning et pipeline sécurisé

30 min de lecture Sécurité Cloud — Chapitre 6

Scanning de vulnérabilités avec Trivy et Grype, GitHub Advanced Security, pipeline sécurisé bout en bout et protection contre la dependency confusion.

Tu peux avoir les meilleurs firewalls, le zero-trust le plus strict et des politiques réseau impeccables — si ton image Docker embarque une CVE critique connue depuis 6 mois, tout ça ne sert à rien. Le scanning de vulnérabilités est le filet de sécurité qui attrape ce que le développement laisse passer. Combiné à un pipeline CI/CD structuré, il transforme la sécurité d’une corvée post-déploiement en un processus automatique, continu et bloquant. Ce cours te montre comment mettre en place cette chaîne complète avec les outils qui font référence aujourd’hui.

Scanning de vulnérabilités : Trivy et Grype

Deux outils dominent le marché du vulnerability scanning open-source. Ils sont complémentaires et souvent utilisés ensemble dans les pipelines matures.

Trivy (Aqua Security) est le couteau suisse : il scanne les images Docker, les repos Git, les fichiers IaC (Terraform, manifests K8s), les SBOMs, et détecte même les secrets. Grype (Anchore) est plus spécialisé sur le scanning de vulnérabilités pur, et s’intègre parfaitement avec Syft pour la chaîne SBOM → scan.

Trivy couvre plus de cas d’usage. Grype est souvent plus rapide et produit moins de faux positifs sur les dépendances applicatives. La bonne pratique en entreprise : utiliser les deux et comparer les résultats.

Voici les commandes essentielles pour Trivy — du scan basique au rapport CI/CD :

# Scanner une image Docker (vue complète)
trivy image ghcr.io/org/myapp:latest

# Filtrer sur les vulns critiques et hautes uniquement
trivy image --severity CRITICAL,HIGH ghcr.io/org/myapp:latest

# Scanner les fichiers IaC (Terraform, K8s manifests)
trivy config ./terraform/

# Scanner un SBOM existant (chaîne Syft → Trivy)
trivy sbom sbom.cdx.json

# Rapport JSON pour intégration CI
trivy image --format json --output report.json ghcr.io/org/myapp:latest

# Ignorer des CVEs documentées (faux positifs, risque accepté)
cat > .trivyignore << 'EOF'
# Faux positif confirmé par l'équipe sécu
CVE-2023-12345
# Risque accepté — ticket SEC-456
CVE-2023-67890
EOF
trivy image --ignorefile .trivyignore ghcr.io/org/myapp:latest

Et pour Grype, qui brille particulièrement dans la chaîne SBOM → vulnérabilités :

# Scanner une image directement
grype ghcr.io/org/myapp:latest

# Pipeline optimal : Syft génère le SBOM, Grype le scanne
syft ghcr.io/org/myapp:latest -o cyclonedx-json | grype

# Bloquer le pipeline si CVE critique détectée
grype ghcr.io/org/myapp:latest --fail-on critical

💡 Tip DevOps : Utilise --fail-on critical en CI mais pas --fail-on high au début — tu risques de bloquer tous les builds. Commence par alerter sur les HIGH, et monte le niveau de blocage progressivement quand l’équipe a pris le rythme de remédiation.

⚠️ Attention : Les bases de vulnérabilités de Trivy et Grype ne sont pas identiques. Trivy agrège NVD, GitHub Advisory, Red Hat, Alpine, etc. Grype utilise sa propre base Anchore. Un scan Trivy clean ne garantit pas un scan Grype clean — et inversement. C’est pourquoi les deux en parallèle apportent une vraie valeur.

GitHub Advanced Security : la sécurité intégrée au workflow

GitHub Advanced Security (GHAS) apporte trois piliers de sécurité directement dans l’interface du développeur — pas dans un dashboard séparé que personne ne consulte.

  • Code Scanning (CodeQL) — analyse statique SAST qui détecte les failles dans ton propre code : SQL injection, XSS, path traversal, etc.
  • Secret Scanning — détecte les clés API, tokens et mots de passe commités. Avec Push Protection, le push est bloqué avant même que le secret n’atteigne le repo.
  • Dependabot — scan continu des dépendances (SCA), alertes de vulnérabilités et PRs automatiques de mise à jour.

L’intérêt majeur de GHAS : les alertes apparaissent dans la PR, pas dans un rapport hebdomadaire. Le développeur voit le problème au moment où il peut le corriger, pas trois semaines après.

Voici la configuration CodeQL pour un scan SAST multi-langage en CI/CD :

# .github/workflows/codeql.yml
name: CodeQL Analysis
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 6 * * 1'  # Scan hebdo le lundi

jobs:
  analyze:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    strategy:
      matrix:
        language: ['javascript', 'python', 'go']
    steps:
      - uses: actions/checkout@v4
      - name: Initialize CodeQL
        uses: github/codeql-action/init@v3
        with:
          languages: ${{ matrix.language }}
          queries: +security-extended,security-and-quality
      - name: Autobuild
        uses: github/codeql-action/autobuild@v3
      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v3

Et la configuration Dependabot pour gérer automatiquement les mises à jour de dépendances :

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
      day: "monday"
    groups:
      production-dependencies:
        patterns: ["*"]
        update-types: ["minor", "patch"]
    open-pull-requests-limit: 10
    labels: ["dependencies", "security"]

  - package-ecosystem: "docker"
    directory: "/"
    schedule:
      interval: "weekly"

  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"

🧠 À retenir : Dependabot ne se limite pas aux packages npm ou pip. Configure-le aussi pour tes images Docker de base et tes GitHub Actions. Une action tierce compromise (uses: random-org/action@v1) est un vecteur d’attaque supply chain classique — Dependabot te prévient quand une mise à jour de sécurité existe.

Pipeline sécurisé bout en bout

Un pipeline CI/CD sécurisé n’est pas un job “security” ajouté à la fin. C’est une architecture en couches où chaque étape renforce la suivante : pre-commit → analyse statique → build hermétique → scanning → signature → admission control → monitoring runtime.

Voici un workflow GitHub Actions complet qui implémente cette architecture :

# .github/workflows/secure-pipeline.yml
name: Secure Pipeline
on:
  push:
    branches: [main]
  pull_request:
env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  sast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run Semgrep (SAST + OWASP Top 10)
        uses: returntocorp/semgrep-action@v1
        with:
          config: p/security-audit p/owasp-top-ten p/secrets

  build:
    needs: sast
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      id-token: write
    outputs:
      digest: ${{ steps.build.outputs.digest }}
    steps:
      - uses: actions/checkout@v4
      - uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Build and push
        id: build
        uses: docker/build-push-action@v5
        with:
          push: true
          tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
          sbom: true
          provenance: true

  security:
    needs: build
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      id-token: write
      security-events: write
    steps:
      - uses: sigstore/cosign-installer@v3
      - name: Trivy scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
          format: 'sarif'
          output: 'trivy-results.sarif'
          severity: 'CRITICAL,HIGH'
          exit-code: '1'
      - name: Upload results to GitHub Security
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: 'trivy-results.sarif'
      - name: Sign image (keyless)
        run: cosign sign --yes ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.digest }}

🔥 Cas réel : Une scale-up fintech européenne a réduit son MTTR (Mean Time To Remediate) de 45 jours à 3 jours après avoir implémenté ce type de pipeline. Le secret : les vulnérabilités critiques bloquent le merge. Pas de négociation, pas de “on verra plus tard”. L’équipe a d’abord résisté, puis a constaté que 80% des CVE critiques se résolvaient en changeant simplement l’image de base.

Dependency confusion et lockfiles

La dependency confusion est une attaque redoutablement simple : un attaquant publie un package malveillant sur un registre public (npm, PyPI) avec le même nom qu’un de tes packages privés internes. Comme les gestionnaires de paquets préfèrent souvent la version la plus récente, ils installent la version 99.0.0 de l’attaquant au lieu de ta version 1.2.0 privée.

La protection passe par deux mécanismes : le scoping des registres et les lockfiles.

# .npmrc — Rediriger les packages @company vers le registre privé
@company:registry=https://npm.company.com/
# Tout le reste va sur npm public
registry=https://registry.npmjs.org/

# En CI : TOUJOURS utiliser les commandes "frozen"
npm ci                           # au lieu de npm install
yarn install --frozen-lockfile
pnpm install --frozen-lockfile
pip install --require-hashes -r requirements.txt

⚠️ Attention : Un npm install en CI met à jour le lockfile silencieusement. Un npm ci échoue si le lockfile ne correspond pas au package.json. C’est exactement le comportement que tu veux en CI — tout écart doit être détecté et corrigé par le développeur, pas résolu automatiquement par le pipeline.

💡 Tip DevOps : Ajoute un pre-commit hook qui vérifie que le lockfile est commité et à jour. Les lockfiles non commités sont le premier vecteur de dependency confusion en entreprise. Certaines équipes ajoutent même un job CI dédié qui compare le hash du lockfile entre le commit et ce que npm install produirait.

Bonnes pratiques et pièges à éviter

Ce qui fonctionne en entreprise :

  • Définis des SLAs de remédiation : critique = 24h, high = 7 jours, medium = 30 jours. Sans deadline, rien ne bouge.
  • Bloque le merge sur les CVE critiques dès le départ — c’est le seul levier qui force l’action immédiate.
  • Intègre les résultats Trivy au format SARIF dans l’onglet Security de GitHub — les développeurs n’iront jamais consulter un dashboard externe.
  • Fais tourner un scan schedule hebdomadaire en plus des scans PR — les nouvelles CVE tombent sur des dépendances déjà déployées.
  • Documente chaque .trivyignore avec un numéro de ticket — un ignore sans justification est un risque ignoré.

Les pièges classiques :

  • Scanner sans jamais corriger — ça crée de la “security fatigue” et l’équipe finit par ignorer toutes les alertes
  • Ignorer les vulnérabilités dans les images de base — python:3.11 embarque des centaines de CVEs, python:3.11-slim en a 10x moins
  • Activer tous les checks d’un coup — commence par les critiques, ajoute progressivement
  • Ne pas scanner les GitHub Actions tierces — uses: random-org/malicious-action@v1 a le même accès que ton code

🔥 Cas réel : En 2021, un chercheur en sécurité (Alex Birsan) a démontré la dependency confusion en ciblant Apple, Microsoft et PayPal. En publiant des packages avec les noms internes de ces entreprises sur npm et PyPI, il a obtenu l’exécution de code sur des serveurs internes des trois entreprises. Récompense totale : plus de 130 000$ en bug bounties. L’attaque reposait sur un principe simple : les registres publics avaient priorité sur les registres privés.

Résumé

Le scanning de vulnérabilités et le pipeline sécurisé forment un couple indissociable. Trivy est le scanner polyvalent (images, IaC, repos, secrets), Grype excelle dans la chaîne SBOM → vulnérabilités, et les deux ensemble couvrent mieux qu’un seul. GitHub Advanced Security intègre CodeQL (SAST), Secret Scanning et Dependabot directement dans le workflow développeur. Un pipeline sécurisé bout en bout enchaîne analyse statique, build hermétique, scanning, signature et admission control — chaque couche bloquante. Enfin, la dependency confusion se prévient par le scoping des registres et les lockfiles committés avec des installs frozen en CI. La sécurité supply chain n’est pas un projet one-shot : c’est un processus continu, automatisé, et intégré dans chaque commit.

🖥️ Pratique sur ton propre serveur

Pour suivre Sécurité Cloud en conditions réelles, tu as besoin d'un VPS. DigitalOcean offre 200$ de crédit gratuit pour démarrer.

Obtenir 200$

Articles liés