DevOpsFacile
AccueilParcours de formationCertificationsModulesCheat SheetÀ Propos
DevOpsFacile

Une plateforme d'apprentissage complète pour maîtriser les pratiques DevOps modernes, du débutant à l'expert.

contact@devopsfacile.fr

Formation

  • Parcours de formation
  • Modules

Informations

  • À Propos
  • Conditions d'utilisation
  • Confidentialité
  • Mentions légales

© 2026 DevOps Facile. Tous droits réservés.

Fait avec pour la communauté DevOps

ModulesSécurité DevOps - Intermédiaire03 - Intégrer Trivy dans un pipeline CI/CD GitHub Actions

Détails

  • 30 minutes
  • Intermédiaire

Objectifs

  • Intégrer Trivy dans GitHub Actions pour scanner les images Docker
  • Bloquer un build si des vulnérabilités CRITICAL sont détectées
  • Générer un rapport SARIF pour afficher les résultats dans GitHub Security
  • Scanner également le filesystem et les fichiers IaC
Module Sécurité DevOps - Intermédiaire

Exercice 03 : Intégrer Trivy dans un pipeline CI/CD GitHub Actions

🎯 Objectifs

À la fin de cet exercice, vous serez capable de :

  • ✅ Construire et scanner une image Docker avec Trivy dans GitHub Actions
  • ✅ Bloquer le pipeline si une vulnérabilité CRITICAL est détectée
  • ✅ Exporter un rapport SARIF pour l'intégration dans GitHub Security
  • ✅ Scanner le filesystem du projet (dépendances + code)
  • ✅ Scanner les fichiers Dockerfile et IaC avec Trivy config

Durée estimée : 30 minutes

Difficulté : ⭐⭐☆☆☆ (Intermédiaire)

Prérequis : Exercice Trivy débutant complété, Docker, Compte GitHub


📖 Contexte

Vous avez appris à utiliser Trivy manuellement dans le module débutant. L'étape suivante est l'intégration CI/CD : chaque image Docker buildée doit être scannée automatiquement avant d'être poussée sur le registre. Si des vulnérabilités critiques sont trouvées, le build échoue et l'image ne part pas en production.

GitHub Actions propose une action officielle aquasecurity/trivy-action qui simplifie cette intégration et peut envoyer les résultats directement dans l'onglet Security de GitHub (via le format SARIF).


📋 Énoncé

Construisez un pipeline GitHub Actions complet avec scan Trivy, blocage sur les CRITICAL, et rapport de sécurité.


🧭 Déroulement de l'exercice

Tâche 1 : Créer une application et un Dockerfile

Créez une application Node.js simple avec un Dockerfile :

bash
mkdir trivy-ci-demo && cd trivy-ci-demo
git init

# Application
cat > app.js << 'EOF'
const http = require('http');
const server = http.createServer((req, res) => {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello from secure container!\n');
});
server.listen(8080, () => console.log('Server running on port 8080'));
EOF

# Dockerfile avec une image de base intentionnellement ancienne
cat > Dockerfile << 'EOF'
# Image ancienne avec des vulnérabilités connues (pour la démonstration)
FROM node:16-alpine

WORKDIR /app
COPY app.js .

# Utilisateur non-root (bonne pratique)
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001
USER nodejs

EXPOSE 8080
CMD ["node", "app.js"]
EOF

# .dockerignore
cat > .dockerignore << 'EOF'
.git
.github
*.md
node_modules
EOF

git add .
git commit -m "feat: application Node.js avec Dockerfile"

Tâche 2 : Créer le workflow GitHub Actions avec Trivy

bash
mkdir -p .github/workflows
cat > .github/workflows/security-scan.yml << 'EOF'
name: Security Scan - Trivy

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  # Job 1 : Scanner le filesystem (dépendances du projet)
  scan-filesystem:
    name: Scanner le code source
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Scanner le filesystem avec Trivy
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          scan-ref: '.'
          format: 'sarif'
          output: 'trivy-fs-results.sarif'
          severity: 'CRITICAL,HIGH'
          exit-code: '0'  # Ne pas bloquer sur le scan filesystem

      - name: Uploader les résultats dans GitHub Security
        uses: github/codeql-action/upload-sarif@v3
        if: always()  # Uploader même si des vulns sont trouvées
        with:
          sarif_file: 'trivy-fs-results.sarif'
          category: 'trivy-filesystem'

  # Job 2 : Builder et scanner l'image Docker
  scan-docker:
    name: Scanner l'image Docker
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Construire l'image Docker
        run: docker build -t mon-app:${{ github.sha }} .

      - name: Scanner l'image avec Trivy (bloquant sur CRITICAL)
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'mon-app:${{ github.sha }}'
          format: 'table'
          exit-code: '1'  # ⚠️ Bloque le pipeline si des CRITICAL sont trouvées
          severity: 'CRITICAL'
          ignore-unfixed: true  # Ignorer si pas de correctif disponible

      - name: Générer le rapport SARIF
        if: always()  # Générer même si le job précédent a échoué
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'mon-app:${{ github.sha }}'
          format: 'sarif'
          output: 'trivy-image-results.sarif'
          severity: 'CRITICAL,HIGH,MEDIUM'

      - name: Uploader le rapport dans GitHub Security
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: 'trivy-image-results.sarif'
          category: 'trivy-docker'
EOF

Indice : Il y a deux étapes Trivy séparées dans le job Docker :

1. Une qui bloque le pipeline (exit-code: '1') mais ne génère pas de SARIF (table format)

2. Une qui génère le rapport SARIF sans bloquer (if: always())

C'est séparé car si on blocait avec le SARIF, on ne pourrait pas uploader les résultats.


Tâche 3 : Scanner les fichiers IaC avec Trivy

Ajoutez un scan des fichiers Dockerfile et configurations Kubernetes :

bash
# Ajouter un scan config au workflow
cat >> .github/workflows/security-scan.yml << 'EOF'

  # Job 3 : Scanner les fichiers de configuration (IaC)
  scan-config:
    name: Scanner les configs IaC
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Scanner Dockerfile et configs K8s
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'config'
          scan-ref: '.'
          format: 'table'
          severity: 'CRITICAL,HIGH'
          exit-code: '0'  # Informatif, ne pas bloquer
EOF

Créez un manifeste Kubernetes pour que Trivy ait quelque chose à analyser :

bash
cat > deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mon-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: mon-app
  template:
    metadata:
      labels:
        app: mon-app
    spec:
      containers:
        - name: mon-app
          image: mon-app:latest
          ports:
            - containerPort: 8080
          # Mauvaise pratique détectée par Trivy :
          # - pas de securityContext
          # - pas de resource limits
          # - image tag "latest"
EOF

Vérification : Trivy doit signaler des problèmes dans deployment.yaml (absence de securityContext, resources, utilisation de latest).


Tâche 4 : Pousser et observer le pipeline

bash
git add .github/ deployment.yaml
git commit -m "ci: intégrer Trivy dans le pipeline GitHub Actions"
git push origin main
  1. Dans l'onglet Actions, observez les 3 jobs s'exécuter
  2. Si le scan Docker échoue sur CRITICAL, le job affiche un ❌
  3. Dans l'onglet Security → Code scanning, les résultats SARIF apparaissent avec :
  • Le fichier/image concerné
  • La CVE et sa description
  • La version corrigée disponible

Indice : Si node:16-alpine n'a pas de CRITICAL (l'image Alpine est bien maintenue), le pipeline passe. Pour tester le blocage, utilisez temporairement FROM node:14 (version EOL avec plus de vulnérabilités).


Tâche 5 : Corriger et améliorer le Dockerfile

Mettez à jour le Dockerfile vers une image récente et observez la diminution des vulnérabilités :

bash
cat > Dockerfile << 'EOF'
# Image récente et maintenue
FROM node:22-alpine

WORKDIR /app
COPY app.js .

# Utilisateur non-root
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001 && \
    chown -R nodejs:nodejs /app
USER nodejs

# Metadata
LABEL org.opencontainers.image.source="https://github.com/votre-org/trivy-ci-demo"

EXPOSE 8080
CMD ["node", "app.js"]
EOF

git add Dockerfile
git commit -m "security: mettre à jour vers node:22-alpine"
git push

Vérification : Le nouveau pipeline doit passer sans CRITICAL pour node:22-alpine.


✅ Vérification du résultat

  • Le workflow security-scan.yml contient 3 jobs (filesystem, docker, config)
  • Le job docker bloque (exit-code: '1') sur les CRITICAL
  • Les rapports SARIF sont uploadés dans GitHub Security
  • L'onglet Security → Code scanning affiche des résultats Trivy
  • deployment.yaml génère des alertes config (securityContext manquant)

💡 À retenir

Structure d'un pipeline de sécurité Docker complet :

Build → Trivy FS scan → Trivy Image scan (bloquant) → Push registre
                                      ↓
                              SARIF → GitHub Security

La règle : ne jamais pousser une image avec des CRITICAL sur le registre. Utiliser ignore-unfixed: true pour ne bloquer que sur les CVE pour lesquelles un fix existe.


✨ Solution Complète

yaml
# Workflow minimal bloquant sur les CRITICAL
- name: Scanner l'image (bloquant)
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: 'mon-app:latest'
    exit-code: '1'
    severity: 'CRITICAL'
    ignore-unfixed: true
Retour au module

Sur cette page

  • 🎯 Objectifs
  • 📖 Contexte
  • 📋 Énoncé
  • 🧭 Déroulement de l'exercice
  • Tâche 1 : Créer une application et un Dockerfile
  • Tâche 2 : Créer le workflow GitHub Actions avec Trivy
  • Tâche 3 : Scanner les fichiers IaC avec Trivy
  • Tâche 4 : Pousser et observer le pipeline
  • Tâche 5 : Corriger et améliorer le Dockerfile
  • ✅ Vérification du résultat
  • 💡 À retenir
  • ✨ Solution Complète