Skip to content

HDMTres/TP2-DevSecOps

Repository files navigation

DevSecOps — TP2 : Rapport (format Q/R)

Ce document est rédigé comme un rendu élève, avec les questions du TP puis mes réponses.

Choix de plateforme pour ce TP : GitHub Actions uniquement.

Étape 1 — Structure du pipeline CI/CD (Architecture YAML)

Exercice 1.1 — Comprendre les concepts de base

1) Quelle est la différence entre un job et un step dans GitHub Actions ? Entre un stage et un job dans GitLab CI ?

Réponse (élève)

  • GitHub Actions

    • Un job est un bloc de travail complet exécuté sur un runner.
    • Un step est une action ou commande à l’intérieur d’un job.
    • Donc : un job contient plusieurs steps.
  • GitLab CI

    • Un stage est une grande phase du pipeline (ex: test, security, deploy).
    • Un job est une tâche concrète placée dans un stage.
    • Donc : un stage regroupe un ou plusieurs jobs.

2) Qu’est-ce qu’un runner GitHub Actions ? Quel runner utiliserez-vous (hosted vs self-hosted) ?

Réponse (élève)

Un runner GitHub Actions est la machine qui exécute les jobs du workflow.

Pour ce TP, j’utilise un runner hosted (ubuntu-latest) car :

  • c’est plus rapide à démarrer,
  • il n’y a pas d’infrastructure à maintenir,
  • il convient bien à un TP CI/CD standard.

Le self-hosted est utile si on veut un environnement interne spécifique (réseau privé, outils spéciaux, conformité).


3) Comment définit-on les dépendances entre jobs dans GitHub Actions (mot-clé à chercher dans la doc) ?

Réponse (élève)

Le mot-clé est needs.

Exemple :

  • dependency-scan peut dépendre de secrets-scan avec needs: [secrets-scan].
  • Cela permet d’ordonner les gates et de faire du fail fast.

4) Quelle est l’équivalente GitLab CI du mot-clé "needs" de GitHub Actions ?

Réponse (élève)

L’équivalent direct dans GitLab CI est aussi needs.

  • stages donne l’ordre global,
  • needs permet des dépendances plus fines entre jobs (et peut accélérer le pipeline en évitant d’attendre toute la fin d’un stage).

Mini conclusion (élève)

Sur cette étape, j’ai compris la structure logique d’un pipeline DevSecOps :

  • découper en jobs/gates,
  • ordonner avec needs,
  • exécuter sur des runners adaptés,
  • viser le fail fast pour bloquer au plus tôt en cas de problème sécurité.

Exercice 1.2 — Créer le squelette du pipeline

Option A — GitHub Actions (PLACEHOLDER complétés)

Réponse (élève)

J’ai choisi :

  • push.branches: main, develop, feature/**, test/**
  • pull_request.branches: main, develop
  • schedule.cron: 0 2 * * * (scan quotidien à 02:00 UTC)
  • runs-on: ubuntu-latest
  • checkout: actions/checkout@v4
  • fetch-depth: 0 (indispensable pour l’historique Git complet, surtout pour les scans de secrets)
  • dépendances:
    • dependency-scan attend secrets-scan
    • sast attend secrets-scan
    • container-scan attend sast et dependency-scan

Implémentation dans devsecops.yml.

Option B — GitLab CI (réponse théorique pour le rapport)

Réponse (élève)

Si je devais compléter l’option GitLab CI dans le rapport, je mettrais :

  1. secrets
  2. sca
  3. sast
  4. container
  5. summary

Et pour les variables :

  • SECURE_LOG_LEVEL: info
  • DS_EXCLUDED_PATHS: .git,node_modules,dist,build,target,coverage

⚠️ Remarque : dans le projet, je n’implémente que GitHub Actions.

Étape 2 — Security Gate 1 : Secrets Scanning avec Gitleaks

Exercice 2.1 — Configurer Gitleaks dans GitHub Actions

Réponse (élève) — PLACEHOLDER complétés

J'ai implémenté le job secrets-scan avec les valeurs suivantes :

  • fetch-depth: 0
    → Indispensable car Gitleaks analyse tout l'historique Git, pas seulement le dernier commit. Si on mettait fetch-depth: 1, les secrets dans les anciens commits ne seraient pas détectés.

  • config-path: .gitleaks.toml
    → Chemin vers le fichier de configuration Gitleaks du TP1 (à la racine du projet).

  • if: always()
    → Le rapport doit être uploadé même si le job échoue (quand un secret est détecté). Sinon on perd le rapport détaillé.

  • path: gitleaks-report.json
    → Nom par défaut du rapport généré par gitleaks-action@v2.

  • retention-days: 30
    → Conservation du rapport pendant 30 jours (suffisant pour analyse).

Comportement attendu :

  • Si Gitleaks détecte un secret → exit code non-nul → job échoue → pipeline bloqué ✅
  • Le rapport JSON est uploadé dans les artefacts GitHub pour analyse.

Implémentation : devsecops.yml

Exercice 2.2 — Variante GitLab CI (réponse théorique)

Réponse (élève)

Si j'implémentais Gitleaks en GitLab CI, je compléterais les PLACEHOLDER ainsi :

  • GIT_DEPTH: 0
    → Équivalent de fetch-depth: 0, pour récupérer tout l'historique Git.

  • --source=.
    → Scanner le répertoire courant (racine du projet).

  • --config=.gitleaks.toml
    → Chemin vers la config Gitleaks.

  • --report-format=json
    → Format du rapport (json ou sarif selon besoin).

  • --report-path=gitleaks-report.json
    → Nom du fichier rapport à générer.

  • when: always
    → Uploader l'artefact même si le job échoue.

  • paths: - gitleaks-report.json
    → Fichier à sauvegarder en artefact.

  • expire_in: 30 days
    → Durée de rétention.

⚠️ Dans mon projet, je n'implémente que GitHub Actions.


Exercice 2.3 — Test du Security Gate

Test effectué (élève)

J'ai créé la branche test/secret-gate et ajouté un fichier test-secret.txt avec un faux secret AWS. Le push a été bloqué par GitHub Push Protection (détection côté serveur avant même que le code arrive dans le pipeline).

Question 7 : Quel est le message d'erreur exact affiché dans les logs quand un secret est détecté ?

Message GitHub Push Protection : "Push cannot contain secrets - Amazon AWS Access Key ID (commit: 48e979..., path: test-secret.txt:1) - Amazon AWS Secret Access Key (commit: 48e979..., path: test-secret.txt:2)"

Le secret a été détecté AVANT même d'arriver dans le pipeline CI/CD (protection côté serveur GitHub).

Question 8 : Combien de secondes dure ce job ?

Le job Gitleaks dure environ 5-6 secondes (scan très rapide, d'où son placement en premier gate - fail fast).

Question 9 : Que se passe-t-il pour les jobs dépendants quand Gitleaks échoue ?

Quand le secret est détecté (ou bloqué par GitHub Push Protection), les jobs dépendants (dependency-scan, sast, container-scan, security-summary) sont automatiquement skipped/cancelled car ils ont needs: [secrets-scan]. C'est le principe fail-fast : on économise du temps de CI en bloquant immédiatement.


Étape 3 — Security Gate 2 : SCA avec OWASP Dependency-Check

Exercice 3.1 — Configurer OWASP Dep-Check avec cache NVD

Réponse (élève) — PLACEHOLDER complétés

  • path: (cache)
    ~/.m2/repository/org/owasp/dependency-check-data/ (répertoire où Dep-Check stocke la base NVD)

  • key: (cache)
    ${{ runner.os }}-dep-check-${{ hashFiles('**/package-lock.json', '**/package.json') }} (clé basée sur l'OS et le hash des fichiers de dépendances)

  • restore-keys:
    ${{ runner.os }}-dep-check- (restaure le cache même si le hash a changé)

  • project:
    TP2-DevSecOps (nom du projet)

  • path: (scan)
    . (scanner tout le projet)

  • format:
    HTML,JSON,SARIF (plusieurs formats pour analyse et upload GitHub Security)

  • out:
    reports (répertoire de sortie des rapports)

  • --failOnCVSS
    7 (échec si CVE avec CVSS ≥ 7.0 = HIGH ou CRITICAL)

  • if: (upload SARIF)
    always() (upload même si le job échoue)

  • sarif_file:
    reports/dependency-check-report.sarif

Comportement attendu :

  • Premier run : télécharge la base NVD (~10-15 min)
  • Runs suivants avec cache : ~2-3 min
  • Si CVE CVSS ≥ 7 détectée → job échoue → pipeline bloqué

Implémentation : devsecops.yml

Exercice 3.2 — Variante GitLab CI (réponse théorique)

Réponse (élève)

Si j'implémentais OWASP Dependency-Check en GitLab CI :

  • cache.paths:
    /root/.m2/repository/org/owasp/dependency-check-data/

  • --scan
    . (répertoire à scanner)

  • --format
    JSON,HTML (formats de rapport)

  • --out
    reports (répertoire de sortie)

  • --failOnCVSS
    7 (seuil de blocage)

  • artifacts.paths:
    reports/*

  • reports.dependency_scanning:
    reports/dependency-check-report.json

⚠️ Dans mon projet, je n'implémente que GitHub Actions.


Exercice 3.3 — Analyser les résultats

Question 12 : Combien de temps dure le job sans cache ? Avec cache ?

RÉPONSE : Sans cache (premier run) : 40 secondes environ Avec cache : Le projet est minimal (package.json sans dépendances lourdes), donc le gain de cache n'est pas significatif ici. Sur un vrai projet, le premier run prendrait 10-15 min (téléchargement base NVD) et les suivants ~2-3 min avec cache.

Question 13 : Combien de CVE CRITICAL/HIGH ont été détectées ? Retrouvez-vous les mêmes résultats qu'en TP1 ?

RÉPONSE : Le projet de test est minimal (package.json vide), donc aucune CVE détectée. Dans un vrai projet avec dépendances (comme TP1), OWASP Dependency-Check détecterait les mêmes CVE que le scan manuel.

Question 14 : Comment le rapport apparaît-il dans l'onglet "Security" de GitHub ?

RÉPONSE : Le rapport SARIF apparaît dans l'onglet Security > Code scanning. On y voit :

  • L'outil : dependency-check (version 12.2.1)
  • Le statut du dernier scan
  • Les configurations actives
  • Un lien vers le workflow run

Question 15 : Si le pipeline échoue à cause d'une CVE, comment configurer une exception temporaire sans supprimer le contrôle ?

RÉPONSE : OWASP Dependency-Check supporte un fichier suppression.xml qui permet d'ignorer temporairement une CVE spécifique avec justification. On utilise le paramètre --suppression suppression.xml et on crée un fichier XML contenant les CVE à ignorer avec leur justification et date d'expiration.


Étape 4 — Security Gate 3 : SAST avec Semgrep

Exercice 4.1 — Semgrep avec annotations PR (GitHub Actions)

Réponse (élève) — PLACEHOLDER complétés

  • container.image:
    returntocorp/semgrep (image Docker officielle Semgrep)

  • --config (packs de règles)
    p/owasp-top-ten (règles OWASP Top 10)
    p/secrets (détection de secrets)
    .semgrep/custom-rules.yaml (règles personnalisées du TP1)

  • --output
    semgrep-results.sarif (fichier de sortie SARIF)

  • --severity
    ERROR (seulement les findings de sévérité ERROR feront échouer le job)

  • sarif_file:
    semgrep-results.sarif

Comportement attendu :

  • Semgrep scanne le code avec les règles OWASP + secrets + custom
  • Si finding ERROR détecté → job échoue
  • SARIF uploadé crée des annotations sur les lignes de code dans les PR

Implémentation : devsecops.yml

Exercice 4.2 — Variante GitLab CI (réponse théorique)

Réponse (élève)

Si j'implémentais Semgrep en GitLab CI :

  • SEMGREP_RULES:
    p/owasp-top-ten p/secrets .semgrep/custom-rules.yaml (liste des packs séparés par espace)

⚠️ Dans mon projet, je n'implémente que GitHub Actions.


Exercice 4.3 — Comprendre les annotations et ajuster les règles

Question 16 : Combien de findings Semgrep votre pipeline a-t-il détectés ? Avec quelle sévérité ?

RÉPONSE : 0 findings détectés (commit 331ec43, job SAST réussi en 7 secondes)

Détails du scan :

  • 203 règles exécutées (Community + Custom)
  • 11 fichiers scannés (limité aux fichiers trackés par git)
  • 2 fichiers ignorés via .semgrepignore (node_modules/, Dockerfile)
  • 1 fichier >1MB skippé

Pourquoi 0 findings malgré app.js vulnérable ? → Les règles custom (.semgrep/custom-rules.yaml) utilisent des patterns trop spécifiques qui ne matchent pas le code réel. Par exemple :

  • Règle password = "admin" ne matche pas const adminPassword = "admin";
  • Les packs p/owasp-top-ten et p/secrets n'ont pas détecté les vulnérabilités dans ce code minimal.

Question 17 : Les annotations apparaissent-elles sur les lignes de code dans la PR ? Montrez une capture.

RÉPONSE : Pas d'annotations car 0 findings détectés. Pour tester les annotations Semgrep :

  1. Améliorer les règles custom pour détecter réellement les vulnérabilités
  2. Créer une Pull Request avec du code vulnérable
  3. Les findings apparaîtraient alors comme annotations sur les lignes concernées via l'onglet Security > Code scanning alerts

Le SARIF a bien été uploadé vers GitHub Security tab (catégorie: semgrep-sast).

Question 18 : Identifiez au moins 1 faux positif. Comment écrire une règle d'exclusion (noqa comment ou .semgrepignore) ?

RÉPONSE : Dans ce TP, tous les findings sont des vrais positifs (vulnérabilités réelles dans app.js).

Exemple de faux positif courant : Un test unitaire qui utilise intentionnellement eval() pour tester la sécurité.

3 méthodes pour exclure un faux positif :

Méthode 1 - Commentaire inline nosemgrep :

const result = eval(testCode); // nosemgrep: dangerous-eval-usage

→ Désactive la règle uniquement pour cette ligne

Méthode 2 - Fichier .semgrepignore (déjà créé dans ce projet) :

node_modules/
.git/
test/fixtures/
*.test.js

→ Ignore des fichiers/répertoires entiers (syntaxe .gitignore)

Méthode 3 - Configuration paths.exclude dans la règle :

rules:
  - id: dangerous-eval-usage
    pattern: eval($INPUT)
    paths:
      exclude:
        - "test/**"
        - "**/*.test.js"

→ Exclut certains chemins directement dans la définition de la règle

💡 Préférer nosemgrep pour exceptions ponctuelles et justifiées.

Question 19 : Comparez le temps d'exécution Semgrep vs OWASP Dep-Check. Lequel est plus rapide ? Pourquoi ?

RÉPONSE : Semgrep : 7 secondes (commit 331ec43)
OWASP Dependency-Check : 40 secondes (commit 7b0cd2e, sans cache)

Semgrep est 5-6× plus rapide.

Raisons :

  1. Semgrep : Analyse syntaxique locale (AST pattern matching) sur le code source, pas de réseau requis
  2. OWASP Dep-Check : Doit télécharger et interroger des bases NVD externes, parser les manifests (package.json, pom.xml), calculer les hashes

→ Semgrep = SAST statique rapide
→ Dependency-Check = SCA avec dépendances réseau (BD de vulnérabilités)


Étape 5 — Security Gate 4 : Scan d'image Docker avec Trivy

Exercice 5.1 — Créer un Dockerfile de test volontairement vulnérable

Réponse (élève)

Dockerfile créé : Dockerfile

FROM node:18.0.0-alpine3.14  # Version ancienne avec CVE CRITICAL

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "src/index.js"]

Vulnérabilités intentionnelles :

  1. Image de base obsolète node:18.0.0-alpine3.14 (avril 2022) → CVE CRITICAL attendues
  2. Pas d'instruction USER → conteneur s'exécute en root (mauvaise pratique)
  3. Alpine 3.14 ancien → vulnérabilités dans les packages système

Exercice 5.2 — Configurer Trivy dans GitHub Actions

Réponse (élève) — PLACEHOLDER complétés

  • docker build -t
    tp2-devsecops:${{ github.sha }} (tag avec hash du commit pour traçabilité)

  • image-ref: (scan)
    tp2-devsecops:${{ github.sha }} (référence de l'image buildée)

  • format: (table)
    table (affichage lisible dans les logs du job)

  • exit-code:
    1 (mode bloquant : job échoue si CVE détectées)
    💡 Utiliser 0 pour mode informatif (ne bloque pas le pipeline)

  • severity: (table)
    CRITICAL (bloquer uniquement sur CVE critiques)
    💡 En production : CRITICAL,HIGH recommandé

  • ignore-unfixed:
    false (afficher toutes les CVE, même sans patch)
    💡 En production : true pour ignorer les CVE non patchables

  • severity: (SARIF)
    CRITICAL,HIGH (remonter CRITICAL + HIGH dans GitHub Security tab)

Comportement attendu :

  • Trivy scanne l'image Docker buildée
  • Détecte les CVE dans l'OS (Alpine) et les packages (Node.js)
  • 1ère exécution (table) : affiche les résultats + bloque si CRITICAL
  • 2ème exécution (SARIF) : génère le fichier pour GitHub Security
  • Upload SARIF créé des alertes dans l'onglet Security

Implémentation : devsecops.yml


Exercice 5.3 — Variante GitLab CI (réponse théorique)

Réponse (élève)

Si j'implémentais Trivy en GitLab CI :

  • --exit-code
    1 (job échoue si CVE détectées)

  • --severity
    CRITICAL,HIGH (détecter CRITICAL et HIGH)

  • --format
    json (format compatible avec GitLab Container Scanning report)

⚠️ Dans mon projet, je n'implémente que GitHub Actions.


Exercice 5.4 — Corriger l'image Docker pour passer le gate

Question 20 : Mettez à jour l'image de base vers une version récente et minimale

RÉPONSE (avant correction - commit 3652dfb) : Image vulnérable : node:18.0.0-alpine3.14 (avril 2022)

Trivy détecte : ❌ Pipeline bloqué avec exit code 1

  • CVE CRITICAL : 1 → CVE-2022-37434 (zlib 1.2.12-r0 - heap-based buffer overflow)
  • CVE HIGH : 0
  • CVE MEDIUM : 0
  • OS : Alpine 3.14.6 (version non supportée, plus de mises à jour de sécurité)

⚠️ Warning Trivy : "This OS version is no longer supported by the distribution"

Question 21 : Ajoutez l'instruction USER nonroot

RÉPONSE : Avant (commit 3652dfb) : Pas d'instruction USER → conteneur s'exécute en root ❌

Après correction :

FROM node:20-alpine3.19
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

→ Conteneur s'exécute avec utilisateur non-privilégié ✅

Question 22 : Poussez la correction et vérifiez que le pipeline réussit

RÉPONSE : Après mise à jour du Dockerfile vers node:20-alpine3.19 + ajout USER appuser (commit f9a7242) :

  • Build réussi ✅ (38s)
  • Trivy scan : 0 CVE CRITICAL, 0 CVE HIGH
  • Pipeline : Réussi en 1m 16s
  • SARIF uploadé vers GitHub Security tab

🎯 Le security gate fonctionne parfaitement :

  • Image vulnérable (3652dfb) → Pipeline bloqué ❌
  • Image corrigée (f9a7242) → Pipeline passe ✅

Question 23 : Comparez le nombre de CVE CRITICAL avant et après la correction

RÉPONSE :

Métrique Avant (node:18.0.0-alpine3.14) Après (node:20-alpine3.19)
CVE CRITICAL 1 (CVE-2022-37434 zlib) 0
CVE HIGH 0 0
CVE MEDIUM 0 0
OS Support ❌ Alpine 3.14.6 (EOL) ✅ Alpine 3.19.4 (récent)
User root ❌ Oui (danger) ✅ Non (appuser)
Pipeline ❌ Échoué (exit code 1) ✅ Réussi (1m 16s)
Temps scan ~10s ~10s
Build time ~39s ~38s

Amélioration sécurité : Passage de 1 CVE CRITICAL à 0 CVE = 100% de réduction des vulnérabilités critiques 🎉


Étape 6 — Gestion des Secrets CI/CD et Masquage

Exercice 6.1 — Configurer et tester le masquage

Question 24 : Naviguez vers Settings > Secrets and variables > Actions

RÉPONSE : Pour créer un secret GitHub :

  1. Aller sur https://github.com/HDMTres/TP2-DevSecOps/settings/secrets/actions
  2. Cliquer sur "New repository secret"
  3. Name : TEST_API_TOKEN
  4. Secret : test-token-do-not-use-12345
  5. Cliquer "Add secret"

✅ Secret créé (capture d'écran à ajouter)

Question 25 : Créez un secret TEST_API_TOKEN

RÉPONSE : ✅ Secret TEST_API_TOKEN créé dans GitHub Actions Secrets avec la valeur test-token-do-not-use-12345

Question 26 : Ajoutez un step qui utilise ce secret et vérifiez que sa valeur est masquée

RÉPONSE : ✅ Job de test ajouté dans le workflow (commit f5d4e0c) :

test-secret-masking:
  name: "🔐 Test Secret Masking"
  runs-on: ubuntu-latest
  steps:
    - name: Test secret masking
      env:
        API_TOKEN: ${{ secrets.TEST_API_TOKEN }}
      run: |
        echo "Testing secret masking..."
        echo "Token value: $API_TOKEN"
        echo "Token length: ${#API_TOKEN}"

Résultat dans les logs (commit f5d4e0c) :

Testing secret masking...
Token value: ***
Token length: 27

Le secret est bien masqué avec ***
✅ La longueur (27 caractères) est affichée mais pas la valeur

Question 27 : Essayez d'afficher le secret avec echo puis vérifiez ce que vous voyez dans les logs

RÉPONSE : ✅ Test effectué : echo "Token value: $API_TOKEN" → Résultat : Token value: ***

GitHub Actions masque automatiquement toutes les occurrences de la valeur du secret dans les logs.

⚠️ Attention aux contournements :

  • echo "$SECRET" | base64 → secret visible en base64
  • echo "${SECRET:0:5}" → premiers caractères visibles
  • Les secrets dans les URLs d'erreur peuvent fuiter

💡 Bonne pratique : Ne jamais logger, encoder ou manipuler un secret dans les logs.


Exercice 6.2 — OIDC — Authentification sans secret permanent

Question 28 : Différence entre secret GitHub (longue durée) et token OIDC (éphémère)

RÉPONSE : Un secret GitHub permanent a une durée de vie illimitée et nécessite une rotation manuelle. Si compromis, il donne un accès permanent. Un token OIDC est temporaire (~1h), jamais stocké, et expire automatiquement. En cas de compromission, l'accès est limité dans le temps. Exemple : AWS Access Key (permanent) vs credentials STS via OIDC (temporaires).

Question 29 : Comment GitHub Actions obtient des credentials AWS temporaires sans clé AWS ?

RÉPONSE : GitHub émet un JWT signé contenant le repo, workflow et expiration. L'action aws-actions/configure-aws-credentials présente ce JWT à AWS STS. AWS vérifie le JWT via IAM Identity Provider et retourne des credentials temporaires (ACCESS_KEY, SECRET_KEY, SESSION_TOKEN) valides 1h. Aucun secret permanent stocké.

Question 30 : Quel service AWS permet cette authentification ?

RÉPONSE : IAM Identity Provider (OIDC) + AWS STS. Configuration : créer un OIDC Provider pointant vers GitHub, créer un IAM Role avec Trust Policy autorisant AssumeRoleWithWebIdentity, attacher les policies nécessaires (ECR, S3, etc.).


Exercice 6.3 — Inventaire des secrets du pipeline

Tableau des secrets utilisés dans TP2-DevSecOps :

Nom du secret Usage Niveau d'exposition Alternative recommandée
GITHUB_TOKEN Upload SARIF, annotations PR, artefacts ✅ Automatique (GitHub) Déjà éphémère par défaut
TEST_API_TOKEN Test masquage (Exercice 6.1) 🟡 Secret permanent Supprimer après l'exercice

Secrets potentiels selon extension du projet :

Nom du secret Usage Niveau d'exposition Alternative recommandée
DOCKER_HUB_TOKEN Push image Docker Hub 🔴 Secret permanent OIDC avec GitHub Container Registry (GHCR)
AWS_ACCESS_KEY Déploiement AWS 🔴 Secret permanent ⭐ OIDC avec aws-actions/configure-aws-credentials
SEMGREP_APP_TOKEN Semgrep Cloud (optionnel) 🔴 Secret permanent Mode CLI local sans token

Légende :

  • ✅ Sécurisé (éphémère, géré auto)
  • 🟡 Acceptable temporairement
  • 🔴 Risque (à remplacer par OIDC)

Bonnes pratiques appliquées :

  1. ✅ Utilisation exclusive de GITHUB_TOKEN (éphémère)
  2. ✅ Aucun secret permanent dans le workflow production
  3. ✅ Pas de push d'image (pas de Docker token)
  4. ✅ Semgrep en mode CLI local

Étape 7 — Quality Gates et Politique de Sécurité

Exercice 7.1 — Définir votre politique de Quality Gates

Tableau Quality Gates implémenté :

Security Gate Condition bloquante Condition informative Justification
Gitleaks Tout secret détecté = BLOCK N/A Zéro tolérance secrets - risque immédiat de compromission
OWASP Dep-Check CVE CRITICAL (CVSS ≥ 9.0) = BLOCK CVE HIGH (CVSS 7-8.9) = INFO Les CVE CRITICAL nécessitent action immédiate, les HIGH peuvent être plannifiées
Semgrep SAST Finding ERROR = BLOCK Finding WARNING = INFO Les erreurs sont des vulnérabilités confirmées, les warnings nécessitent review
Trivy container CVE CRITICAL = BLOCK CVE HIGH = INFO Image de base vulnérable critique inacceptable en production

Implémentation dans le workflow :

  • Gitleaks : Pas de continue-on-error → bloque automatiquement
  • OWASP : --failOnCVSS 9 → bloque sur CRITICAL uniquement
  • Semgrep : --severity ERROR --error → bloque sur ERROR
  • Trivy : exit-code: 1 + severity: CRITICAL → bloque sur CRITICAL

Exercice 7.2 — Job de synthèse Security Summary

PLACEHOLDER complété :

  • if:${{ success() }} (s'exécute seulement si tous les jobs précédents réussissent)

Implémentation : devsecops.yml

Le job security-summary génère un tableau récapitulatif dans l'onglet Summary du workflow avec le statut de chaque security gate. Il utilise la variable $GITHUB_STEP_SUMMARY pour afficher du Markdown formaté directement dans l'interface GitHub Actions.

Exemple de sortie :

## 🛡️ Security Scan Summary
| Gate | Status | Details |
|------|--------|---------|
| 🔐 Secrets | ✅ Passed | No secrets detected |
| 📦 SCA | ✅ Passed | 0 CVE CRITICAL |
| 🔍 SAST | ✅ Passed | 1 finding (corrected) |
| 🐳 Trivy | ✅ Passed | 0 CVE CRITICAL |

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors