hors suivi
Leçon

Ce qui vous est demandé aujourd'hui

Jour 1 · Auditer, prouver et soutenir · 20 min

Une journée pour transformer quinze jours de travaux en trois livrables qu'un tiers peut vérifier, et pour les défendre vingt minutes devant un jury. Aucune notion nouvelle aujourd'hui : tout ce dont vous avez besoin a été construit entre le 3 et le 20 août. Ce que vous n'avez jamais fait, en revanche, c'est le faire tenir ensemble en une seule fois.

J1 Plateforme 11 h 00 5 jobs verts J2 Preuves 12 h 15 10 rejeux J3 Rapport 14 h 50 audit livré J4 Répétition 16 h 00 repli prêt Soutenance Jury 16 h 10 20 minutes
Quatre jalons, puis la soutenance. Chacun se valide avant le suivant ; aucun ne se rattrape le lendemain, il n'y a pas de lendemain.

À quelle heure vous faites quoi

La journée est minutée et les jalons sont des rendez-vous : Samer les a dans son agenda, et il suit à distance.

CréneauCe qui s'y joue
9 h 00 – 9 h 30Cette leçon, puis le quiz de cadrage
9 h 30 – 11 h 00Jalon 1 — la plateforme remonte et les cinq jobs passent au vert
11 h 00 – 12 h 15Jalon 2 — les dix vulnérabilités rejouées, une preuve de fermeture chacune
12 h 15 – 13 h 15Déjeuner
13 h 15 – 14 h 50La leçon sur le rapport d'audit, puis jalon 3 — rédaction
14 h 50 – 16 h 00La leçon sur la soutenance, puis jalon 4 — répétition chronométrée et plan de repli
16 h 00 – 17 h 00Dernière vérification, soutenance à 16 h 10, retour du jury, clôture du parcours

Les trois livrables

Ni plus, ni moins. Tout le reste de la journée sert ces trois-là.

LivrableCe qui le rend recevableConstruit en
La plateformedevsecops-lab:hardened tourne, le cluster dso-lab répond, Juice Shop est joignable sur 3000M1 · M3
Le pipelineLes cinq jobs — secrets, sast, sca, dast, image — verts sur main, et rouges dès qu'une faille revientM1 J3 · M2 · M3
Le rapport d'auditrapports/audit-devsecops-lab.md au format des six parties, une preuve rejouable par findingplan type posé en M5, rempli aujourd'hui
Ce que la journée ne vous demande pas

Aucune vulnérabilité nouvelle à corriger. Aucun outil à installer. Aucun manifeste Kubernetes à écrire. Si vous vous surprenez à ouvrir un éditeur sur app.py pour autre chose que la régression volontaire du jalon 4, arrêtez-vous : vous êtes en train de fabriquer du travail au lieu de prouver celui qui est fait.

Les dix VULN-NN ont été fermées en M1, M2, M3 et M5. Ce qui manque n'est pas une correction de plus, c'est la preuve, aujourd'hui, sur le HEAD d'aujourd'hui, que chacune est effectivement fermée.

Le rappel qui ne se négocie pas

Votre périmètre reste localhost, aujourd'hui comme le 3 août

La journée fait rejouer des exploits réels et relance Juice Shop. Le cadre du 3 août s'applique intégralement : vous n'attaquez que ce que vous déployez vous-même, sur votre postedevsecops-lab sur 5000 et juice-shop sur 3000. Jamais sur Internet, jamais sur une ressource de Caplogy, jamais sur le système d'un tiers sans mandat écrit. Ce n'est pas une précaution de style : les articles 323-1 et suivants du Code pénal punissent l'accès non autorisé à un système, même sans dommage.

Cela vaut aussi pendant la démonstration. Si le jury vous demande « et sur un vrai site, ça donnerait quoi ? », la bonne réponse est de décrire, pas de montrer.

La grille de soutenance

La voici en entier, à 9 h 05. Vous devez savoir à quoi vous consacrez vos heures.

CritèreCe que le jury regardePoids
Le pipeline refuse la failleUne régression poussée en direct fait rougir la CI et bloque la fusion. C'est la démonstration centrale de la journée●●●
Les dix failles sont closesUne preuve rejouable par VULN-NN — la même commande qu'à l'aller, un résultat différent●●●
Justification des choixPourquoi ce seuil de sévérité, pourquoi Calico, pourquoi ce périmètre. Un choix non justifié vaut un choix subi●●●
Durcissement effectifImage non-root, PSA qui rejette, NetworkPolicy qui bloque — montrés, pas déclarés●●
Rapport d'auditLes six parties, un vecteur CVSS complet par finding, une remédiation vérifiable●●
Posture d'attaquantLe rapport de pentest Juice Shop du 20 août tient debout sous questions●●
SoutenanceVingt minutes tenues, démonstration maîtrisée, réponses aux questions●●
Ce qui n'est pas évalué

Le nombre d'outils installés sur votre poste. La longueur du rapport. Le score brut de kube-bench — un cluster kind n'est pas durci, ses FAIL sont attendus et vous l'avez écrit vous-même le 13 août.

Une plateforme modeste qui tourne, dont chaque garde-fou est démontrable et chaque choix explicable, vaut mieux qu'un dispositif ambitieux à moitié remonté. C'est le conseil le plus utile de cette page.

Pour vous repérer

Le piège du jour n'est pas technique, il est de calendrier : les deux jalons qui pèsent le plus dans la grille — le pipeline vert et les dix preuves — sont ceux du matin, et le matin ne dure que trois heures et quart. Tout ce qui déborde de 12 h 15 se paie sur le rapport, puis sur la répétition, c'est-à-dire sur les deux choses qui rendent la soutenance tenable.

Auto-vérification en trente secondes : sur les sept lignes de la grille, dites laquelle vous inquiète le plus et à quelle heure de la journée elle se joue. Si vous ne savez pas répondre à la seconde partie, relisez le tableau des créneaux avant de lancer le premier conteneur.

✓ terminé
Quiz

Quiz — Ce que le jury vérifiera

Jour 1 · Auditer, prouver et soutenir · 10 min

1. Votre job image lance trivy image --severity HIGH,CRITICAL --exit-code 1. Une CVE de sévérité MEDIUM apparaît dans l'image. Que fait le pipeline ?

2. Vous avez fermé VULN-03 (injection de commande) le 7 août. Qu'est-ce qui le prouve au jury ?

3. Votre netpol.yaml est appliqué et kubectl get netpol -n dso le liste. Que devez-vous montrer en plus ?

4. Le jury demande pourquoi votre registre de risques cote en CVSS et en DREAD.

Pour vous repérer

Ces quatre questions ne mesurent pas votre score, elles vous rendent quatre réponses que le jury vous demandera cet après-midi presque mot pour mot. Après correction, reprenez chaque option que vous aviez cochée à tort et dites à voix haute ce qui la rend fausse, sans relire l'explication — si vous n'y arrivez pas, notez-la sur la fiche que vous préparerez au jalon 4.

La deuxième question est celle qui structure toute votre matinée : si vous l'avez manquée, relisez-la avant de lancer le jalon 2, sans quoi vous produirez un tableau de captures d'écran au lieu d'un tableau de preuves.

✓ terminé
Travaux pratiques

Jalon 1 — La plateforme remonte, les cinq jobs passent au vert

Jour 1 · Auditer, prouver et soutenir · 1 h 30

Obtenir, une fois et pour de bon, un état de départ démontrable : tout tourne, tout est vert, et vous savez ce qui ne l'est pas.

L'ordre des étapes n'est pas négociable

Le cluster kind passe en deuxième position, avant l'image et avant le pipeline. Ce n'est pas un caprice : c'est le composant que vous n'avez plus touché depuis le 13 août, et Docker a redémarré au moins une fois depuis. Si le cluster doit être reconstruit, cela prend huit à dix minutes — supportable à 9 h 40, impossible à 16 h 05.

Règle de coupure : à 10 h 15, ce qui ne remonte pas ne remontera pas. Vous le notez dans journal-incidents.md, vous basculez ce point sur le plan de repli du jalon 4, et vous avancez. Un jalon 1 fini à 11 h avec un composant en moins vaut infiniment mieux qu'un jalon 1 fini à midi.

  1. Le réseau et les deux cibles. dso-net existe depuis le 3 août ; la commande de création échoue si c'est le cas, et c'est le résultat attendu.
    docker network create dso-net 2>/dev/null || echo 'dso-net : deja la, tres bien'
    
    docker start juice-shop devsecops-lab 2>/dev/null
    docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
    
    # juice-shop met 30 a 60 s avant de repondre : on l'interroge, on n'attend pas au juge
    curl -s -o /dev/null -w '%{http_code}\n' http://localhost:3000/
    curl -s -o /dev/null -w '%{http_code}\n' http://localhost:5000/
  2. Le cluster, tout de suite. S'il ne répond pas, ses deux nœuds sont des conteneurs arrêtés : on les redémarre, on réexporte le kubeconfig, et on attend que les nœuds passent Ready. Calico met environ une minute à se remettre en route.
    kind get clusters                       # attendu : dso-lab
    kubectl get nodes
    
    # si la commande ci-dessus echoue ou n'en finit pas :
    docker start dso-lab-control-plane dso-lab-worker
    kind export kubeconfig --name dso-lab
    kubectl wait --for=condition=Ready node --all --timeout=120s
    
    kubectl -n dso get pods,netpol
    kubectl -n kube-system get pods | grep -i calico
  3. Décision à prendre ici, pas plus tard. Si à 10 h 15 le cluster ne répond toujours pas, vous ne le reconstruisez pas : vous écrivez la ligne dans journal-incidents.md, et les deux démonstrations Kubernetes de cet après-midi — le pod root rejeté par PSA, le flux bloqué par la NetworkPolicy — passeront par les captures du 13 août. Le jury accepte très bien une preuve enregistrée annoncée comme telle ; il n'accepte pas cinq minutes de silence devant un terminal.
  4. L'image durcie. Vous la reconstruisez pour être certain que le Dockerfile du dépôt est bien celui qui produit l'image que vous montrerez, puis vous rejouez le gate exactement comme le pipeline le lance.
    cd ~/devsecops-lab
    docker build -t devsecops-lab:hardened .
    
    docker run --rm devsecops-lab:hardened id      # attendu : uid=10001
    
    trivy image --severity HIGH,CRITICAL --exit-code 1 --format json \
      --output artefacts/trivy-image-2026-08-21.json devsecops-lab:hardened
    echo "code de sortie : $?"                     # attendu : 0
  5. Le dépôt. Trois vérifications de trente secondes qui valent chacune une question de jury : l'arbre est propre, le dernier commit est signé, et rien de secret n'est suivi par Git.
    git status --short                       # doit ne rien afficher
    git log --show-signature -1 --oneline    # attendu : Good "git" signature
    git ls-files | grep -E '(^|/)\.env$|\.key$|^artefacts/'   # doit ne rien afficher
  6. Le pipeline complet. Vous poussez une branche sans modification de code — un simple horodatage dans le journal suffit — et vous ouvrez la pull request : c'est le seul moyen de voir les cinq jobs s'exécuter dans les conditions de la protection de main.
    git checkout -b feat/pfr-verification
    printf '\n## 2026-08-21 — verification de bout en bout (PFR)\n' >> journal-incidents.md
    git add journal-incidents.md
    git commit -m 'chore(pfr): verification de bout en bout du pipeline'
    git push -u origin feat/pfr-verification
    
    # puis, dans le navigateur : ouvrir la PR, onglet Actions, et regarder les cinq jobs.
    # secrets et sast repondent en 1 a 2 min ; sca en 2 a 3 ; image en 2 ;
    # dast est le plus lent (4 a 6 min) : c'est lui qui fixe la duree totale du run.
  7. Les cinq jobs doivent être verts : secrets, sast, sca, dast, image. Si l'un est rouge, triez avant de corriger — les deux cas ne se traitent pas pareil. Une régression réelle (une règle Semgrep qui correspond de nouveau, une CVE HIGH apparue dans une image de base rafraîchie) se corrige, et c'est du travail utile. Une défaillance d'environnement (dépassement de délai sur le téléchargement d'une image, quota de runner, indisponibilité de GitHub) ne se corrige pas : vous relancez une fois, et si cela recommence, vous notez et vous basculez sur act à l'étape suivante.
  8. Le repli hors ligne, vérifié maintenant et pas au moment où vous en aurez besoin. Deux jobs seulement ont été validés sous act le 5 août : ce sont les deux que vous montrerez si le réseau tombe.
    brew install act        # si ce n'est pas deja fait
    act -j secrets
    act -j sast
    
    # ne tentez pas dast ni image sous act : ils n'ont jamais ete repetes ainsi,
    # et une soutenance n'est pas le moment de decouvrir comment ils s'y comportent.
  9. Fusionnez la pull request, et vérifiez que main porte bien le run vert. Puis notez dans journal-incidents.md l'heure de fin du jalon, la durée totale du run, et tout ce qui n'est pas remonté. Cette dernière liste n'est pas un aveu : c'est la matière de la partie 5 de votre rapport et de votre plan de repli.
Questions de réflexion — à préparer par écrit
  • Combien de temps a duré le run complet, et quel job en consomme la moitié ?
  • Qu'est-ce qui, dans votre plateforme, n'est pas remonté seul après huit jours sans y toucher — et quel geste le remet ?
Pour vous repérer

Quatre-vingt-dix minutes pour six composants : vous avez environ un quart d'heure chacun. Le seul qui mérite qu'on dépasse est le cluster, et encore, jusqu'à 10 h 15 seulement. Tout le reste — image, dépôt, pipeline — se vérifie par des commandes que vous avez déjà lancées des dizaines de fois : si l'une d'elles vous surprend, c'est un constat à noter, pas un chantier à ouvrir.

L'erreur classique de ce créneau est de vouloir un tableau parfaitement vert. Ce n'est pas le but : le but est de savoir, à 11 h précises, ce qui est vert, ce qui est rouge et pourquoi. Un pipeline dont vous expliquez le job rouge se défend très bien ; un pipeline vert dont vous ne savez pas dire ce qu'il vérifie ne se défend pas du tout.

✓ terminé
Travaux pratiques

Jalon 2 — Rejouer les dix preuves de fermeture

Jour 1 · Auditer, prouver et soutenir · 1 h 15

Démontrer, exploit par exploit et sur le HEAD d'aujourd'hui, que chacune des dix vulnérabilités est effectivement close.

La règle de fond, et elle ne souffre pas d'exception

Un finding sans preuve rejouable et sans remédiation vérifiable n'est pas un finding, c'est une opinion. Vous appliquez ce format depuis le 7 août ; aujourd'hui vous l'appliquez à votre propre code.

Concrètement : pour chaque VULN-NN, vous relancez exactement la commande d'exploitation qui fonctionnait, et vous notez ce qu'elle renvoie aujourd'hui. Une sortie d'outil qui ne signale plus rien n'est pas une preuve de fermeture — c'est une preuve que l'outil ne signale plus rien, ce qui n'est pas la même chose et le jury fera la différence.

Toutes les commandes visent localhost:5000, votre appli, sur votre poste.

  1. Ouvrez le tableau de preuves. C'est l'ossature de la partie 3 de votre rapport : ne le recopiez pas plus tard, écrivez-le directement dans rapports/audit-devsecops-lab.md.
    | VULN | Faille           | Exploit rejoue le 21/08      | Resultat | Statut | Ferme en |
    |------|------------------|------------------------------|----------|--------|----------|
    | 01   | Injection SQL    |                              |          |        | M1 J3    |
    | 02   | XSS reflechi     |                              |          |        | M2       |
    | 03   | Injection cmd    |                              |          |        | M2       |
    | 04   | IDOR             |                              |          |        | M5       |
    | 05   | Secret en dur    |                              |          |        | M1 J2    |
    | 06   | Hachage md5      |                              |          |        | M2       |
    | 07   | Deserialisation  |                              |          |        | M2       |
    | 08   | SSRF             |                              |          |        | M5       |
    | 09   | debug=True       |                              |          |        | M3       |
    | 10   | Dependances CVE  |                              |          |        | M2       |
  2. Les quatre injections. Ce sont les rejeux les plus parlants et les plus rapides : la même charge qu'à l'aller, et un comportement différent.
    # VULN-01 — injection SQL : attendu 401, et non plus "bienvenue"
    curl -s -o /dev/null -w '%{http_code}\n' -X POST http://localhost:5000/login \
      --data "user=admin'--&pwd=x"
    
    # VULN-02 — XSS reflechi : la balise doit ressortir echappee (<script>)
    curl -s 'http://localhost:5000/search?q=<script>alert(1)</script>'
    
    # VULN-03 — injection de commande : aucun 'uid=' ne doit apparaitre
    curl -s 'http://localhost:5000/ping?host=127.0.0.1;id'
    
    # VULN-07 — deserialisation : la charge yaml ne doit plus s'executer
    curl -s -X POST http://localhost:5000/config \
      --data-binary '!!python/object/apply:os.system ["id"]'
  3. Les trois failles de logique et de cryptographie. Notez la longueur de la sortie de /hash : trente-deux caractères, c'est encore du md5 ; soixante-quatre, c'est bien du sha256.
    # VULN-04 — IDOR : un identifiant qui ne vous appartient pas doit etre refuse
    curl -s -o /dev/null -w '%{http_code}\n' http://localhost:5000/profile/2
    
    # VULN-06 — hachage : compter les caracteres, c'est la preuve la plus courte
    curl -s 'http://localhost:5000/hash?p=test' | wc -c
    
    # VULN-08 — SSRF : l'adresse de metadonnees doit etre refusee par la liste blanche
    curl -s -o /dev/null -w '%{http_code}\n' \
      'http://localhost:5000/fetch?url=http://169.254.169.254/latest/meta-data/'
  4. Les trois failles de configuration et de chaîne d'approvisionnement. Elles ne se prouvent pas par un curl sur une route, mais par l'état de l'image et du dépôt.
    # VULN-09 — debug=True et execution en root : deux preuves distinctes
    docker run --rm devsecops-lab:hardened id                 # attendu : uid=10001
    
    # le mode debug s'annonce au demarrage dans les journaux, jamais dans une page 404 :
    # c'est la que Flask ecrit "Debug mode: on" et le code PIN du debogueur.
    docker logs devsecops-lab 2>&1 | grep -ciE 'debug mode: on|debugger is active'
    # attendu : 0
    
    # VULN-10 — dependances : plus aucune HIGH ni CRITICAL dans l'arbre
    trivy fs --scanners vuln --severity HIGH,CRITICAL --exit-code 1 .
    echo "code de sortie : $?"                                 # attendu : 0
    
    # VULN-05 — secret : l'arbre de travail est propre
    docker run --rm -v "$PWD:/repo" zricethezav/gitleaks:v8.18.4 \
      detect --source=/repo --no-git -v
  5. Et maintenant la question que le jury posera. La commande ci-dessus porte --no-git : elle n'inspecte que l'arbre de travail. Or votre secret a existé dans un commit. Relancez Gitleaks sans cette option, et regardez l'historique.
    docker run --rm -v "$PWD:/repo" zricethezav/gitleaks:v8.18.4 \
      detect --source=/repo -v
    
    git log --oneline -S 's3cr3t-dev-key' --all
    git log --oneline -S 'AKIAIOSFODNN7EXAMPLE' --all
  6. Vous venez de trouver un défaut dans votre propre pipeline, et c'est le meilleur moment de la journée. Le secret est retiré du code, mais il reste dans l'historique, et votre job secrets ne peut pas le voir puisqu'il est configuré avec --no-git. Ne corrigez rien : réécrire l'historique impose un git filter-repo et une poussée forcée sur une branche protégée, ce qui n'est ni répété ni raisonnable à quatre heures de la soutenance. Écrivez-le comme un finding ouvert, avec sa remédiation en deux volets : rotation du secret d'abord — ici sans objet, la clé AWS est un exemple public de la documentation d'Amazon — et purge de l'historique ensuite, planifiée. C'est exactement ce qu'un auditeur écrit dans la vraie vie.
  7. Complétez la colonne « Statut » avec trois valeurs seulement : Fermé (l'exploit rejoué échoue), Ouvert (il fonctionne encore, ou la correction est incomplète comme pour l'historique Git), Accepté (le risque est connu et assumé, avec sa raison écrite). Une case vide ou un statut inventé sont les deux seules fautes qui peuvent faire basculer un jury, parce qu'elles ne portent pas sur la technique.
  8. Reportez chaque sortie brute dans artefacts/preuves-2026-08-21.txt — la commande et ce qu'elle a répondu chez vous. Le tableau du rapport renvoie à ce fichier ; c'est ce qui permet à un tiers de tout rejouer sans vous.
Questions de réflexion — à préparer par écrit
  • Sur les dix lignes, combien de statuts « Fermé » reposent sur un rejeu d'exploit, et combien sur une sortie d'outil silencieuse ?
  • Le finding de l'historique Git : quelle est sa sévérité réelle, sachant que le dépôt est privé et que la clé est un exemple public ?
Pour vous repérer

Soixante-quinze minutes pour dix lignes, soit sept minutes chacune : c'est large si vous rejouez, très court si vous vous mettez à corriger. Dès qu'un rejeu ne donne pas le résultat attendu, votre réflexe doit être d'écrire « Ouvert » et de passer à la suivante. Vous reviendrez sur les cas ouverts à la fin s'il reste du temps — et s'il n'en reste pas, un finding ouvert honnêtement documenté vaut mieux qu'une ligne vide.

Le passage sur l'historique Git est le plus important du jalon, et c'est aussi le plus tentant à corriger. Résistez : la valeur de ce constat est qu'il montre que vous savez auditer votre propre dispositif, y compris là où il vous arrange de ne pas regarder. C'est très exactement ce qui distingue un ingénieur qui applique une chaîne d'outils d'un ingénieur qui la comprend.

✓ terminé
Leçon

Le rapport d'audit — ce que le rapport de pentest ne dit pas

Jour 1 · Auditer, prouver et soutenir · 20 min

Vous avez rendu hier rapports/pentest-juice-shop.md. Vous allez écrire cet après-midi rapports/audit-devsecops-lab.md. Même plan en six parties, même barème CVSS, même gabarit de finding — et pourtant deux documents qui ne répondent pas à la même question.

Rapport de pentest (20 août)Rapport d'audit (aujourd'hui)
CibleJuice Shop, dont vous n'avez pas le codedevsecops-lab, dont vous avez tout
Point de vueBoîte noire, celui de l'attaquantBoîte blanche, celui du propriétaire
Question poséeQue puis-je casser depuis l'extérieur ?Ce code et sa chaîne de production sont-ils sains ?
IdentifiantsF-01F-10VULN-01VULN-10, plus les findings du jour
Ce qu'on y trouve en plusLes contrôles : ce qui empêche la faille de revenir
Preuve attendueL'exploit qui fonctionneL'exploit qui ne fonctionne plus, et le garde-fou qui le maintient ainsi
La colonne qui fait la différence

Un pentest constate. Un audit constate et se prononce sur le dispositif. Pour chacune de vos dix lignes, la question qui compte n'est pas « est-ce corrigé ? » mais « qu'est-ce qui m'avertira si cela revient ? ». Pour VULN-01, la réponse est le job sast avec son option --error. Pour VULN-10, c'est le job sca. Pour l'exécution en root, c'est le job image et son --exit-code 1.

Et là où il n'y a pas de contrôle — VULN-04, l'IDOR, qu'aucun de vos cinq jobs ne détecterait s'il revenait — dites-le. C'est le constat le plus précieux du rapport.

Les six parties, et ce que vous y mettez déjà

Le rapport n'est pas une rédaction, c'est un assemblage : quatre des six parties existent déjà, écrites entre le 14 et ce matin.

PartieContenuVous l'avez déjà
1. Résumé exécutifUne page sans jargon, pour un décideur. Combien de failles, combien de fermées, ce qui reste et ce que cela coûteà écrire — en dernier
2. Périmètre et méthodologieLa cible, les versions, les dates, les outils, ce qui est hors périmètreà écrire — quinze minutes
3. Synthèse des findingsLe tableau du jalon 2, avec sévérité et statutfait ce matin
4. Findings détaillésUn bloc par vulnérabilité, au gabarit : sévérité, vecteur CVSS complet, composant, description, impact, preuve rejouable, remédiationles vecteurs CVSS viennent du registre du 17 août
5. Feuille de routeLes findings ouverts, par sévérité puis par effortl'historique Git en est la première ligne
6. AnnexesCommandes rejouables, sorties d'outils, renvois CWE et OWASPartefacts/preuves-2026-08-21.txt et le modèle de menaces du 14 août
Les deux formulations qui décrédibilisent

L'affirmation non mesurée. « Le pipeline détecte toute injection » alors que vous avez vérifié trois règles Semgrep sur une application de cent trente lignes. Écrivez plutôt ce que vous avez constaté, et sous quelle hypothèse cela s'étend.

Le zéro absolu. « Aucune vulnérabilité résiduelle. » Un auditeur qui ne trouve rien n'a pas fini de chercher, et un jury le sait. Vous avez au moins un finding ouvert depuis 11 h 40 — celui-là fait plus pour votre crédibilité que les neuf fermés.

✓ terminé
Travaux pratiques

Jalon 3 — Rédiger audit-devsecops-lab.md

Jour 1 · Auditer, prouver et soutenir · 1 h 15

Assembler en un document livrable ce qui existe déjà en morceaux, et le rendre rejouable par un tiers.

Assembler, pas rédiger

Ouvrez côte à côte les quatre sources : le tableau de preuves de ce matin, rapports/threat-model.md du 14 août, rapports/risk-register.csv du 17 août, et artefacts/preuves-2026-08-21.txt. Presque tout ce que vous allez écrire est déjà dans l'un des quatre.

Heure de bascule : 14 h 35. À cette heure-là, quel que soit l'état du texte, vous écrivez le résumé exécutif et vous fermez le document. Un rapport à quatre-vingts pour cent se lit très bien ; une démonstration non répétée se voit tout de suite.

  1. Créez le document et posez ses six titres de partie avant d'écrire une phrase. Vous remplissez ensuite dans l'ordre 3, 4, 5, 6, 2, et 1 en dernier.
  2. Partie 3 — synthèse. Collez le tableau du jalon 2 et ajoutez-lui deux colonnes : la sévérité en bande CVSS, et le contrôle qui détecterait le retour de la faille. Pour les lignes sans contrôle, écrivez « aucun » — c'est un résultat d'audit, pas une lacune de rédaction.
  3. Partie 4 — findings détaillés. Un bloc par vulnérabilité, au gabarit que vous appliquez depuis le 7 août. Voici le premier, entièrement rempli : les neuf autres suivent le même moule.
    ### VULN-01 — Injection SQL sur le formulaire d'authentification
    
    - Severite : Critical — CVSS 9.8 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
    - Composant : POST /login, parametre `user`
    - References : CWE-89, OWASP A03:2021 — Injection
    - Statut : FERME le 2026-08-05 (commit fix(VULN-01), branche fix/vuln-01-sqli)
    - Controle anti-regression : job `sast` (Semgrep 1.85.0, option --error)
    
    Description
      La requete etait construite par concatenation de chaines ; une entree
      contenant une apostrophe modifiait la structure de la requete.
    
    Preuve de fermeture (rejouee le 2026-08-21)
      $ curl -s -o /dev/null -w '%{http_code}\n' -X POST http://localhost:5000/login \
          --data "user=admin'--&pwd=x"
      401        (avant correction : 200 et le corps "bienvenue")
    
    Remediation appliquee
      Requete parametree : db().execute(
        "SELECT * FROM users WHERE user=? AND pwd=?", (user, pwd))
      Verifie par rejeu ci-dessus. Toute reintroduction fait echouer le job sast.
  4. Partie 5 — feuille de route. Vos findings ouverts, ordonnés par sévérité puis par effort, avec un geste concret et une estimation par ligne. La première est le secret présent dans l'historique Git : rotation, puis purge par git filter-repo, puis retrait de l'option --no-git du job secretsdans cet ordre, l'inverse rendrait le pipeline rouge en permanence.
  5. Partie 6 — annexes. Un renvoi vers artefacts/preuves-2026-08-21.txt, la liste des versions d'outils épinglées, et le renvoi vers le modèle de menaces du 14 août. Ne recopiez pas les sorties brutes dans le corps du rapport.
  6. Partie 2 — périmètre et méthodologie. Quinze minutes, et soyez précis sur ce qui est hors périmètre : Juice Shop n'est pas auditée ici, seulement attaquée dans le rapport d'hier ; le cluster kind n'est pas un environnement de production et ses écarts CIS sont attendus ; aucun test n'a visé autre chose que localhost.
  7. Partie 1 — résumé exécutif, en dernier et en une page. Sans jargon : combien de failles au départ, combien de fermées et prouvées, combien d'ouvertes, ce que la chaîne de production empêche désormais, et les deux ou trois actions qui restent. Un lecteur non technique doit pouvoir décider après cette page seule.
  8. Relisez en traquant une seule chose : toute affirmation que vous ne pouvez pas prouver. Puis committez, et vérifiez une dernière fois que rien de secret n'est suivi.
    git add rapports/audit-devsecops-lab.md
    git commit -m 'docs(pfr): rapport audit devsecops-lab, dix findings prouves'
    git ls-files | grep -E '(^|/)\.env$|\.key$|^artefacts/'   # doit ne rien afficher
    git push
Questions de réflexion — à préparer par écrit
  • Combien de vos dix lignes ont un contrôle anti-régression, et combien n'en ont aucun ?
  • Si un collègue reprenait ce dépôt lundi sans vous, que lui manquerait-il pour rejouer vos dix preuves ?
Pour vous repérer

La partie qui prend le plus de temps est la 4, parce qu'elle compte dix blocs. Chronométrez le premier : s'il vous prend plus de six minutes, les neuf suivants ne tiendront pas dans le créneau. La parade n'est pas d'écrire plus vite, c'est de raccourcir la description — le gabarit est utile parce qu'il est court, et l'essentiel est dans les deux lignes « preuve de fermeture » et « contrôle anti-régression ».

Écrivez « aucun » là où aucun contrôle n'existe, et résistez à l'envie d'écrire une phrase rassurante à la place. C'est la ligne que le jury lira en premier, et c'est celle qui montre que vous avez audité votre dispositif plutôt que raconté votre quinzaine.

✓ terminé
Leçon

Tenir vingt minutes devant un jury

Jour 1 · Auditer, prouver et soutenir · 15 min

Vingt minutes, en visioconférence, écran partagé. Le jury évalue autant votre plateforme que votre capacité à l'expliquer — c'est exactement ce qu'on attendra de vous en poste, lors d'une revue de sécurité.

Le déroulé qui fonctionne

Il est construit autour d'une idée : lancer la régression tôt et parler pendant qu'elle tourne. Un run complet prend six à huit minutes ; attendre en silence devant l'onglet Actions serait la pire minute de votre soutenance.

0-2 min    le contexte : une appli Flask de 130 lignes, dix failles deliberees,
             et la question posee — qu'est-ce qui empeche qu'elles reviennent ?
2-4 min    la chaine : poste -> depot signe -> 5 jobs -> image durcie -> cluster
4-6 min    JE POUSSE LA REGRESSION
             git push origin demo/regression   (VULN-01 reintroduite en une ligne)
             j'ouvre la PR, JE LAISSE TOURNER, et je continue de parler
6-11 min   DEMONSTRATION en direct
             . curl de l'exploit VULN-01 sur localhost:5000  -> 401
             . docker run --rm devsecops-lab:hardened id     -> uid=10001
             . kubectl apply d'un pod root                   -> rejete a l'admission
             . kubectl exec + curl entre deux pods           -> bloque
11-13 min  JE REVIENS SUR L'ONGLET ACTIONS
             . le job sast est ROUGE, la PR est bloquee par la protection de main
13-16 min  trois choix expliques : le seuil de severite du gate, --no-git, Calico
16-18 min  les limites : ce qui reste ouvert dans le rapport d'audit
18-20 min  questions
Pourquoi le job sast suffit

Vous n'attendez pas la fin du run. sast répond en quatre-vingt-dix secondes environ, et dès qu'il est rouge la fusion est bloquée par la protection de branche : la démonstration est faite. Les quatre autres jobs peuvent continuer de tourner à l'écran pendant que vous expliquez vos choix — cela donne même un fond visuel utile.

Trois règles

  • Montrez, ne racontez pas. Sept minutes de manipulation en direct valent mieux que quinze de diapositives. Cinq diapositives au maximum.
  • Assumez les manques. « Je ne l'ai pas testé » est une réponse recevable, surtout suivie de « voici comment je m'y prendrais ». Inventer ne l'est pas, et un jury technique le repère en une question de relance.
  • Justifiez, ne décrivez pas. « J'ai mis --severity HIGH,CRITICAL » n'apprend rien. « J'ai placé le seuil à HIGH parce qu'un gate qui échoue sur les MEDIUM aurait bloqué le build trois fois cette semaine sans qu'aucune ne soit exploitable ici » montre un ingénieur.
Le partage d'écran est un dispositif technique, traitez-le comme tel

Le jury est à distance. Une police de terminal à 12 points est illisible à travers une compression vidéo : montez-la à 16 points au moins. Partagez une fenêtre, jamais l'écran entier — vos notifications ne regardent personne. Fermez tout ce qui n'entre pas dans le déroulé, et préparez les onglets du navigateur dans l'ordre où vous les montrerez.

Les questions à préparer

Question probableCe qu'elle vérifie
Pourquoi le seuil du gate est-il à HIGH et pas à MEDIUM ?Que le réglage est un arbitrage, pas un défaut recopié
Qu'est-ce qui vous avertirait si l'IDOR revenait ?Que vous savez où votre dispositif ne voit rien
Votre job secrets voit-il l'historique du dépôt ?Que vous avez audité votre propre pipeline
Pourquoi Calico plutôt que le réseau par défaut de kind ?Que la NetworkPolicy bloque vraiment, et que vous savez pourquoi
Ce pipeline tiendrait-il sur un dépôt de cent mille lignes ?Que vous distinguez le mesuré de l'extrapolé
Un développeur contourne le pre-commit. Que se passe-t-il ?Que vous savez qu'un hook local n'est pas un contrôle
Qu'est-ce que vous feriez différemment ?Votre recul — c'est souvent la meilleure question
La dernière question

« Qu'est-ce que vous feriez différemment ? » revient presque toujours. Préparez-la sérieusement : une réponse honnête et précise sur ce que vous avez appris en vous trompant vaut mieux que n'importe quelle démonstration réussie. Vous avez de la matière — quinze jours de journal-incidents.md.

Après la soutenance

Le parcours S4 s'achève. Le dépôt, le rapport de pentest et le rapport d'audit vous appartiennent : c'est le dossier sur lequel vous vous appuierez à votre prise de poste, et la matière avec laquelle vous outillerez les projets de Caplogy.

✓ terminé
Travaux pratiques

Jalon 4 — Répétition chronométrée et plan de repli

Jour 1 · Auditer, prouver et soutenir · 55 min

Transformer une plateforme qui marche en une démonstration de vingt minutes qui tient, quoi qu'il arrive.

Un système qui marche et une démonstration qui tient sont deux choses différentes

C'est la seconde qui manque presque toujours, et c'est elle qui porte trois critères ●●● de la grille : ils ne se constatent qu'en direct.

Cinquante-cinq minutes, découpées ainsi : dix minutes pour préparer la branche de régression et le poste, vingt minutes pour deux répétitions chronométrées, quinze minutes pour le plan de repli, dix minutes pour la fiche de questions.

  1. Préparez la branche de régression, sans la pousser. Une seule ligne change : la requête paramétrée redevient une concaténation. Vous la poussez à la sixième minute de la soutenance, pas maintenant.
    cd ~/devsecops-lab
    git checkout main && git pull
    git checkout -b demo/regression
    
    # modifier la seule ligne de /login dans app.py :
    #   q = "SELECT * FROM users WHERE user='%s' AND pwd='%s'" % (user, pwd)
    #   row = db().execute(q).fetchone()
    
    git commit -am 'demo: reintroduction volontaire de VULN-01 (ne pas fusionner)'
    # PAS de push maintenant. La commande a taper en direct sera simplement :
    #   git push -u origin demo/regression
    
    # le hook pre-commit va refuser ce commit : c'est normal et c'est meme un bon
    # moment de demonstration. Pour le preparer, passez-le en le disant au jury :
    #   git commit -am '...' --no-verify
  2. Préparez le poste. Police du terminal à 16 points minimum, une seule fenêtre partagée et non l'écran entier, notifications coupées, onglets du navigateur ouverts dans l'ordre du déroulé : la pull request, l'onglet Actions, l'onglet Security. Fermez tout le reste.
  3. Première répétition, chronomètre en main, en entier. Suivez le déroulé de la leçon sans sauter d'étape et sans vous arrêter pour corriger : vous notez, vous continuez. Relevez la durée de chaque segment, pas seulement le total — c'est le relevé par segment qui vous dira quoi couper.
  4. Regardez votre relevé. Si vous êtes au-delà de vingt minutes, décidez maintenant ce que vous coupez, et coupez dans la démonstration, jamais dans le segment 13-16 min. Ce segment est celui où vous justifiez vos choix : c'est un critère à trois points, il ne se sacrifie pas pour une manipulation qui en rapporte deux.
  5. Deuxième répétition, avec la coupe décidée. Celle-ci doit tenir. Si elle ne tient toujours pas, coupez la démonstration Kubernetes — c'est la plus longue et la plus fragile, et son contenu se raconte très bien avec une capture.
  6. Le plan de repli, maintenant et pas quand vous en aurez besoin. Trois pannes possibles, trois réponses écrites, aucune improvisation. Collez ces commandes dans un fichier repli.md que vous garderez ouvert dans un onglet.
    # 1. LE CLUSTER kind NE REPOND PAS  (le plus frequent apres un redemarrage de Docker)
    kubectl get nodes                       # "connection refused", ou une attente qui ne finit pas
    docker start dso-lab-control-plane dso-lab-worker
    kind export kubeconfig --name dso-lab
    kubectl wait --for=condition=Ready node --all --timeout=120s
    # toujours mort au bout de 5 minutes -> on bascule sur la capture. On ne reconstruit PAS
    # un cluster en direct : kind create + Calico + manifestes, c'est 8 a 10 minutes.
    
    # 2. RESEAU COUPE OU GITHUB ACTIONS INDISPONIBLE
    act -j secrets                          # les deux jobs valides hors ligne des le 5 aout
    act -j sast
    # ne pas tenter dast ni image sous act pendant la soutenance : jamais repetes ainsi.
    
    # 3. UNE CIBLE NE REMONTE PAS
    docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
    docker start juice-shop devsecops-lab
    lsof -iTCP -sTCP:LISTEN -P -n | grep -E ':(3000|5000)'   # le port est-il pris par autre chose ?
    # juice-shop met 30 a 60 s avant de repondre : on la demarre a 15 h 55, pas a 16 h 10.
  7. Constituez le repli visuel : une capture d'écran de chaque étape du déroulé, rangée dans artefacts/repli/ et numérotée dans l'ordre. Cela prend dix minutes et cela vaut la démonstration entière. La règle en direct : annoncez la bascule au jury — « cette partie ne remonte pas, je vous montre la capture d'hier » — puis continuez. Le dire est professionnel ; rester bloqué trois minutes sur un terminal ne l'est pas, et cela se voit encore plus en visioconférence.
  8. Écrivez enfin votre fiche de questions : les sept de la leçon, plus celles du quiz de ce matin que vous aviez manquées. Une réponse écrite en trois lignes chacune, pas un intitulé recopié. Vous ne la lirez pas pendant la soutenance ; l'avoir écrite suffit.
Questions de réflexion — à préparer par écrit
  • Votre démonstration tient-elle en vingt minutes, chronomètre en main, coupe comprise ?
  • Si le cluster ne répond plus à 16 h 05, quelle est votre première phrase au jury, et votre première commande ?
Pour vous repérer

Une répétition mentale ne compte pas. Une répétition qui saute la partie « qui marche déjà » ne compte pas non plus : c'est justement là que se cachent les quatre-vingt-dix secondes imprévues — le temps que Juice Shop réponde, le temps que le navigateur vous redemande votre mot de passe GitHub, le temps de retrouver le bon onglet. Le chiffre typique est un écart de trois à cinq minutes entre le déroulé estimé et le premier chronométrage réel.

Et gardez le plan de repli pour ce qu'il est : une assurance, pas une prédiction. Il prend quinze minutes à constituer et il ne servira probablement pas. Les fois où il sert, il sauve la soutenance entière.

✓ terminé
Point de contrôle

PFR · J1 — Cinq jobs verts, dix preuves rejouées, soutenance tenue

Jour 1 · Auditer, prouver et soutenir · 1 h

Vérifiez avant de continuer
Le dernier créneau, minute par minute

16 h 00 – 16 h 10 · dernière vérification. Vous démarrez Juice Shop maintenant — elle met une minute à répondre —, vous relancez la pile, vous vérifiez que kubectl get nodes répond, vous ouvrez vos onglets dans l'ordre et vous montez la police du terminal.

16 h 10 – 16 h 30 · soutenance, vingt minutes. 16 h 30 – 16 h 50 · retour du jury. 16 h 50 – 17 h 00 · clôture du parcours S4.

Si à 16 h 05 quelque chose ne remonte pas, vous ne déboguez pas : vous basculez sur le repli et la soutenance démarre à l'heure. C'est pour ce moment-là que vous avez passé quinze minutes sur repli.md.

Et rappelez-vous ce qui est évalué en premier : le pipeline refuse la faille, les dix preuves tiennent, et vous savez pourquoi vous avez réglé les choses ainsi. Le reste vient après.

Pour vous repérer

Le critère qu'on coche à tort le plus souvent est le quatrième. Une ligne « Fermé » adossée à « Semgrep ne remonte plus rien » n'est pas fermée, elle est silencieuse — et c'est la première chose que le jury ira tester. Reprenez vos dix lignes et comptez combien portent une commande d'exploitation dans la colonne de preuve : si le compte n'est pas de dix, corrigez ce qui manque avant de cocher, cela prend deux minutes par ligne.

Même exigence sur le premier critère, qui attend un chiffre : « le run dure environ sept minutes, et dast en consomme cinq » se défend ; « c'est assez rapide » ne se défend pas.

✓ terminé

Mon avancement

Signature d'émargement

Demander de l'aide à votre encadrant

Étape concernée :

Avant d'envoyer

Cherchez seul pendant 30 minutes et notez ce que vous avez tenté. Ce que vous avez essayé fait partie de ce que vous présentez — c'est ce qui distingue l'autonomie de l'abandon.