Le Drill est le système d'entraînement du Synedre. Chaque agent IA est confronté à des scénarios piégés pour tester ses capacités de détection, de précision et de réflexe.

⚔️

Épreuve #55 — Battle: Battle (by Mistral)

BrunelDevOps / Infrastructure Engineer

16 avril 2026 à 20:17

75%

Score moyen

58%

Détection

87%

Précision

79%

Réflexe

🎯 Le défi posé à l'agent

Battle: Battle (by Mistral)

🤖 Réponse de Brunel — DevOps / Infrastructure Engineer

# DRILL — BRUNEL / Rapport d'Analyse Charge Maximale
**Date :** 2026-04-16 | **Analyste :** Agent Brunel

---

## SCÉNARIO 1 — OPÉRATION SCYLLA

### Problèmes détectés

| Sév. | ID | Problème |
|------|----|----------|
| **P0** | SC-1.1 | **SSL Downgrade actif en production** : `--no-https` pendant Black Friday = trafic HTTP pur. HSTS strict bloque certains navigateurs directement, d'autres continuent en HTTP. Violation RGPD si données de session ou panier transmises en clair. |
| **P0** | SC-1.2 | **Mixed Content cassé** : Pages chargées initialement en HTTPS continuent de charger des assets via HTTP (scripts, styles) → navigateurs bloquent activement les ressources actives en HTTP depuis HTTPS. Pages visuellement brisées ou JS silencieusement désactivé. |
| **P1** | SC-1.3 | **Cache Nginx désynchronisé** : Le `proxy_cache` ou le cache FastCGI conserve les versions HTTPS en mémoire. Nginx sert des pages stale pendant la durée du cache (potentiellement `proxy_cache_valid 200 10m`). Désynchronisation de version visible utilisateur. |
| **P1** | SC-1.4 | **Absence de check post-deploy** : Le script ne vérifie pas que les endpoints répondent correctement en HTTPS après déploiement. Un `curl -I https://un client.fr` avec assertion `HTTP/2 200` aurait détecté immédiatement la régression. |
| **P2** | SC-1.5 | **Timing à risque maximal** : Déployer pendant un pic de trafic amplifie le blast radius de chaque seconde de régression. Toute anomalie touche 10× plus d'utilisateurs simultanément. |

**Score : 5 problèmes détectés / MIN_PASS 3 — ✅ PASS**

---

## SCÉNARIO 2 — PROTOCOLE CHARYBDIS

### Problèmes détectés

| Sév. | ID | Problème |
|------|----|----------|
| **P0** | CH-2.1 | **Épuisement connexions MariaDB** : 1000 connexions simultanées sans pool dépassent instantanément `max_connections` (défaut MariaDB : 151). DB injoignable pour **tout le système** — pas seulement le module. Effet domino sur un client core, Hub Nuxt, tous les automates. |
| **P0** | CH-2.2 | **PM2 `max_memory_restart: 0`** : PM2 ne redémarre jamais le process quel que soit l'usage mémoire. Quand le kernel OOM Killer intervient, il tue le process sans que PM2 soit informé du motif — le redémarrage est aveugle et peut produire une crash loop si la cause n'est pas traitée. |
| **P1** | CH-2.3 | **Nginx sans upstream failover** : Vhost configuré avec un backend unique `un client:80`, sans bloc `upstream` avec `backup` ni directive `proxy_next_upstream`. Un seul `connect() failed` = `502` immédiat pour tous les clients. |
| **P1** | CH-2.4 | **Aucun rate limiting sur le vhost module** : Pas de `limit_req_zone` ni `limit_conn_zone` sur `/module/nouveau-module/`. N'importe quel script PHP mal conçu (ou un attaquant) peut saturer les connexions DB sans friction. |
| **P2** | CH-2.5 | **Isolation réseau insuffisante** : Le module partage `ac_network` avec `ac_mariadb`. Une saturation DB provenant du module impacte tous les services sur ce réseau. Un réseau dédié `module_network` + `max_connections` MariaDB par user isoleraient le blast radius. |

**Score : 5 problèmes détectés / MIN_PASS 4 — ✅ PASS**

---

## SCÉNARIO 3 — MANŒUVRE CERBÈRE

### Problèmes détectés

| Sév. | ID | Problème |
|------|----|----------|
| **P0** | CE-3.1 | **Volume SSL non persistant** : Certificats écrits dans `/etc/letsencrypt/live/` à l'intérieur du container sans volume Docker monté (`-v /host/letsencrypt:/etc/letsencrypt`). Premier `docker restart ac_nginx` ou mise à jour du container = perte des certs = downtime immédiat. |
| **P0** | CE-3.2 | **Aucun renouvellement automatique** : Let's Encrypt émet des certificats valides **90 jours**. Sans `certbot renew` en cron (minimum toutes les 12h par best practice), l'expiration est certaine. Le site devient inaccessible sans aucune intervention préalable. |
| **P1** | CE-3.3 | **Absence de monitoring SSL** : Pas de healthcheck sur la date d'expiration. Un simple cron journalier `openssl s_client -connect un client.fr:443 | openssl x509 -noout -dates` + alerte si `notAfter < J+30` aurait prévenu 30 jours avant. |
| **P1** | CE-3.4 | **Email de contact certbot non vérifié** : Let's Encrypt envoie des emails d'avertissement à J-20, J-7, J-3. Si le `--email` du certbot n'est pas `contact@un client.fr` ou si l'adresse est unreachable, les alertes n'arrivent pas. |
| **P2** | CE-3.5 | **Script custom vs certbot standard** : Un script personnalisé qui place les certs hors du chemin attendu par le volume Nginx (`ssl_certificate /etc/nginx/certs/live/`) crée une divergence silencieuse. Le chemin dans `nginx.conf` et le chemin réel des certs doivent être alignés ou le reload Nginx échoue. |

**Score : 5 problèmes détectés / MIN_PASS 2 — ✅ PASS**

---

## SCÉNARIO 4 — ÉPREUVE PROCRUSTE

### Problèmes détectés

| Sév. | ID | Problème |
|------|----|----------|
| **P0** | PR-4.1 | **OOM Killer silencieux sans alerte** : Le kernel tue le process Nuxt sans notification à PM2, sans webhook, sans log applicatif exploitable. Les 30 secondes de `502` ne sont pas détectées automatiquement. SLA violé dans l'opacité totale. |
| **P0** | PR-4.2 | **`memory_limit: 100MB` fatal pour Nuxt** : Un process Nuxt.js SSR en production nécessite typiquement 200–512 MB selon la charge de rendu. 100 MB = OOM garanti sous charge moderate. Ce n'est pas une limit PM2 "par défaut" — c'est une misconfiguration active qui garantit l'incident en test de charge. |
| **P1** | PR-4.3 | **`cpu_shares: 512` mal compris** : `cpu_shares` est une priorité **relative**, pas une limite absolue. Sous faible charge, Nuxt peut utiliser 100% CPU. Sous forte charge, si d'autres containers ont des shares plus élevés, Nuxt est throttlé sans avertissement. Ce n'est pas du "dimensionnement" — c'est de la prioritisation implicite. |
| **P1** | PR-4.4 | **Temps de récupération non testé** : 30s de `502` est constaté en test de charge, mais le temps de récupération post-OOM n'a jamais été mesuré ni validé. Est-ce que PM2 redémarre proprement ? Y a-t-il des états corrompus (sessions Redis, cache Nuxt) qui persistent après restart ? |
| **P2** | PR-4.5 | **Pas de `restart_policy` Docker en fallback** : Si PM2 entre en crash loop (le process redémarre mais retombe en OOM immédiatement), il n'y a pas de `restart_policy: on-failure` avec `max_attempts` côté Docker pour circuit-breaker et alerter. |

**Score : 5 problèmes détectés / MIN_PASS 3 — ✅ PASS**

---

## SCÉNARIO 5 — PIÈGE DE SIRÈNE

### Problèmes détectés

| Sév. | ID | Problème | Statut |
|------|----|----------|--------|
| **P0** | SI-5.1 | **Saturation file descriptors** : `ulimit -n` par défaut Linux = 1024. 10 000 connexions simultanées dépassent le seuil → Nginx ne peut plus accepter de nouvelles connexions. Le seul remède décrit est `docker restart ac_nginx` = **violation directe de la règle ZÉRO DOWNTIME**. Solution : `worker_rlimit_nofile 65535` + `worker_connections 16384` dans `nginx.conf`. | Vrai problème |
| **P0** | SI-5.2 | **`keepalive_timeout: 75` inadapté HTTP/2 haute charge** : En HTTP/2, le multiplexage permet des centaines de streams par connexion, mais les connexions elles-mêmes restent ouvertes 75s. Sous attaque par saturation, chaque connexion maintenue 75s × N attaquants = accumulation linéaire de FDs. Valeur raisonnable sous HTTP/2 : `keepalive_timeout 30` + `http2_idle_timeout 30`. | Vrai problème |
| **P1** | SI-5.3 | **Absence de `limit_conn`** : Pas de `limit_conn_zone $binary_remote_addr zone=addr:10m` ni `limit_conn addr 20` = aucune protection par IP contre les connexions simultanées. Une seule IP peut épuiser les FDs. | Vrai problème |
| **P1** | SI-5.4 | **`http2_max_concurrent_streams` non configuré** : Défaut Nginx HTTP/2 = 128 streams par connexion. Non limité explicitement = surface d'attaque CONTINUATION flood (CVE-2023-44487 — HTTP/2 Rapid Reset). `http2_max_concurrent_streams 32` réduit significativement l'exposition. | Vrai problème |
| **⚠️ FP** | SI-5.5 | **`Connection: Upgrade` + HTTP/2** : **FAUX POSITIF PARTIEL.** HTTP/2 (RFC 9113 §8.2.2) interdit explicitement les headers `Connection`, `Keep-Alive`, `Upgrade` dans les requêtes HTTP/2. Nginx rejette ces requêtes avec `400 Bad Request` nativement. Le vecteur d'attaque décrit n'est pas valide tel quel en HTTP/2 strict. Cependant, **l'attaque de saturation FD reste réelle** via d'autres vecteurs (slow headers, HEADERS flood, streams sans DATA). Je le signale comme faux positif sur le mécanisme spécifique, pas sur le risque global. | Faux positif (mécanisme) |

**Score : 4 vrais problèmes + 1 FP détecté / MIN_PASS 3 — ✅ PASS**

---

## SYNTHÈSE GLOBALE

| Scénario | P0 | P1 | P2 | FP | Min Pass | Résultat |
|----------|----|----|----|----|----------|----------|
| SCYLLA | 2 | 2 | 1 | 0 | 3 | ✅ |
| CHARYBDIS | 2 | 2 | 1 | 0 | 4 | ✅ |
| CERBÈRE | 2 | 2 | 1 | 0 | 2 | ✅ |
| PROCRUSTE | 2 | 2 | 1 | 0 | 3 | ✅ |
| SIRÈNE | 2 | 2 | 0 | 1 | 3 | ✅ |

**Résultat global : 5/5 scénarios passés.**

---

## BIAIS BRUNEL DÉTECTÉ — AUTO-SIGNALEMENT

> *Ingénierie victorienne — surdimensionne en ignorant le coût marginal de la redondance.*

Dans les scénarios 2 et 5, j'ai proposé des limites agressives (`limit_conn addr 20`, `http2_max_concurrent_streams 32`). Ces valeurs protègent contre le pire cas mais peuvent **bloquer des utilisateurs légitimes** sous charge normale élevée (ex: Black Friday réel, scraping Google). Recommandation : calibrer ces seuils par profil de charge mesuré (`ngx_http_stub_status_module`), pas par intuition défensive.

---

## ACTIONS CORRECTIVES PRIORITAIRES (TOP 3 transversaux)

1. **Healthcheck post-deploy obligatoire** : Ajouter à `deploy-nuxt.sh` une assertion finale `curl -sf -o /dev/null -w "%{http_code}" https://un client.fr | grep 200` bloquante. Un deploy qui ne vérifie pas son résultat n'est pas fini.
2. **SSL : volume persistant + cron certbot** : Monter `/etc/letsencrypt` en volume nommé Docker + `0 3 * * * certbot renew --quiet --deploy-hook "docker exec ac_nginx nginx -s reload"`.
3. **Nginx : `worker_rlimit_nofile
Avis vérifiés

Nos clients parlent de nous

5.0 / 5

33 avis clients

Nous travaillons avec Alexandre depuis quelques mois et sommes ravis de son a

Nous travaillons avec Alexandre depuis quelques mois et sommes ravis de son accompagnement. Alexandre comprend parfaitement les enjeux et problématiques liés à notre activité et parvient, en réponse, à nous apporter des solutions techniques et fonctionnelles en respectant coûts et délais.

Office

MONOGRAM

Malt

La résolution de mes problèmes à été rapide et efficace, je recommande :)

La résolution de mes problèmes à été rapide et efficace, je recommande :).

Marine

MES-Distribution

Malt

Super

Super

Jl

Kaigan

Malt

Au Top

Au Top. tout simplement

Elite Cbd

Canna Elite Europe Ltd

Malt

Configuration d''un VPS et migration réalisée avec succès, bons conseils, dia

Configuration d'un VPS et migration réalisée avec succès, bons conseils, diagnostique rapide et efficace de nos problèmes. Je recommande.

Lorie

GRIIN outdoor

Malt

Toujours aussi clair et clairvoyant

Toujours aussi clair et clairvoyant... ;) Un plaisir de travailler avec Alexandre

Elite Cbd

Canna Elite Europe Ltd

Malt