TP Avancé — Supervision Réseau

Infrastructure Zero-Trust
& Observabilité Full-Stack

Déploiement d'une infrastructure réseau sécurisée avec supervision multicouche, détection d'anomalies, alerting automatisé et réponse aux incidents.

Durée estimée: 8–12h
Niveau: Avancé
VMs requises: 5
Prérequis: TP Supervision de base
🏗️

Infrastructure

5 VMs segmentées avec routage inter-VLAN contrôlé

📡

Observabilité

Métriques, logs et traces centralisés avec Prometheus + Loki

🛡️

Sécurité

IDS/IPS, audit de surface d'attaque, blocage automatique

🚨

Incidents

Simulation, détection et réponse structurée aux incidents réseau

ARCHI

Architecture cible

┌─────────────────────────────────────────────────────────┐ │ VMware / VirtualBox │ │ │ │ ┌──────────┐ ┌──────────────────────────────────┐ │ │ │ VM-GW │ │ VLAN LAN │ │ │ │ (Router/ │◄──►│ VM-APP (192.168.10.10) │ │ │ │ Firewall)│ │ VM-DB (192.168.10.20) │ │ │ │.1.1 .10.1│ └──────────────────────────────────┘ │ │ │ .20.1 │ │ │ │ .30.1 │ ┌──────────────────────────────────┐ │ │ │ │◄──►│ VLAN DMZ │ │ │ │ │ │ VM-MON (192.168.20.10) │ │ │ │ │ │ (Prometheus+Grafana+Loki) │ │ │ │ │ └──────────────────────────────────┘ │ │ │ │ │ │ │ │ ┌──────────────────────────────────┐ │ │ │ │◄──►│ VLAN MGMT │ │ │ │ │ │ VM-SEC (192.168.30.10) │ │ │ │ │ │ (Suricata+Fail2ban+Lynis) │ │ │ └──────────┘ └──────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘ Flux autorisés : LAN→DMZ (monitoring), GW→toutes (mgmt) Flux bloqués : DMZ→LAN, MGMT→LAN (sauf SSH explicite) IDS actif sur : interface GW eth1 (miroir de trafic)
VMRôleIPOS recommandéRAM
VM-GWRouteur / Firewall nftables192.168.{10,20,30}.1Debian 12512 MB
VM-APPServeur applicatif (Nginx)192.168.10.10Debian 121 GB
VM-DBBase de données (PostgreSQL)192.168.10.20Debian 121 GB
VM-MONMonitoring (Prometheus+Grafana+Loki)192.168.20.10Debian 122 GB
VM-SECSécurité (Suricata+Fail2ban+Lynis)192.168.30.10Debian 121 GB
PRÉ

Prérequis

Avoir complété le TP de base (Prometheus + Grafana + Blackbox Exporter + nftables simple). Les notions de routage IP, de règles de pare-feu et de PromQL sont supposées acquises.
  • VMware Workstation / VirtualBox avec support des réseaux internes personnalisés
  • Au minimum 8 GB de RAM disponible sur la machine hôte
  • Image ISO Debian 12 (Bookworm) disponible en local
  • Accès internet sur la machine hôte pour télécharger les paquets
  • Compréhension des bases du routage IP statique (ip route, ip addr)
  • Connaissance minimale de YAML pour les fichiers de configuration
01

Infrastructure & Segmentation

~2h
1.1 Création et configuration des 5 VMs

Créer cinq VMs Debian 12 minimalistes. Lors de l'installation, choisir uniquement « SSH server » et « standard system utilities ».

RéseauSous-réseauDHCP
VMnet10192.168.10.0/24Désactivé
VMnet20192.168.20.0/24Désactivé
VMnet30192.168.30.0/24Désactivé

Assigner les interfaces réseau à chaque VM :

  • VM-GW : eth0 (NAT/WAN), eth1 (VMnet10), eth2 (VMnet20), eth3 (VMnet30)
  • VM-APP / VM-DB : une seule interface sur VMnet10
  • VM-MON : une seule interface sur VMnet20
  • VM-SEC : eth0 (VMnet30) + eth1 (VMnet10 en mode promiscuous pour IDS)
# /etc/network/interfaces sur VM-APP
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    address 192.168.10.10
    netmask 255.255.255.0
    gateway 192.168.10.1
    dns-nameservers 8.8.8.8
⚠ Attention : Sur VM-GW, activer le forwarding IP avant de configurer les routes. Ne pas oublier de persister avec sysctl.conf.
# Sur VM-GW
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p

# Vérification
cat /proc/sys/net/ipv4/ip_forward
# Doit retourner : 1
1.2 Routage inter-VLAN et connectivité

Configurer VM-GW comme routeur central. Chaque VM des segments LAN/DMZ/MGMT doit pouvoir joindre les autres uniquement selon la politique de sécurité définie.

# Sur VM-GW — Vérifier les interfaces actives
ip addr show
ip route show

# Ajouter une route par défaut NAT vers internet
ip route add default via <IP_HOTE_NAT>

# Sur VM-APP — Tester la connectivité vers VM-MON
ping -c 4 192.168.20.10
traceroute 192.168.20.10
  • VM-APP peut joindre VM-GW (192.168.10.1) → ping OK
  • VM-APP peut joindre VM-MON (via routage GW) → ping OK
  • VM-MON ne peut PAS joindre VM-DB directement (réglé au pare-feu étape 1.3)
  • VM-GW peut joindre toutes les VMs → accès SSH d'administration
1.3 Pare-feu nftables avancé avec stateful inspection

Remplacer le pare-feu basique par une configuration nftables complète avec : stateful inspection, rate limiting, logging différencié par chaîne et protection contre les scans de ports.

# /etc/nftables.conf — Configuration complète VM-GW
flush ruleset

table inet filter {

  # Set pour les IPs bannies dynamiquement (alimenté par Fail2ban)
  set blocklist {
    type ipv4_addr
    flags dynamic, timeout
    timeout 1h
  }

  chain input {
    type filter hook input priority 0 ; policy drop

    # Connexions établies
    ct state established,related accept
    ct state invalid drop

    # Blocklist dynamique
    ip saddr @blocklist drop

    # Loopback
    iif "lo" accept

    # ICMP limité
    ip protocol icmp icmp type echo-request limit rate 5/second accept
    ip protocol icmp drop

    # SSH uniquement depuis MGMT
    ip saddr 192.168.30.0/24 tcp dport 22 accept
    tcp dport 22 log prefix "[FW-SSH-DENY] " drop

    # Protection scan de ports (SYN flood)
    tcp flags syn tcp option maxseg size 1-500 drop
    tcp flags & (fin|syn|rst|psh|ack|urg) == fin|syn|rst|psh|ack|urg drop
    tcp flags & (fin|syn) == fin|syn drop

    log prefix "[FW-INPUT-DROP] " drop
  }

  chain forward {
    type filter hook forward priority 0 ; policy drop

    ct state established,related accept
    ip saddr @blocklist drop

    # LAN → DMZ : autoriser metrics (9090, 3000, 3100)
    ip saddr 192.168.10.0/24 ip daddr 192.168.20.0/24 \
      tcp dport { 9090, 3000, 3100, 9100 } accept

    # DMZ → LAN : interdit sauf réponses (géré par ct state)

    # MGMT → toutes : SSH uniquement
    ip saddr 192.168.30.0/24 tcp dport 22 accept

    # LAN → WAN : NAT sortant (HTTP/HTTPS)
    ip saddr 192.168.10.0/24 tcp dport { 80, 443 } accept

    log prefix "[FW-FWD-DROP] " drop
  }

  chain output {
    type filter hook output priority 0 ; policy accept
  }
}

table ip nat {
  chain postrouting {
    type nat hook postrouting priority 100
    ip saddr 192.168.10.0/24 oif "eth0" masquerade
  }
}
# Appliquer et activer au démarrage
nft -f /etc/nftables.conf
systemctl enable nftables
nft list ruleset

# Vérifier les logs en temps réel
journalctl -f -k | grep "FW-"
✓ Validation : Depuis VM-DB, essayer curl http://192.168.20.10:3000 → doit être bloqué et logué. Depuis VM-APP, le même curl doit aboutir.
02

Stack d'Observabilité Full-Stack

~3h
2.1 Prometheus avec exporteurs étendus (Node, Nginx, Postgres, Process)

Déployer Prometheus sur VM-MON avec une configuration scrape couvrant tous les services. Ajouter les exporteurs spécialisés sur chaque VM cible.

# Node Exporter (métriques système)
wget https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-amd64.tar.gz
tar xzf node_exporter-*.tar.gz && cp node_exporter-*/node_exporter /usr/local/bin/

# Nginx Exporter
apt install nginx -y
wget https://github.com/nginxinc/nginx-prometheus-exporter/releases/download/v1.3.0/nginx-prometheus-exporter_1.3.0_linux_amd64.tar.gz

# Process Exporter (surveiller des processus spécifiques)
wget https://github.com/ncabatoff/process-exporter/releases/download/v0.8.3/process-exporter-0.8.3.linux-amd64.tar.gz
# /etc/prometheus/prometheus.yml
global:
  scrape_interval:     15s
  evaluation_interval: 15s
  external_labels:
    environment: 'tp-lab'

# Règles d'alerte
rule_files:
  - "/etc/prometheus/rules/*.yml"

# Alertmanager
alerting:
  alertmanagers:
    - static_configs:
        - targets: ['localhost:9093']

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'node'
    static_configs:
      - targets:
          - '192.168.10.10:9100'  # VM-APP
          - '192.168.10.20:9100'  # VM-DB
          - '192.168.20.10:9100'  # VM-MON elle-même
          - '192.168.30.10:9100'  # VM-SEC
    relabel_configs:
      - source_labels: [__address__]
        regex: '(.+):\d+'
        target_label: instance

  - job_name: 'nginx'
    static_configs:
      - targets: ['192.168.10.10:9113']

  - job_name: 'postgres'
    static_configs:
      - targets: ['192.168.10.20:9187']

  - job_name: 'blackbox-http'
    metrics_path: /probe
    params:
      module: [http_2xx]
    static_configs:
      - targets:
          - http://192.168.10.10
          - http://192.168.10.10/health
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: localhost:9115

  - job_name: 'blackbox-icmp'
    metrics_path: /probe
    params:
      module: [icmp]
    static_configs:
      - targets: ['192.168.10.10', '192.168.10.20', '192.168.30.10']
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: localhost:9115
# Taux d'erreurs HTTP sur Nginx (sur 5 min)
rate(nginx_http_requests_total{status=~"5.."}[5m]) /
rate(nginx_http_requests_total[5m]) * 100

# Saturation CPU avec alerte si > 80% pendant 5 min
100 - (avg by(instance) (
  rate(node_cpu_seconds_total{mode="idle"}[2m])
) * 100) > 80

# Connexions TCP en état CLOSE_WAIT (fuite de connexions)
node_netstat_Tcp_CurrEstab - node_netstat_Tcp_PassiveOpens

# Jitter estimé : écart-type de la latence ICMP
stddev_over_time(probe_duration_seconds{job="blackbox-icmp"}[10m]) * 1000
2.2 Loki + Promtail — Agrégation centralisée des logs

Loki permet d'agréger les logs de toutes les VMs dans Grafana, corrélables avec les métriques Prometheus en utilisant les mêmes labels (instance, job).

# Sur VM-MON — Installer Loki
wget https://github.com/grafana/loki/releases/download/v3.2.0/loki-linux-amd64.zip
unzip loki-linux-amd64.zip && mv loki-linux-amd64 /usr/local/bin/loki
chmod +x /usr/local/bin/loki
# /etc/loki/loki-config.yml
auth_enabled: false

server:
  http_listen_port: 3100

common:
  path_prefix: /var/loki
  storage:
    filesystem:
      chunks_directory: /var/loki/chunks
      rules_directory:  /var/loki/rules
  replication_factor: 1
  ring:
    instance_addr: 127.0.0.1
    kvstore:
      store: inmemory

schema_config:
  configs:
    - from: 2024-01-01
      store: tsdb
      object_store: filesystem
      schema: v13
      index:
        prefix: index_
        period: 24h

limits_config:
  allow_structured_metadata: false
# Sur CHAQUE VM cible — Installer Promtail
wget https://github.com/grafana/loki/releases/download/v3.2.0/promtail-linux-amd64.zip
unzip promtail-linux-amd64.zip && mv promtail-linux-amd64 /usr/local/bin/promtail
# /etc/promtail/promtail-config.yml — VM-APP
server:
  http_listen_port: 9080

positions:
  filename: /tmp/positions.yaml

clients:
  - url: http://192.168.20.10:3100/loki/api/v1/push

scrape_configs:
  - job_name: system
    static_configs:
      - targets: ['localhost']
        labels:
          job: syslog
          instance: vm-app
          __path__: /var/log/syslog

  - job_name: nginx
    static_configs:
      - targets: ['localhost']
        labels:
          job: nginx
          instance: vm-app
          __path__: /var/log/nginx/*.log
    pipeline_stages:
      - regex:
          expression: '(?P<ip>\S+) .+ "(?P<method>\w+) (?P<path>\S+).+" (?P<status>\d{3})'
      - labels:
          method:
          status:

  - job_name: nftables
    static_configs:
      - targets: ['localhost']
        labels:
          job: firewall
          instance: vm-gw
          __path__: /var/log/kern.log
    pipeline_stages:
      - match:
          selector: '{job="firewall"}'
          stages:
            - regex:
                expression: '\[(?P<fw_chain>FW-[A-Z-]+)\]'
            - labels:
                fw_chain:
✓ Validation : Dans Grafana, ajouter Loki comme datasource (http://localhost:3100), puis explorer les logs avec la requête LogQL : {job="nginx"} |= "status"
2.3 Dashboards Grafana — Corrélation métriques/logs

Créer un dashboard unifié qui affiche simultanément les métriques Prometheus et les logs Loki pour diagnostiquer un incident sans changer d'outil.

PanelTypeRequête
CPU par instanceTime series100 - avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[2m])*100)
Latence ICMPGaugeprobe_duration_seconds{job="blackbox-icmp"}*1000
Drops firewall/minStatrate(nftables_dropped_packets_total[1m])
Logs erreurs NginxLogs (Loki){job="nginx"} |= "error" or `status="5`
Connexions TCP activesTime seriesnode_netstat_Tcp_CurrEstab
Disponibilité servicesState timelineprobe_success{job="blackbox-http"}
Astuce : utiliser les annotations Grafana pour marquer les événements de simulation (congestion, attaque) sur le timeline. Cela corrèle visuellement l'événement avec la dégradation des métriques.
03

Sécurité & Détection d'Intrusion

~2h30
3.1 Suricata — IDS réseau en mode AF_PACKET

Installer Suricata sur VM-SEC avec son interface eth1 en mode promiscuous sur le segment LAN. Suricata analysera tout le trafic du LAN en temps réel et générera des alertes JSON.

# Sur VM-SEC
apt install suricata -y

# Mettre eth1 en mode promiscuous (miroir du trafic LAN)
ip link set eth1 promisc on
echo 'SUBSYSTEM=="net", ACTION=="add", KERNEL=="eth1", RUN+="/sbin/ip link set eth1 promisc on"' > /etc/udev/rules.d/99-promisc.rules

# Télécharger les règles Emerging Threats (gratuites)
suricata-update
suricata-update list-sources
suricata-update enable-source et/open
suricata-update update
# /etc/suricata/suricata.yaml — sections clés à modifier

# Interface à surveiller
af-packet:
  - interface: eth1
    cluster-id: 99
    cluster-type: cluster_flow
    defrag: yes

# Format des alertes
outputs:
  - eve-log:
      enabled: yes
      filetype: regular
      filename: /var/log/suricata/eve.json
      types:
        - alert:
            payload: yes
            payload-buffer-size: 4kb
            http-body: yes
        - http:
            extended: yes
        - dns:
        - tls:
            extended: yes
# Ajouter des règles personnalisées
# /etc/suricata/rules/local.rules

# Détecter un scan de ports (>15 SYN vers ports différents en 2 sec)
alert tcp any any -> 192.168.10.0/24 any (msg:"PORT SCAN DETECTED"; flags:S; threshold: type both, track by_src, count 15, seconds 2; sid:1000001; rev:1;)

# Détecter tentative de connexion SSH brute force
alert tcp any any -> 192.168.10.0/24 22 (msg:"SSH BRUTE FORCE"; flow:to_server; threshold: type both, track by_src, count 5, seconds 30; sid:1000002; rev:1;)

# Détecter exfiltration de données (gros transfert sortant inhabituel)
alert tcp 192.168.10.0/24 any -> !192.168.0.0/16 any (msg:"LARGE DATA EXFILTRATION"; dsize:>65000; sid:1000003; rev:1;)
# Démarrer Suricata et surveiller les alertes en temps réel
systemctl start suricata
tail -f /var/log/suricata/eve.json | python3 -m json.tool | grep -A5 '"event_type":"alert"'
3.2 Fail2ban — Bannissement automatique depuis les alertes Suricata

Configurer Fail2ban pour lire le fichier eve.json de Suricata et bannir automatiquement les IPs malveillantes via le set nftables blocklist créé en phase 1.

# Sur VM-GW
apt install fail2ban -y
# /etc/fail2ban/filter.d/suricata.conf
[Definition]
failregex = .*"src_ip":"<HOST>".*"event_type":"alert".*
ignoreregex =
# /etc/fail2ban/jail.d/suricata.conf
[suricata]
enabled  = true
filter   = suricata
logpath  = /var/log/suricata/eve.json
maxretry = 3
findtime = 60
bantime  = 3600
action   = nftables-multiport[name=suricata, port="0:65535", protocol=tcp]

# Action personnalisée pour utiliser notre blocklist nftables
[suricata-nft]
enabled  = true
filter   = suricata
logpath  = /var/log/suricata/eve.json
maxretry = 3
findtime = 60
bantime  = 3600
action   = %(action_)s
           nft add element inet filter blocklist { <ip> timeout 1h }
# Vérifier le statut des bans
fail2ban-client status
fail2ban-client status suricata
nft list set inet filter blocklist
3.3 Lynis — Audit de sécurité et hardening

Lynis effectue un audit de sécurité complet d'un système Linux. Lancer l'audit sur VM-APP et VM-DB, analyser le score et appliquer les corrections prioritaires.

# Sur VM-APP et VM-DB
apt install lynis -y
lynis audit system --quiet 2>&1 | tee /tmp/lynis-report.txt
grep "Hardening index" /tmp/lynis-report.txt
grep "WARNING\|SUGGESTION" /tmp/lynis-report.txt | head -30
# 1. Désactiver les services inutiles
systemctl disable --now avahi-daemon cups bluetooth 2>/dev/null || true

# 2. Sécuriser SSH
cat >> /etc/ssh/sshd_config << 'EOF'
PermitRootLogin no
PasswordAuthentication no
MaxAuthTries 3
ClientAliveInterval 300
AllowUsers votre_user
EOF

# 3. Restreindre les permissions sysctl
cat >> /etc/sysctl.conf << 'EOF'
kernel.dmesg_restrict = 1
kernel.kptr_restrict = 2
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.tcp_syncookies = 1
EOF
sysctl -p

# 4. Relancer l'audit pour mesurer l'amélioration
lynis audit system --quiet | grep "Hardening index"
04

Alerting & Réponse aux Incidents

~2h
4.1 Alertmanager — Règles d'alerte et routage
# /etc/prometheus/rules/network.yml
groups:
  - name: network-alerts
    rules:

      - alert: HostDown
        expr: up == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Host {{ $labels.instance }} is DOWN"
          description: "Prometheus ne peut plus scraper {{ $labels.instance }} depuis 1 min."

      - alert: HighLatency
        expr: probe_duration_seconds{job="blackbox-icmp"} * 1000 > 100
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "Latence élevée vers {{ $labels.instance }}"
          description: "Latence ICMP : {{ $value | humanizeDuration }}"

      - alert: PacketLoss
        expr: probe_success{job="blackbox-icmp"} == 0
        for: 30s
        labels:
          severity: critical
        annotations:
          summary: "Perte de paquets vers {{ $labels.instance }}"

      - alert: FirewallDropSpike
        expr: rate(nftables_dropped_packets_total[2m]) > 50
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: "Spike de drops firewall détecté"
          description: "{{ $value }} paquets/s droppés — possible scan ou attaque"

      - alert: CPUSaturation
        expr: 100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[2m]))*100) > 90
        for: 3m
        labels:
          severity: critical
        annotations:
          summary: "CPU saturé sur {{ $labels.instance }}"
# /etc/alertmanager/alertmanager.yml
global:
  resolve_timeout: 5m

route:
  group_by: ['alertname', 'instance']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 1h
  receiver: 'webhook-local'
  routes:
    - match:
        severity: critical
      receiver: 'webhook-critical'

receivers:
  - name: 'webhook-local'
    webhook_configs:
      - url: 'http://localhost:5001/alert'
        send_resolved: true

  - name: 'webhook-critical'
    webhook_configs:
      - url: 'http://localhost:5001/critical'
        send_resolved: true
# /opt/alert-receiver/server.py
from http.server import HTTPServer, BaseHTTPRequestHandler
import json, datetime

class AlertHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        length = int(self.headers['Content-Length'])
        body = json.loads(self.rfile.read(length))
        ts = datetime.datetime.now().isoformat()
        for alert in body.get('alerts', []):
            status = alert['status'].upper()
            name   = alert['labels'].get('alertname', '?')
            inst   = alert['labels'].get('instance', '?')
            sev    = alert['labels'].get('severity', '?')
            print(f"[{ts}] [{status}] [{sev.upper()}] {name} — {inst}")
        self.send_response(200)
        self.end_headers()

HTTPServer(('0.0.0.0', 5001), AlertHandler).serve_forever()
4.2 Simulation d'incidents avancés
⚠ Important : Toutes ces simulations doivent être effectuées depuis une VM du lab uniquement. Ne jamais cibler des systèmes extérieurs.
# Sur VM-APP (serveur)
iperf3 -s -p 5201

# Sur VM-GW (client) — montée en charge progressive
for bw in 10M 50M 100M 500M 1G; do
  echo "=== Test bande passante: $bw ==="
  iperf3 -c 192.168.10.10 -p 5201 -b $bw -t 30 -J > /tmp/iperf-$bw.json
  sleep 10
done
# Sur VM-GW — Appliquer des dégradations graduelles sur eth0

# Étape 1 : latence seule (100ms ± 20ms)
tc qdisc add dev eth1 root netem delay 100ms 20ms
sleep 120  # Observer dans Grafana

# Étape 2 : latence + perte de paquets
tc qdisc change dev eth1 root netem delay 200ms 50ms loss 5%
sleep 120

# Étape 3 : corruption + réordonnancement
tc qdisc change dev eth1 root netem delay 300ms corrupt 2% reorder 10% 25%
sleep 120

# Nettoyage
tc qdisc del dev eth1 root
# Sur VM-SEC — Nmap pour déclencher les règles Suricata
apt install nmap -y

# Scan SYN furtif (doit déclencher l'alerte PORT SCAN)
nmap -sS -T4 --top-ports 1000 192.168.10.10

# Vérifier que Suricata a détecté le scan
grep "PORT SCAN" /var/log/suricata/fast.log

# Vérifier que Fail2ban a banni l'IP
nft list set inet filter blocklist
# Sur VM-SEC — Requêtes HTTP massives vers VM-APP
apt install apache2-utils -y
ab -n 50000 -c 200 http://192.168.10.10/

# Observer simultanément dans Grafana :
# — CPU de VM-APP (panel CPU par instance)
# — Logs Nginx avec explosion des status 200 puis 503
# — Alertes Prometheus si CPU > 90%
4.3 Plan de réponse aux incidents — Runbook

Pour chaque scénario simulé, rédiger un runbook de réponse structuré. C'est l'exercice central du TP : apprendre à diagnostiquer méthodiquement depuis les alertes jusqu'à la cause racine.

## Runbook — Incident : [NOM DE L'ALERTE]

### 1. Détection
- Alerte déclenchée : [nom_alerte, seuil, heure]
- Source de détection : Prometheus / Suricata / Loki

### 2. Triage (< 5 min)
- Impact utilisateur : OUI / NON / PARTIEL
- Services affectés : [liste]
- Urgence : P1 / P2 / P3

### 3. Diagnostic (requêtes à exécuter)
# Vérifier la disponibilité générale
$ ping -c 10 [instance] && traceroute [instance]

# Regarder les métriques au moment T de l'incident
# (utiliser Grafana en mode historique)

# Corréler avec les logs Loki
{instance="[vm]"} |= "error" | __error__=""

### 4. Cause racine identifiée
[Description précise]

### 5. Remédiation appliquée
[Commandes exécutées]

### 6. Vérification post-incident
- Métriques revenues à la normale : OUI / NON
- Durée totale de l'incident : [T]
- Action corrective permanente : [description]
05

Livrables & Rapport d'analyse

~1h
5.1 Livrables attendus
  • /etc/nftables.conf complet de VM-GW avec commentaires
  • /etc/prometheus/prometheus.yml et tous les fichiers de règles
  • /etc/loki/loki-config.yml + /etc/promtail/promtail-config.yml
  • /etc/suricata/rules/local.rules avec vos règles personnalisées
  • Export JSON du dashboard Grafana principal
  • Screenshot Grafana : vue pendant la congestion iperf3 (CPU + latence + bande passante)
  • Screenshot Grafana : corrélation dégradation netem + probe_duration_seconds
  • Screenshot Suricata fast.log pendant le scan Nmap
  • Screenshot nftables blocklist après bannissement par Fail2ban
  • Rapport Lynis avant/après hardening avec le score d'amélioration
  1. Quelle différence concrète observez-vous entre une panne totale (up == 0) et une dégradation silencieuse (probe_duration_seconds qui monte) ? Comment les détecter différemment ?
  2. En quoi le mode stateful du pare-feu (suivi des connexions via ct state) améliore-t-il la sécurité par rapport à un filtrage statique classique ?
  3. Lors du scénario DoS applicatif, quelles métriques ont augmenté en premier ? Quelle est la chaîne causale observée ?
  4. Quel est l'intérêt de corréler métriques Prometheus et logs Loki dans le même outil Grafana ? Donnez un exemple de diagnostic que cela accélère.
  5. Comparez le score Lynis avant et après hardening. Quelles mesures ont eu le plus d'impact sur la réduction de la surface d'attaque ?