Objectif : à la fin de cette journée, la VM Linux cible envoie ses logs vers la VM SOC, qui les traite via Logstash et les rend consultables dans Splunk.
java -version192.168.91.10 et 192.168.91.20 sont des exemples — adapter aux IPs réelles de votre lab| Horaire | Activité | VM(s) | Durée |
|---|---|---|---|
| 09h00 – 09h45 | Cours — Architecture SOC, pipeline de collecte, rôle de chaque composant | — | 45 min |
| 09h45 – 10h30 | Cours — Architecture Splunk (Forwarder / Indexer / Search Head) + SPL | — | 45 min |
| 10h30 – 10h45 | Pause | — | 15 min |
| 10h45 – 11h15 | Étape 0 — Mise en place et vérification des deux VMs | SOC + Cible | 30 min |
| 11h15 – 13h00 | TP 1 — Installation & configuration rsyslog + Logstash | SOC + Cible | 1h45 |
| 13h00 – 14h00 | Pause déjeuner | — | 1h |
| 14h00 – 17h30 | TP 2 — Déploiement Splunk + requêtes SPL sur données réelles | SOC + Cible | 3h30 |
| 17h30 – 18h00 | Validation collective + débrief | — | 30 min |
Cette étape est le prérequis absolu. Si les deux VMs ne communiquent pas correctement, aucun TP de la journée ne fonctionnera.
Les IPs ci-dessous sont des exemples basés sur un réseau NAT VMware typique. Votre sous-réseau peut être différent. Récupérer toujours les IPs réelles avec ip a sur chaque VM avant de commencer.
| VM | Rôle | IP fixe (exemple) | RAM | OS |
|---|---|---|---|---|
| VM SOC | Serveur central — reçoit tous les logs | 192.168.91.10 | 4 Go | Ubuntu 22.04 LTS |
| VM Linux cible | Machine surveillée — génère des logs | 192.168.91.20 | 2 Go | Ubuntu 22.04 LTS |
Avec VMware Workstation en mode NAT, les deux VMs partagent le réseau NAT VMware, peuvent communiquer entre elles et accéder à internet pour télécharger les paquets. Une seule carte réseau par VM suffit.
# Pour CHAQUE VM (SOC et cible) : # VM Settings → Network Adapter → NAT # VMware attribue les IPs automatiquement via DHCP # Le sous-réseau NAT est visible dans : # Edition → Virtual Network Editor → VMnet8 # Après démarrage de chaque VM, récupérer l'IP réelle : ip a | grep "inet 192" # Noter les deux IPs — elles serviront dans TOUT le TP
Ce TP utilise 192.168.91.10 (SOC) et 192.168.91.20 (cible) comme exemples. Vos IPs NAT réelles peuvent être différentes. Toujours vérifier avec ip a sur chaque VM avant de configurer quoi que ce soit.
Avec NAT, une seule carte réseau par VM suffit : accès internet ET communication inter-VMs sont assurés sur la même interface. Pas de configuration réseau manuelle nécessaire.
En mode NAT VMware, l'IP est attribuée automatiquement par DHCP. Il suffit de la récupérer et de la noter — elle sera utilisée dans toutes les configurations du TP.
# Récupérer l'IP de l'interface NAT VMware ip a | grep "inet 192" # Exemple de résultat : inet 192.168.91.10/24 brd 192.168.91.255 # → Votre IP SOC est 192.168.91.10 (adapter selon votre résultat) hostname -I # Méthode alternative
# Récupérer l'IP de l'interface NAT VMware ip a | grep "inet 192" # Exemple de résultat : inet 192.168.91.20/24 # → Votre IP cible est 192.168.91.20 (adapter selon votre résultat)
Ne pas passer à l'étape suivante si ce test échoue. Si le ping ne répond pas, vérifier la configuration du réseau NAT VMware et le pare-feu.
# Depuis la VM SOC, pinguer la VM cible ping -c 4 192.168.91.20 # Résultat attendu : 4 packets transmitted, 4 received, 0% packet loss
# Depuis la VM cible, pinguer la VM SOC ping -c 4 192.168.91.10
1. Vérifier que les deux VMs sont bien en mode NAT dans VMware. 2. Vérifier que les IPs sont sur le même sous-réseau (même préfixe 192.168.x). 3. Désactiver temporairement le pare-feu : sudo ufw disable. 4. Vérifier ip route sur les deux VMs.
Apache sera notre première source de logs applicatifs. Il sera surveillé par rsyslog et Logstash tout au long du cours.
sudo apt update sudo apt install -y apache2 # Vérifier qu'Apache fonctionne sudo systemctl status apache2 curl -s http://localhost | head -5 # Activer le module de log complet sudo a2enmod rewrite sudo systemctl restart apache2 # Générer quelques accès pour pré-remplir les logs for i in {1..10}; do curl -s http://localhost > /dev/null; done curl -s http://localhost/pagequiexistepas > /dev/null # Génère un 404 # Vérifier que les logs sont générés tail -5 /var/log/apache2/access.log
Le fichier /var/log/apache2/access.log contient des lignes avec des codes 200 et au moins un 404.
La VM SOC doit accepter les connexions entrantes sur les ports de collecte depuis la VM cible.
# Autoriser les ports de collecte depuis la VM cible # Autoriser le sous-réseau NAT VMware entier (adapter 192.168.91 à votre sous-réseau) sudo ufw allow from 192.168.91.0/24 to any port 5514 proto tcp # Logstash sudo ufw allow from 192.168.91.0/24 to any port 514 proto tcp # rsyslog sudo ufw allow from 192.168.91.0/24 to any port 9997 proto tcp # Splunk Forwarder sudo ufw allow from 192.168.91.0/24 to any port 1514 proto udp # Wazuh (Jour 3) # Autoriser l'accès web à Splunk depuis votre machine hôte sudo ufw allow 8000/tcp sudo ufw enable sudo ufw status
Les deux VMs communiquent, Apache génère des logs sur la VM cible, et les ports sont ouverts sur la VM SOC. La base est prête.
rsyslog tourne sur la VM cible et envoie vers la VM SOC. Logstash et Elasticsearch tournent sur la VM SOC et reçoivent depuis le réseau.
VM Cible :192.168.91.20 → rsyslog → TCP → VM SOC :192.168.91.10:5514 → Logstash → Elasticsearch → Splunk
Elasticsearch doit démarrer en premier — Logstash ne peut pas démarrer sans lui. Toutes ces commandes s'exécutent sur la VM SOC.
sudo apt update # Ajouter le dépôt officiel Elastic wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch \ | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] \ https://artifacts.elastic.co/packages/8.x/apt stable main" \ | sudo tee /etc/apt/sources.list.d/elastic-8.x.list sudo apt update && sudo apt install -y elasticsearch # IMPORTANT : désactiver la sécurité ET le SSL pour le TP # Elasticsearch 8.x active sécurité + SSL par défaut # Il faut désactiver les TROIS paramètres sinon le démarrage échoue sudo tee -a /etc/elasticsearch/elasticsearch.yml << 'EOF' xpack.security.enabled: false xpack.security.transport.ssl.enabled: false xpack.security.http.ssl.enabled: false EOF # Vérifier l'absence de doublons (erreur fréquente) grep -c "xpack.security.enabled" /etc/elasticsearch/elasticsearch.yml # Doit retourner 1 — si 2, ouvrir le fichier et supprimer la ligne en double : # sudo nano /etc/elasticsearch/elasticsearch.yml sudo systemctl enable --now elasticsearch # Vérifier (attendre ~30 secondes après démarrage) curl -s http://localhost:9200 | python3 -m json.tool
Un JSON avec "tagline" : "You Know, for Search" s'affiche. Elasticsearch est opérationnel.
# Le dépôt Elastic est déjà ajouté — installer directement sudo apt install -y logstash # Vérifier la version /usr/share/logstash/bin/logstash --version # Ne pas démarrer maintenant — d'abord créer la configuration
Les étapes 3 et 4 s'exécutent sur la VM Linux cible (192.168.91.20), pas sur la VM SOC.
rsyslog va transférer tous les logs de la VM cible vers Logstash sur la VM SOC. On crée un fichier dédié dans /etc/rsyslog.d/ pour ne pas modifier la configuration principale.
# Transférer TOUS les logs vers Logstash sur la VM SOC # @@ = TCP (fiable) · Un seul @ = UDP (perte silencieuse — interdit) # Remplacer 192.168.91.10 par l'IP réelle de votre VM SOC # Format JSON structuré — plus facile à parser pour Logstash # Créer le fichier via bash heredoc pour éviter les guillemets typographiques # Remplacer 192.168.91.10 par l'IP réelle de votre VM SOC sudo bash -c 'cat > /etc/rsyslog.d/50-soc.conf' << 'ENDOFFILE' template(name="LogstashJSON" type="string" string="{"@timestamp":"%timereported:::date-rfc3339%","host":"%hostname%","facility":"%syslogfacility-text%","severity":"%syslogseverity-text%","program":"%programname%","pid":"%procid%","message":"%msg:::json%"}\n") *.* @@192.168.91.10:5514;LogstashJSON ENDOFFILE # Vérifier l'absence de guillemets typographiques cat -A /etc/rsyslog.d/50-soc.conf | head -2
# Valider la configuration (dry-run) sudo rsyslogd -N1 # Si "Config validation run succeeded" → redémarrer sudo systemctl restart rsyslog sudo systemctl status rsyslog
Un copier-coller depuis un PDF ou une page web peut introduire des guillemets typographiques (" ") au lieu de guillemets droits ("). rsyslog refuse de démarrer avec ce type d'erreur. La méthode bash heredoc ci-dessus contourne ce problème. Si une erreur persiste, vérifier avec cat -A et recréer le fichier.
rsyslog tente de se connecter à 192.168.91.10:5514 mais Logstash n'est pas encore démarré. Les logs sont mis en file d'attente localement. Dès que Logstash sera lancé, ils seront envoyés automatiquement.
logger injecte une ligne dans le système syslog, qui sera transmise vers la VM SOC dès que Logstash sera démarré.
# Injecter un log de test horodaté logger -p auth.warning "TEST_SOC_TP1_$(date +%H%M%S)" # Vérifier que le log est bien présent dans le journal local grep "TEST_SOC_TP1" /var/log/auth.log # Générer quelques tentatives SSH échouées (pour les exercices SPL) for i in {1..6}; do ssh utilisateurquiexistepas@192.168.91.10 2>/dev/null || true done
Logstash écoute sur le port 5514/TCP et attend les logs JSON envoyés par rsyslog de la VM cible.
input {
# Recevoir les logs rsyslog JSON depuis la VM cible
tcp {
port => 5514
codec => "json"
type => "syslog"
}
}
Le filtre identifie les événements SSH, extrait les champs clés (utilisateur, IP source, succès/échec), et supprime les champs inutiles.
filter {
if [type] == "syslog" {
# ── Événements SSH ──────────────────────────────────────
if [program] == "sshd" {
grok {
match => { "message" => [
# Échec de connexion
"%{DATA:ssh_action} password for (invalid user )?%{DATA:ssh_user} from %{IP:src_ip} port %{NUMBER:src_port}",
# Connexion réussie
"Accepted %{DATA:ssh_method} for %{DATA:ssh_user} from %{IP:src_ip} port %{NUMBER:src_port}",
# Utilisateur inexistant
"Invalid user %{DATA:ssh_user} from %{IP:src_ip}"
]}
add_tag => ["ssh_event"]
}
}
# ── Fail2ban (prépare le Jour 2) ────────────────────────
if [program] == "fail2ban.actions" {
grok {
match => { "message" => "%{DATA:f2b_action} %{IP:banned_ip}" }
add_tag => ["fail2ban_event"]
}
}
# ── Normalisation commune ────────────────────────────────
mutate {
remove_field => ["@version", "port"]
}
# Géolocaliser l'IP source si elle est présente
if [src_ip] and [src_ip] != "127.0.0.1" {
geoip { source => "src_ip" target => "geoip" } # target obligatoire en Logstash 8.x (ECS)
}
}
}
Utiliser Grok Debugger (grokdebugger.com) : coller une ligne de log brute et le pattern pour voir les champs extraits en temps réel. Aucun redémarrage de service nécessaire.
output {
# Index Elasticsearch nommé par type et par date
elasticsearch {
hosts => ["http://localhost:9200"]
index => "syslog-%{+YYYY.MM.dd}"
}
# Afficher dans le terminal pour déboguer (à retirer en production)
stdout { codec => rubydebug }
}
# 1. Valider la syntaxe de tous les fichiers .conf (dry-run) sudo /usr/share/logstash/bin/logstash \ --config.test_and_exit \ -f /etc/logstash/conf.d/ # 2. Démarrer Logstash si "Configuration OK" # Autoriser la création automatique des index Logstash dans Elasticsearch 8.x curl -X PUT "http://localhost:9200/_cluster/settings" \ -H 'Content-Type: application/json' \ -d '{"persistent":{"action.auto_create_index":"syslog-*,*"}}' sudo systemctl enable --now logstash # 3. Suivre les logs de démarrage (attendre ~60 secondes) sudo journalctl -u logstash -f # 4. Depuis la VM CIBLE : injecter un nouveau log de test # logger -p auth.warning "TEST_LOGSTASH_ACTIF" # 5. Depuis la VM SOC : vérifier l'arrivée dans Elasticsearch curl -s "http://localhost:9200/syslog-*/_search?q=TEST_LOGSTASH_ACTIF&pretty" \ | python3 -m json.tool | grep -A2 '"message"'
La requête curl retourne "hits.total.value" : 1 avec le message de test. Les logs de la VM cible arrivent bien sur la VM SOC via le pipeline Logstash.
1. Vérifier les logs Logstash : sudo journalctl -u logstash --since "5 min ago". 2. Vérifier que Logstash écoute : ss -tlnp | grep 5514 sur la VM SOC. 3. Tester la connexion depuis la VM cible : nc -zv 192.168.91.10 5514. 4. Vérifier les règles UFW : sudo ufw status sur la VM SOC.
Apache écrit ses logs dans des fichiers locaux. On va configurer rsyslog pour lire ce fichier et le transférer vers Logstash, tout comme les logs système.
# Lire le fichier de logs Apache et le transférer au SOC # imfile = module de lecture de fichier module(load="imfile") input(type="imfile" File="/var/log/apache2/access.log" Tag="apache_access" Facility="local6" Severity="info" ) # Envoyer les logs Apache vers Logstash (même destination) if $syslogtag == 'apache_access' then @@192.168.91.10:5514 & stop
sudo systemctl restart rsyslog # Générer du trafic Apache pour tester for i in {1..15}; do curl -s http://localhost > /dev/null; done curl -s http://localhost/admin > /dev/null # → 404 curl -s http://localhost/../../../etc/passwd > /dev/null # → tentative LFI
Compléter le fichier filter existant avec un bloc pour parser les logs Apache. Le pattern COMBINEDAPACHELOG est intégré nativement dans Logstash — pas besoin de l'écrire.
# ── Logs Apache ───────────────────────────────────────── if [syslogtag] == "apache_access" { grok { match => { "message" => "%{COMBINEDAPACHELOG}" } add_tag => ["apache_access"] } mutate { # Harmoniser le nom du champ IP source rename => { "clientip" => "src_ip" } # Convertir le code HTTP en entier pour filtrer dans SPL convert => { "response" => "integer" } } }
sudo systemctl restart logstash
# Attendre ~60s, puis vérifier l'index Apache
curl -s "http://localhost:9200/syslog-*/_search?q=apache_access&pretty" | grep '"hits"'
Splunk est installé sur la VM SOC. Il va recevoir directement les logs de la VM cible via rsyslog et les requêtes SPL seront exécutées sur des données réelles générées par votre lab.
Splunk Enterprise (version d'évaluation 60 jours, 500 Mo/jour) — le lien de téléchargement est fourni par l'enseignant.
# Télécharger (remplacer par le lien fourni) wget -O splunk.deb "LIEN_FOURNI_PAR_ENSEIGNANT" # Installer sudo dpkg -i splunk.deb # Premier démarrage + acceptation de la licence # → définir un mot de passe admin (min 8 caractères, noté quelque part) sudo /opt/splunk/bin/splunk start --accept-license --run-as-root # → Définir le mot de passe admin (min. 8 caractères) quand demandé # → Message "Running Splunk as root is deprecated" = normal, pas une erreur # Activer le démarrage automatique sudo /opt/splunk/bin/splunk enable boot-start --run-as-root # Vérifier que Splunk est accessible ss -tlnp | grep 8000 # Doit afficher LISTEN sur *:8000 — c'est suffisant pour confirmer que Splunk tourne
Ouvrir un navigateur sur votre machine hôte → http://[IP_VM_SOC]:8000 (ex: 192.168.91.10:8000). La page de connexion Splunk s'affiche. Se connecter avec admin et le mot de passe choisi.
Dans Splunk, toutes les données sont organisées en index. Un index dédié "security" isole les événements de sécurité et permet une rétention indépendante.
Settings → Indexes → New Index Index Name : security Max Size : 5000 MB Retention : 30 days → Save
Splunk va écouter sur le port 9514/TCP pour recevoir les logs de la VM cible en parallèle de Logstash. Splunk dispose de parseurs natifs pour le format syslog — pas besoin de GROK.
Settings → Data Inputs → TCP → New Local Input Port : 9514 Source Type : syslog Index : security → Next → Review → Submit
sudo ufw allow from 192.168.91.0/24 to any port 9514 proto tcp # Adapter le sous-réseau NAT au vôtre
rsyslog supporte plusieurs destinations simultanées. On ajoute Splunk (port 9514) sans toucher à la configuration Logstash (port 5514) déjà en place.
# Envoyer vers Splunk sur la VM SOC — remplacer 192.168.91.10 par votre IP SOC réelle # Splunk parse nativement le format syslog — pas besoin de JSON *.* @@192.168.91.10:9514
sudo systemctl restart rsyslog
# Injecter un log de test pour Splunk
logger -p auth.info "TEST_SPLUNK_ACTIF_$(date +%H%M%S)"
index=security "TEST_SPLUNK_ACTIF"
La requête SPL retourne 1 événement avec votre message. Les logs de la VM cible arrivent dans Splunk.
http://[IP_VM_SOC]:8000 → "Search & Reporting" (ex: 192.168.91.10:8000). Toujours vérifier la plage temporelle en haut à droite (mettre "Last 60 minutes" ou "Today").
index=security # ❓ Combien de sourcetypes différents voyez-vous (panneau gauche) ? # ❓ Quel champ contient l'hostname de la VM cible ? # ❓ Quel programme génère le plus de logs ?
index=security
| stats count by sourcetype
| sort -count
# ❓ Modifier pour ne voir que les événements de sshd
# Générer d'abord des tentatives depuis la VM cible : # ssh [email protected] (refuser 6 fois) index=security "Failed password" | rex "from (?<src_ip>\d+\.\d+\.\d+\.\d+)" | stats count as nb_echecs by src_ip | where nb_echecs >= 3 | sort -nb_echecs # ⭐ LIVRABLE : Screenshot de ce résultat → binome_tp1_ssh.png # ❓ Quelle IP a le plus de tentatives échouées ? # ❓ Pourquoi ce seuil de 3 et pas 10 ou 100 ?
index=security | timechart span=5m count # Visualization → Line Chart # Save As → Report → "TP1_Volume_Par_Minute" # ❓ Y a-t-il un pic correspondant à vos tentatives SSH ? # ❓ Comment exploiter ce graphique en SOC au quotidien ?
# Générer du trafic Apache depuis la VM cible d'abord : # for i in {1..20}; do curl -s http://localhost > /dev/null; done index=security sourcetype=syslog "apache_access" | rex "(?<http_method>GET|POST|PUT|DELETE) (?<uri>\S+)" | stats count by http_method, uri | sort -count # ❓ Quelles URI ont été accédées le plus souvent ? # ❓ Retrouvez-vous la tentative d'accès à /admin et à /../etc/passwd ?
Tous ces points doivent être valides avant de quitter. Le Jour 2 démarre directement depuis cet état.
Faire un snapshot de chaque VM en fin de journée avec un nom explicite (ex: "Jour1_OK"). Si un TP du lendemain casse la configuration, vous pourrez revenir à cet état propre.
ip a | grep "inet 192" retourne une IPip a | grep "inet 192" retourne une IP différente de la VM SOCcurl http://192.168.91.20 retourne une page HTMLsudo ufw statussudo rsyslogd -N1 → "Config validation run succeeded"ss -tlnp | grep 5514 affiche LISTENlogger injecté sur la VM cible est retrouvable dans Elasticsearch sur la VM SOC via curlsyslog-* existe : curl -s localhost:9200/_cat/indices?v le listesrc_ip et response parséshttp://192.168.91.10:8000)security existe dans Splunk (Settings → Indexes)logger de test injecté sur la VM cible est retrouvable dans Splunk : index=security "TEST"TP1_Volume_Par_Minute est sauvegardé dans Splunkbinome_tp1_ssh.png réalisée et sauvegardéeLogstash normalise et enrichit (GeoIP, champs harmonisés) avant indexation. Splunk reçoit le flux brut et parse nativement. Cette redondance permet de comparer les deux approches et de basculer de l'une à l'autre sans interruption.
rsyslog avec TCP met les messages en file d'attente localement (disk queue configurable). À la reconnexion, les logs sont renvoyés. Sans queue configurée, seuls les logs générés pendant la coupure peuvent être perdus. C'est un argument pour la queue persistante en production.
Non, si rsyslog envoie en temps réel : les logs sont déjà sur le SOC au moment où l'attaquant tente d'effacer les fichiers locaux. C'est précisément l'un des bénéfices fondamentaux de la centralisation des logs.
Demain (Jour 2) : installation du Splunk Universal Forwarder sur la VM cible, déploiement de Fail2ban, et vous verrez votre premier vrai bannissement d'IP arriver dans Splunk en temps réel.