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édiaire05 - Capstone : Pipeline DevSecOps complet

Détails

  • 1h
  • Avancé

Objectifs

  • Assembler un pipeline CI/CD avec toutes les couches de sécurité intermédiaire
  • Intégrer Dependabot, CodeQL, Trivy et gestion de secrets dans un seul workflow
  • Implémenter des quality gates de sécurité qui bloquent le déploiement
  • Générer un rapport de sécurité consolidé
Module Sécurité DevOps - Intermédiaire

Exercice 05 : Capstone - Pipeline DevSecOps complet

🎯 Objectifs

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

  • ✅ Créer un pipeline CI/CD avec plusieurs quality gates de sécurité
  • ✅ Combiner CodeQL, Trivy et audit de dépendances dans un workflow unique
  • ✅ Implémenter une logique de blocage conditionnelle selon la sévérité
  • ✅ Générer un rapport de sécurité agrégé publié comme artefact de build
  • ✅ Appliquer la règle : "Shift Left" - sécurité au plus tôt dans le pipeline

Durée estimée : 1h

Difficulté : ⭐⭐⭐☆☆ (Avancé)

Prérequis : Exercices 01 à 04 complétés


📖 Contexte

Vous êtes responsable DevSecOps dans une équipe. On vous demande de construire un pipeline "secure by default" pour tous les nouveaux projets. Ce pipeline doit exécuter automatiquement toutes les vérifications de sécurité et n'autoriser le déploiement que si l'ensemble des quality gates passe.

Le principe "Shift Left" : plus une vulnérabilité est détectée tôt (shift left = plus tôt dans le pipeline), moins elle coûte à corriger.


📋 Énoncé

Construisez un pipeline DevSecOps complet avec Dependabot, CodeQL, Trivy et reporting.


🧭 Déroulement de l'exercice

Tâche 1 : Structure du projet

bash
mkdir devsecops-capstone && cd devsecops-capstone
git init

# Application
cat > package.json << 'EOF'
{
  "name": "devsecops-app",
  "version": "1.0.0",
  "dependencies": {
    "express": "^4.18.0",
    "helmet": "^7.1.0"
  },
  "devDependencies": {
    "jest": "^29.0.0"
  }
}
EOF

cat > app.js << 'EOF'
const express = require('express');
const helmet = require('helmet');

const app = express();
app.use(helmet());  // Headers de sécurité automatiques
app.use(express.json());

app.get('/health', (req, res) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

app.get('/api/user/:id', (req, res) => {
  const userId = req.params.id;

  // Validation de l'ID
  if (!/^\d+$/.test(userId)) {
    return res.status(400).json({ error: 'ID invalide' });
  }

  res.json({ id: userId, name: 'Exemple User' });
});

module.exports = app;
if (require.main === module) {
  app.listen(3000, () => console.log('Server started'));
}
EOF

cat > Dockerfile << 'EOF'
FROM node:22-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY app.js .

RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001
USER nodejs

EXPOSE 3000
HEALTHCHECK --interval=30s CMD wget -qO- http://localhost:3000/health || exit 1
CMD ["node", "app.js"]
EOF

Tâche 2 : Configurer Dependabot

bash
mkdir -p .github
cat > .github/dependabot.yml << 'EOF'
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    groups:
      patches:
        update-types: ["patch"]
  - package-ecosystem: "docker"
    directory: "/"
    schedule:
      interval: "weekly"
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"
EOF

Tâche 3 : Pipeline DevSecOps principal

bash
mkdir -p .github/workflows
cat > .github/workflows/devsecops-pipeline.yml << 'EOF'
name: DevSecOps Pipeline

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

# Permissions minimales (principe du moindre privilège)
permissions:
  contents: read
  security-events: write
  pull-requests: read

env:
  IMAGE_NAME: devsecops-app

jobs:
  # ═══ COUCHE 1 : Audit des dépendances ═══
  dependency-audit:
    name: Audit des dépendances npm
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: 'npm'

      - name: Installer les dépendances
        run: npm ci

      - name: Audit npm (bloquant sur CRITICAL/HIGH)
        run: |
          npm audit --audit-level=high --json > npm-audit.json || true
          CRITICAL=$(cat npm-audit.json | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('metadata',{}).get('vulnerabilities',{}).get('critical',0))")
          HIGH=$(cat npm-audit.json | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('metadata',{}).get('vulnerabilities',{}).get('high',0))")
          echo "CRITICAL: $CRITICAL, HIGH: $HIGH"
          if [ "$CRITICAL" -gt "0" ]; then
            echo "❌ $CRITICAL vulnérabilités CRITICAL détectées"
            exit 1
          fi

      - name: Sauvegarder le rapport
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: npm-audit-report
          path: npm-audit.json

  # ═══ COUCHE 2 : Analyse statique CodeQL ═══
  code-analysis:
    name: Analyse statique CodeQL
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: github/codeql-action/init@v3
        with:
          languages: javascript
          queries: security-and-quality

      - uses: github/codeql-action/autobuild@v3

      - uses: github/codeql-action/analyze@v3
        with:
          category: "/language:javascript"
          output: codeql-results.sarif

      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: codeql-results.sarif

  # ═══ COUCHE 3 : Scanner l'image Docker ═══
  container-security:
    name: Sécurité du conteneur Docker
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build de l'image
        run: docker build -t $IMAGE_NAME:${{ github.sha }} .

      - name: Scanner l'image (bloquant sur CRITICAL)
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: '${{ env.IMAGE_NAME }}:${{ github.sha }}'
          format: 'table'
          exit-code: '1'
          severity: 'CRITICAL'
          ignore-unfixed: true

      - name: Rapport SARIF Trivy
        uses: aquasecurity/trivy-action@master
        if: always()
        with:
          image-ref: '${{ env.IMAGE_NAME }}:${{ github.sha }}'
          format: 'sarif'
          output: 'trivy-results.sarif'

      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: trivy-results.sarif
          category: 'trivy'

  # ═══ RAPPORT FINAL ═══
  security-report:
    name: Rapport de sécurité
    runs-on: ubuntu-latest
    needs: [dependency-audit, code-analysis, container-security]
    if: always()
    steps:
      - name: Récupérer les artefacts
        uses: actions/download-artifact@v4
        with:
          name: npm-audit-report
          path: reports/

      - name: Générer le rapport consolidé
        run: |
          STATUS_DEPS="${{ needs.dependency-audit.result }}"
          STATUS_CODE="${{ needs.code-analysis.result }}"
          STATUS_CONTAINER="${{ needs.container-security.result }}"

          cat > reports/security-summary.md << REPORT
          # Rapport de Sécurité - $(date -u +"%Y-%m-%d %H:%M UTC")

          ## Résumé des quality gates

          | Vérification | Statut |
          |---|---|
          | Audit dépendances npm | $([ "$STATUS_DEPS" = "success" ] && echo "✅ Passé" || echo "❌ Échoué") |
          | Analyse CodeQL | $([ "$STATUS_CODE" = "success" ] && echo "✅ Passé" || echo "❌ Échoué") |
          | Scanner Docker | $([ "$STATUS_CONTAINER" = "success" ] && echo "✅ Passé" || echo "❌ Échoué") |

          ## Commit
          - SHA: ${{ github.sha }}
          - Branch: ${{ github.ref_name }}
          - Auteur: ${{ github.actor }}
          REPORT

          cat reports/security-summary.md

      - name: Publier le rapport
        uses: actions/upload-artifact@v4
        with:
          name: security-report-${{ github.sha }}
          path: reports/
          retention-days: 30

  # ═══ DÉPLOIEMENT (uniquement si tout passe) ═══
  deploy:
    name: Déployer (si tout passe)
    runs-on: ubuntu-latest
    environment: staging
    needs: [dependency-audit, code-analysis, container-security]
    if: |
      github.ref == 'refs/heads/main' &&
      needs.dependency-audit.result == 'success' &&
      needs.code-analysis.result == 'success' &&
      needs.container-security.result == 'success'

    steps:
      - name: Déploiement
        run: echo "✅ Tous les quality gates passés - Déploiement en staging"
EOF

Tâche 4 : Pousser et observer

bash
git add .
git commit -m "feat: pipeline DevSecOps complet avec 3 quality gates"
git push origin main

Observez dans l'onglet Actions :

  1. Les 4 jobs tournent en parallèle (les 3 scans + le rapport)
  2. Le job deploy ne tourne que si les 3 scans sont verts
  3. Dans Security → Code scanning, les résultats CodeQL et Trivy apparaissent

Tâche 5 : Tester le blocage

Introduisez une vulnérabilité pour vérifier que le pipeline bloque :

bash
# Downgrader express vers une version avec CVE
npm install express@4.17.1
git add package.json package-lock.json
git commit -m "test: introduire une vulnérabilité pour tester le blocage"
git push

Vérification : Le job dependency-audit doit échouer si des CRITICAL sont trouvées, ce qui empêche le job deploy de se lancer.


✅ Vérification du résultat

  • .github/dependabot.yml couvre npm, docker et github-actions
  • Le workflow contient les 3 couches de sécurité (deps, code, container)
  • Le job deploy ne se lance que si les 3 quality gates passent
  • Le rapport de sécurité est publié comme artefact de build
  • Le pipeline se visualise correctement dans l'onglet Actions

💡 À retenir

Un pipeline DevSecOps en 3 couches :

Code → npm audit → CodeQL → Trivy Image
                                 ↓ (si tout passe)
                            Déploiement
                                 ↓
                         Rapport de sécurité archivé 30 jours

Shift Left = détection précoce = correction moins coûteuse : une CVE détectée en développement coûte 6x moins cher à corriger qu'une CVE détectée en production.


✨ Solution Complète

Le workflow complet est défini dans .github/workflows/devsecops-pipeline.yml ci-dessus. La clé est le needs conditionnel sur le job deploy qui garantit que les quality gates sont tous verts avant tout déploiement.

Retour au module

Sur cette page

  • 🎯 Objectifs
  • 📖 Contexte
  • 📋 Énoncé
  • 🧭 Déroulement de l'exercice
  • Tâche 1 : Structure du projet
  • Tâche 2 : Configurer Dependabot
  • Tâche 3 : Pipeline DevSecOps principal
  • Tâche 4 : Pousser et observer
  • Tâche 5 : Tester le blocage
  • ✅ Vérification du résultat
  • 💡 À retenir
  • ✨ Solution Complète