TP : Mini-SIEM local avec Wazuh
Prérequis
Environnement technique
- Docker installé et fonctionnel.
- Docker Compose disponible (
docker compose version). - Git installé.
- curl installé.
- Accès à un terminal Bash ou Zsh.
- Accès Internet pour cloner le dépôt Wazuh Docker et télécharger les images.
- Pour la partie Kubernetes optionnelle :
kindetkubectlinstallés.
Installer jq
Sur Debian / Ubuntu :
sudo apt updatesudo apt install -y jqSur macOS avec Homebrew :
brew install jqVérifier les outils
docker --versiondocker compose versiongit --versioncurl --versionPour la partie Kubernetes optionnelle :
kubectl version --clientkind versionConfiguration minimale recommandée
| Élément | Valeur recommandée |
|---|---|
| CPU | 4 cœurs |
| RAM | 8 Go |
| Espace disque | 50 Go |
Précaution
Ce TP crée uniquement un environnement local.
Aucune ressource cloud n’est créée.
Wazuh utilise un certificat auto-signé. Le navigateur affichera une alerte de sécurité lors de l’accès au dashboard, ce qui est normal dans ce contexte de lab.
Le mot de passe du dashboard Wazuh est défini en clair dans le fichier scripts/env.sh. Ne jamais utiliser ce fichier dans un environnement partagé ou de production.
Objectifs
À la fin de ce TP, l’apprenant doit être capable de :
- Déployer un SIEM local avec Wazuh via Docker Compose.
- Configurer la collecte d’événements Docker dans Wazuh.
- Configurer la collecte d’événements Kubernetes dans Wazuh.
- Créer des règles locales de détection dans Wazuh.
- Générer des événements de test Docker et Kubernetes.
- Vérifier que les règles produisent des alertes dans Wazuh.
- Consulter les alertes dans le dashboard Wazuh.
- Produire un rapport local des résultats.
- Nettoyer l’environnement.
Commandes
1. Créer l’arborescence du TP
mkdir -p tp-mini-siem-localcd tp-mini-siem-local
mkdir -p scripts reports logs/docker logs/kubernetestouch logs/docker/docker-events.logtouch logs/kubernetes/kind-events.logfind . -maxdepth 3 -type d | sortRésultat attendu :
../logs./logs/docker./logs/kubernetes./reports./scripts2. Définir les variables du TP
cat > scripts/env.sh <<'EOF'export TP_NAME="tp-mini-siem-local"export WAZUH_VERSION="v4.14.2"
export WAZUH_DASHBOARD_URL="https://localhost"export WAZUH_DASHBOARD_USER="admin"export WAZUH_DASHBOARD_PASSWORD="SecretPassword"
export DOCKER_TEST_CONTAINER="siem-demo-nginx"export KIND_CLUSTER_NAME="mini-siem"export K8S_NAMESPACE="mini-siem"EOFsource scripts/env.shecho "$TP_NAME"echo "$WAZUH_VERSION"echo "$WAZUH_DASHBOARD_URL"3. Préparer le paramètre système requis
Sur Linux ou WSL2, définir vm.max_map_count :
sudo sysctl -w vm.max_map_count=262144Ce paramètre est requis par Wazuh Indexer (basé sur OpenSearch) pour gérer ses zones mémoire virtuelles. Sans lui, Wazuh Indexer ne démarre pas.
sysctl vm.max_map_count | tee reports/01-vm-max-map-count.txtRésultat attendu :
vm.max_map_count = 262144Sur macOS avec Docker Desktop, cette étape n’est pas nécessaire.
4. Cloner le dépôt Wazuh Docker
git clone https://github.com/wazuh/wazuh-docker.git -b "${WAZUH_VERSION}"cd wazuh-docker/single-nodels -la | tee ../../reports/02-wazuh-single-node-files.txt5. Ajouter les montages locaux nécessaires
Depuis wazuh-docker/single-node, créer le fichier docker-compose.override.yml :
cat > docker-compose.override.yml <<'EOF'services: wazuh.manager: volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ../../logs/docker:/var/log/docker-training:ro - ../../logs/kubernetes:/var/log/kubernetes-training:roEOFcat docker-compose.override.yml | tee ../../reports/03-compose-override.txtCe fichier ajoute au manager Wazuh :
/var/run/docker.sock: accès aux événements Docker du poste local.../../logs/docker: fichier d’événements Docker de test.../../logs/kubernetes: fichier d’événements Kubernetes de test.
6. Configurer la collecte Docker et Kubernetes
Sauvegarder la configuration Wazuh avant modification :
cp config/wazuh_cluster/wazuh_manager.conf config/wazuh_cluster/wazuh_manager.conf.bakAjouter la surveillance Docker et Kubernetes :
python3 - <<'PY'from pathlib import Path
path = Path("config/wazuh_cluster/wazuh_manager.conf")content = path.read_text()
block = """ <wodle name="docker-listener"> <disabled>no</disabled> <interval>1m</interval> <attempts>5</attempts> <run_on_start>yes</run_on_start> </wodle>
<localfile> <log_format>syslog</log_format> <location>/var/log/docker-training/docker-events.log</location> </localfile>
<localfile> <log_format>syslog</log_format> <location>/var/log/kubernetes-training/kind-events.log</location> </localfile>"""
if "docker-training/docker-events.log" not in content: content = content.replace("</ossec_config>", block + "\n</ossec_config>") path.write_text(content) print("Configuration mise à jour.")else: print("Configuration déjà présente, aucune modification.")PYVérifier la configuration :
grep -n "docker-listener\|docker-training\|kubernetes-training" config/wazuh_cluster/wazuh_manager.conf \ | tee ../../reports/04-wazuh-collection-config.txt7. Générer les certificats Wazuh
docker compose -f generate-indexer-certs.yml run --rm generatorfind config/wazuh_indexer_ssl_certs -type f | sort \ | tee ../../reports/05-wazuh-certificates.txt8. Démarrer Wazuh
docker compose up -ddocker compose ps | tee ../../reports/06-wazuh-containers.txtRésultat attendu :
wazuh.manager Upwazuh.indexer Upwazuh.dashboard Up9. Attendre l’initialisation du dashboard
docker compose logs wazuh.dashboard | tail -n 50 \ | tee ../../reports/07-wazuh-dashboard-logs.txtAttendre que le dashboard soit disponible (peut prendre 2 à 5 minutes) :
until curl -k -s https://localhost >/dev/null; do echo "Dashboard Wazuh en cours de démarrage..." sleep 15doneecho "Dashboard disponible."curl -k -I https://localhost | tee ../../reports/08-wazuh-dashboard-http.txtRésultat attendu :
HTTP/1.1 200 OKAccès au dashboard depuis un navigateur :
URL : https://localhostLogin : adminPassword : SecretPassword10. Créer des règles locales de détection
docker compose exec -T wazuh.manager bash -lc 'cat > /var/ossec/etc/rules/local_rules.xml' <<'EOF'<group name="local,training,docker,kubernetes,">
<rule id="100100" level="5"> <match>TRAINING_DOCKER_EVENT</match> <description>Docker : événement de conteneur détecté</description> <group>docker,training,</group> </rule>
<rule id="100101" level="8"> <match>TRAINING_DOCKER_CONTAINER_EXEC</match> <description>Docker : exécution de commande dans un conteneur détectée</description> <group>docker,training,suspicious_command,</group> </rule>
<rule id="100102" level="7"> <match>TRAINING_DOCKER_CONTAINER_STOP</match> <description>Docker : arrêt de conteneur détecté</description> <group>docker,training,container_lifecycle,</group> </rule>
<rule id="100200" level="6"> <match>TRAINING_K8S_EVENT</match> <description>Kubernetes : événement de cluster détecté</description> <group>kubernetes,training,</group> </rule>
<rule id="100201" level="8"> <match>TRAINING_K8S_WARNING</match> <description>Kubernetes : événement de type Warning détecté</description> <group>kubernetes,training,warning,</group> </rule>
<rule id="100202" level="9"> <match>TRAINING_K8S_FAILED_POD</match> <description>Kubernetes : pod en échec détecté</description> <group>kubernetes,training,failed_pod,</group> </rule>
</group>EOFVérifier les règles :
docker compose exec -T wazuh.manager bash -lc \ "grep -n '10010\|10020' /var/ossec/etc/rules/local_rules.xml" \ | tee ../../reports/09-local-rules.txtRedémarrer le manager pour prendre en compte les règles :
docker compose restart wazuh.managersleep 30docker compose ps wazuh.manager | tee ../../reports/10-wazuh-manager-after-rules.txtCentralisation et détection Docker
11. Créer un conteneur Docker de test
docker run -d \ --name "${DOCKER_TEST_CONTAINER}" \ nginx:alpinedocker ps --filter "name=${DOCKER_TEST_CONTAINER}" \ | tee ../../reports/11-docker-test-container.txt12. Générer un événement Docker normalisé
echo "$(date -Iseconds) source=docker event=TRAINING_DOCKER_EVENT container=${DOCKER_TEST_CONTAINER} action=create image=nginx:alpine" \ >> ../../logs/docker/docker-events.logtail -n 5 ../../logs/docker/docker-events.log \ | tee ../../reports/12-docker-event-log.txt13. Générer un événement Docker sensible
docker exec "${DOCKER_TEST_CONTAINER}" sh -c "id"echo "$(date -Iseconds) source=docker event=TRAINING_DOCKER_CONTAINER_EXEC container=${DOCKER_TEST_CONTAINER} command='sh -c id'" \ >> ../../logs/docker/docker-events.logtail -n 5 ../../logs/docker/docker-events.log \ | tee ../../reports/13-docker-exec-event.txt14. Générer un événement d’arrêt de conteneur
docker stop "${DOCKER_TEST_CONTAINER}"echo "$(date -Iseconds) source=docker event=TRAINING_DOCKER_CONTAINER_STOP container=${DOCKER_TEST_CONTAINER} action=stop" \ >> ../../logs/docker/docker-events.logtail -n 10 ../../logs/docker/docker-events.log \ | tee ../../reports/14-docker-stop-event.txt15. Vérifier les alertes Docker dans Wazuh
sleep 30docker compose exec -T wazuh.manager bash -lc \ "grep '10010' /var/ossec/logs/alerts/alerts.json | tail -n 20" \ | tee ../../reports/15-wazuh-docker-alerts.jsonLes règles locales 100100, 100101 et 100102 doivent produire des alertes.
Centralisation et détection Kubernetes (optionnel)
Cette partie nécessite kind et kubectl.
16. Créer un cluster Kubernetes local avec Kind
kind create cluster --name "${KIND_CLUSTER_NAME}"kubectl get nodes -o wide \ | tee ../../reports/16-kind-nodes.txtkubectl create namespace "${K8S_NAMESPACE}"kubectl get namespace "${K8S_NAMESPACE}" \ | tee ../../reports/17-k8s-namespace.txt17. Déployer une application Kubernetes saine
kubectl -n "${K8S_NAMESPACE}" create deployment web --image=nginx:alpinekubectl -n "${K8S_NAMESPACE}" rollout status deployment/webkubectl -n "${K8S_NAMESPACE}" get pods -o wide \ | tee ../../reports/18-k8s-web-pods.txtecho "$(date -Iseconds) source=kubernetes event=TRAINING_K8S_EVENT namespace=${K8S_NAMESPACE} workload=deployment/web action=created" \ >> ../../logs/kubernetes/kind-events.log18. Générer un pod Kubernetes en erreur
kubectl -n "${K8S_NAMESPACE}" run bad-image \ --image=does-not-exist:latest \ --restart=Never || truesleep 45kubectl -n "${K8S_NAMESPACE}" get pods \ | tee ../../reports/19-k8s-bad-image-pod.txtkubectl get events -A --sort-by=.lastTimestamp \ | tee ../../reports/20-k8s-events.txt19. Centraliser les événements Kubernetes dans Wazuh
Depuis la racine du TP, créer le script de collecte :
cd ../..cat > scripts/collect-k8s-events.sh <<'EOF'#!/usr/bin/env bashset -euo pipefail
OUTPUT_FILE="logs/kubernetes/kind-events.log"
kubectl get events -A --sort-by=.lastTimestamp --no-headers | while read -r line; do if echo "$line" | grep -E "Warning|Failed|BackOff|ErrImagePull|ImagePullBackOff" >/dev/null; then echo "$(date -Iseconds) source=kubernetes event=TRAINING_K8S_WARNING raw=\"$line\"" >> "$OUTPUT_FILE" fidoneEOFchmod +x scripts/collect-k8s-events.sh./scripts/collect-k8s-events.shecho "$(date -Iseconds) source=kubernetes event=TRAINING_K8S_FAILED_POD namespace=${K8S_NAMESPACE} pod=bad-image reason=ImagePullBackOff" \ >> logs/kubernetes/kind-events.logtail -n 20 logs/kubernetes/kind-events.log \ | tee reports/21-k8s-normalized-events.txtRevenir dans le dossier Wazuh :
cd wazuh-docker/single-node20. Vérifier les alertes Kubernetes dans Wazuh
sleep 30docker compose exec -T wazuh.manager bash -lc \ "grep '10020' /var/ossec/logs/alerts/alerts.json | tail -n 20" \ | tee ../../reports/22-wazuh-kubernetes-alerts.jsonLes règles locales 100200, 100201 et 100202 doivent produire des alertes.
Consultation dans le dashboard Wazuh
21. Accéder au dashboard
Ouvrir dans un navigateur :
https://localhost| Champ | Valeur |
|---|---|
| Utilisateur | admin |
| Mot de passe | SecretPassword |
Le navigateur peut afficher une alerte de certificat. C’est attendu car le TP utilise un certificat auto-signé.
22. Rechercher les alertes Docker
Dans le dashboard Wazuh, rechercher les identifiants de règles :
10010010010110010223. Rechercher les alertes Kubernetes
Dans le dashboard Wazuh, rechercher les identifiants de règles :
100200100201100202Rapport de synthèse
24. Revenir à la racine du TP
cd ../..25. Créer un rapport de synthèse local
{ echo "# Rapport TP : Mini-SIEM local avec Wazuh" echo echo "## Environnement" echo echo "| Élément | Valeur |" echo "|---|---|" echo "| TP | ${TP_NAME} |" echo "| Version Wazuh | ${WAZUH_VERSION} |" echo "| Dashboard | ${WAZUH_DASHBOARD_URL} |" echo "| Conteneur Docker de test | ${DOCKER_TEST_CONTAINER} |" echo "| Cluster Kubernetes local | ${KIND_CLUSTER_NAME} |" echo "| Namespace Kubernetes | ${K8S_NAMESPACE} |" echo echo "## Composants déployés" echo echo "| Composant | Rôle |" echo "|---|---|" echo "| Wazuh Manager | Collecte, analyse et corrélation |" echo "| Wazuh Indexer | Indexation des événements |" echo "| Wazuh Dashboard | Visualisation des alertes |" echo "| Docker | Source d'événements conteneurs |" echo "| Kind | Source Kubernetes locale optionnelle |" echo echo "## Fichiers surveillés" echo echo "| Fichier | Source |" echo "|---|---|" echo "| logs/docker/docker-events.log | Événements Docker normalisés |" echo "| logs/kubernetes/kind-events.log | Événements Kubernetes normalisés |" echo echo "## Règles locales" echo echo "| Rule ID | Détection |" echo "|---|---|" echo "| 100100 | Docker : événement de conteneur |" echo "| 100101 | Docker : exécution de commande dans un conteneur |" echo "| 100102 | Docker : arrêt de conteneur |" echo "| 100200 | Kubernetes : événement de cluster |" echo "| 100201 | Kubernetes : événement Warning |" echo "| 100202 | Kubernetes : pod en échec |" echo echo "## Tests réalisés" echo echo "| Test | Résultat attendu |" echo "|---|---|" echo "| Démarrage Wazuh | Dashboard disponible sur https://localhost |" echo "| Événement Docker normalisé | Alerte Wazuh 100100 |" echo "| Commande Docker exec | Alerte Wazuh 100101 |" echo "| Arrêt conteneur Docker | Alerte Wazuh 100102 |" echo "| Événement Kubernetes | Alerte Wazuh 100200 |" echo "| Warning Kubernetes | Alerte Wazuh 100201 |" echo "| Pod Kubernetes en échec | Alerte Wazuh 100202 |"} > reports/rapport-tp-mini-siem-local.md26. Afficher le rapport
cat reports/rapport-tp-mini-siem-local.md27. Lister les fichiers générés
find . -maxdepth 3 -type f | sort \ | tee reports/23-generated-files.txtNettoyage
28. Supprimer le conteneur Docker de test
docker rm -f "${DOCKER_TEST_CONTAINER}" 2>/dev/null || truedocker ps -a --filter "name=${DOCKER_TEST_CONTAINER}"29. Supprimer le cluster Kubernetes local (optionnel)
Réaliser cette étape uniquement si la partie Kubernetes a été complétée.
kind delete cluster --name "${KIND_CLUSTER_NAME}"kind get clusters || true30. Arrêter Wazuh et supprimer les volumes
cd wazuh-docker/single-nodedocker compose down -vdocker compose psdocker volume ls | grep wazuh || true31. Supprimer le dossier local
Se placer dans le dossier parent avant d’exécuter cette commande.
cd ../..cd ..rm -rf tp-mini-siem-localRésultat attendu
À la fin du TP, les éléments suivants doivent avoir été validés :
| Élément | Validation |
|---|---|
| Wazuh local | Dashboard disponible sur https://localhost |
| Collecte Docker | Événements Docker présents dans le fichier surveillé |
| Détection Docker | Alertes 100100, 100101, 100102 visibles dans Wazuh |
| Collecte Kubernetes | Événements Kubernetes centralisés dans le fichier surveillé |
| Détection Kubernetes | Alertes 100200, 100201, 100202 visibles dans Wazuh |
| Rapport | Rapport Markdown disponible dans reports/ |
| Nettoyage | Conteneurs, volumes et cluster Kind supprimés |
Aucune ressource cloud, aucune clé AWS et aucun compte externe ne sont utilisés pendant ce TP.