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
.trivyignoreavec 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.11embarque des centaines de CVEs,python:3.11-slimen 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@v1a 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.
Contenu réservé aux abonnés
Ce chapitre fait partie de la formation complète. Abonne-toi pour débloquer tous les contenus.
Débloquer pour 29 CHF/moisLe chapitre 1 de chaque formation est gratuit.
Série pas encore débloquée
Termine la série prérequise d'abord pour accéder à ce contenu.
Aller à la série prérequiseSur cette page
Articles liés
Supply Chain Security : SLSA et SBOM
Comprends les menaces sur la supply chain logicielle, le framework SLSA, la signature avec Sigstore/cosign et la génération de SBOM.
Zero Trust : ne fais confiance à personne
Comprends les principes du Zero Trust, pourquoi le modèle périmétrique est mort, l'architecture ZTA en détail et le modèle BeyondCorp de Google.
mTLS et Service Mesh en pratique
Implémente mTLS, déploie un Service Mesh (Istio/Linkerd), utilise Tailscale, et mets en place le Zero Trust progressivement sur Kubernetes.