Introduction
Les services auto-hébergés exposés par le biais d'un proxy inverse attirent inévitablement les scanners automatisés à la recherche de mauvaises configurations, de panneaux d'administration et de points d'extrémité vulnérables. Dans cet article, je montre comment transformer les journaux d'accès de routine de Traefik en un contrôle défensif actif en utilisant Elastic Security et Cloudflare.
J'utilise une règle de détection ES|QL prête à l'emploi pour identifier les comportements de découverte et de fuzzing des serveurs web. Lorsque des schémas d'exploration suspects sont détectés, un flux de travail automatisé bloque immédiatement l'IP source incriminée au niveau de la périphérie via l'API Cloudflare. La meilleure partie de cette configuration est qu'elle s'adapte sans effort. En construisant cette plomberie de réponse une fois pour la détection de fuzzing, je peux attacher exactement la même action de blocage à n'importe quelle autre règle Elastic, comme celles qui capturent les injections SQL ou les tentatives d'inclusion de fichiers. Cela transforme un pipeline de journalisation de base en une défense périmétrique hautement adaptable.
Contexte et paysage des menaces
Mon laboratoire personnel utilise Proxmox VE pour les conteneurs et les machines virtuelles. J'utilise un proxy inverse Traefik, sécurisé par Authelia pour l'authentification, pour permettre un accès externe sans VPN. Cloudflare, avec le proxy activé, gère le DNS.
Pour ceux qui ne sont pas familiers avec cette pile spécifique, Traefik agit comme la porte d'entrée du réseau. Lorsqu'une requête web arrive via Cloudflare, Traefik achemine dynamiquement le trafic vers le bon conteneur interne tout en gérant les certificats SSL pour que les connexions restent cryptées. Cependant, avant que le trafic n'atteigne ces applications dorsales, il est intercepté par Authelia. En s'appuyant sur la fonction d'authentification avancée de Traefik, Authelia met en œuvre le Single Sign-On et l'authentification multi-facteurs sur l'ensemble du réseau. Cela signifie que les scanners automatisés et les attaquants ne peuvent même pas atteindre les écrans de connexion de mes services internes sans passer par ce portail sécurisé initial.
Pour maintenir la visibilité et la sécurité, j'ingère ces logs d'accès Traefik dans Elastic en utilisant l'intégration officielle. Lors d'un contrôle de routine, j'ai observé dans ces journaux de nombreux codes de réponse HTTP 404 provenant des mêmes adresses IP sources.
Ce schéma suggère un trafic potentiel de sondage ou de fuzzing de serveurs web ciblant des vulnérabilités dans des applications qui ne sont pas réellement utilisées sur mon réseau. Parmi les exemples de ces chemins ciblés, citons /wp-includes/mani., /wp-content/plugins/all-in-one-wp-security-and-firewall/templates.php, /archive.php et /wp-admin/includes/header.php.
Philosophie de conception : pourquoi pas Fail2Ban ?
Une question fréquente dans la communauté des homelabs est de savoir pourquoi ne pas utiliser des outils locaux comme Fail2Ban ou CrowdSec directement sur le serveur Traefik. Bien qu'il s'agisse d'excellents outils, l'orchestration de la réponse par Elastic Security et la transmission du bloc à Cloudflare présentent deux avantages majeurs. Le fait de laisser tomber le trafic malveillant à la périphérie de Cloudflare permet d'économiser de la bande passante locale et d'empêcher les scanners de pénétrer dans le réseau domestique. De plus, l'orchestration de la réponse par le biais d'Elastic nous permet de disposer d'un guichet unique pour l'ensemble de la surveillance de la sécurité.
Stratégie de détection et stratégie de mise en œuvre
Pour identifier efficacement la reconnaissance malveillante, notre stratégie repose sur l'analyse de la fréquence des codes de réponse HTTP au niveau du proxy. Plus précisément, nous recherchons un volume élevé d'erreurs 404 (Not Found) générées par une seule IP source dans un court laps de temps, un indicateur classique de l'exploration de répertoires ou de vulnérabilités.
Bien qu'Elastic Security fournisse des règles de détection robustes et prêtes à l'emploi pour ce scénario précis, ces règles nécessitent des données ECS (Elastic Common Schema) correctement normalisées pour fonctionner correctement. La détection et l'atténuation de ces scans nécessitent donc un flux coordonné. Pour que cela fonctionne, nous devons ingérer les journaux Traefik, ajouter le champ host.name manquant à l'aide d'un pipeline personnalisé et faire pointer la règle de détection sur nos données.
Logique et réglage du seuil
Notre stratégie de détection s'éloigne de la simple correspondance des chaînes de caractères et s'appuie plutôt sur des seuils statistiques. La règle surveille spécifiquement les ressources refusées ou inexistantes représentées par les codes de réponse HTTP 403 et 404 et regroupe cette activité en fonction de l'IP source d'origine.
Ce comportement est régi par la dernière instruction where de la requête. Par défaut, une alerte n'est déclenchée que si une IP source produit plus de 500 erreurs sur 250 chemins URI distincts au cours de la fenêtre d'interrogation. Ce seuil à deux niveaux est conçu pour éliminer les faux positifs, en veillant à ce qu'un seul élément cassé ne déclenche pas un blocage, tout en identifiant les scripts automatisés qui parcourent les listes de mots du répertoire.
Dans un homelab ou une équipe plus restreinte, ces valeurs par défaut sont souvent trop permissives. Étant donné que le trafic externe légitime n'a aucune raison d'accéder à des panneaux d'administration inexistants sur mon réseau, j'ai ajusté la sensibilité afin de détecter rapidement les efforts de reconnaissance plus furtifs. J'ai modifié la logique pour qu'elle se déclenche lorsque event_count > 100 et url_original_count_distinct > 50.
Pour les environnements de production où les applications génèrent naturellement des volumes d'erreurs plus importants, vous pouvez envisager d'augmenter ces valeurs ou d'ajouter une clause ES|QL where not pour exclure les liens brisés connus. Enfin, j'utilise un filtre where source.ip not in (...) pour m'assurer que les outils de sécurité autorisés ou les scanners de vulnérabilité personnelle ne sont pas accidentellement interdits par le flux de travail automatisé.
Ingestion des journaux d'accès à Traefik
Pour ingérer les logs d'accès de Traefik dans le cluster, j'ai utilisé l'intégration par défaut de Traefik. L'agent Elastic collecte les journaux des serveurs Traefik. Cette intégration écrit les journaux ingérés dans le flux de données logs-traefik.access-default.
Construire un pipeline d'ingestion personnalisé
Le champ host.name est crucial pour la règle de détection que j'utilise, mais l'intégration par défaut de Traefik ne le remplit pas. Par conséquent, un pipeline d'ingestion personnalisé est nécessaire pour ajouter ce champ. Comme l'intégration Traefik utilise un flux de fichiers sur le serveur Traefik, je peux copier la valeur du champ agent.name existant pour remplir host.name.
J'utilise spécifiquement le pipeline logs-traefik.access@custom au lieu de modifier le pipeline principal. Les intégrations élastiques sont conçues pour récupérer et exécuter automatiquement ces pipelines @custom à la fin de leur flux de traitement. Plus important encore, les pipelines par défaut sont complètement écrasés chaque fois que je mets à jour une intégration. Le stockage de ma logique dans le pipeline personnalisé garantit que mes mappages de champs survivront à la prochaine mise à jour. L'appel à l'API nécessaire pour créer ce pipeline peut être exécuté dans la console Dev Tools :
PUT _ingest/pipeline/logs-traefik.access@custom
{
"description": "copy the agent.name field to the host.name field",
"processors": [
{
"set": {
"field": "host.name",
"value": "{{{agent.name}}}",
"override": false,
"ignore_empty_value": true,
"ignore_failure": true
}
}
]
}
Réponse automatisée via le flux de travail de Cloudflare
Pour passer de la détection à la défense active, nous mettons en œuvre un flux de travail qui comble le fossé entre nos alertes élastiques et la périphérie de Cloudflare. La logique est conçue pour être efficace : plutôt que de créer une nouvelle règle de pare-feu pour chaque alerte, ce qui atteindrait rapidement les limites de règles de Cloudflare, le flux de travail récupère d'abord la liste de blocage existante. Il ajoute ensuite dynamiquement la nouvelle IP source incriminée à cette liste avant de transmettre la mise à jour à l'API de Cloudflare. Une fois le bord sécurisé, le flux de travail se termine par l'accusé de réception de l'alerte dans Elastic, ce qui permet de boucler la boucle de l'incident.
Conditions préalables et portée du jeton
Ce processus nécessite une clé API et l'ID de la zone pour la configuration de Cloudflare. Le jeton API doit posséder les privilèges "Zone WAF edit" pour permettre la création de la règle. Lorsque vous générez ce jeton dans le tableau de bord de Cloudflare, utilisez l'option "Create Custom Token" et définissez les autorisations strictement Zone -> Zone WAF -> Edit à.
Une fois le flux de travail configuré, il doit être affecté en tant qu'action à la règle de détection "Web Server Discovery ou Fuzzing Activity".
Les conditions préalables étant réunies, nous allons voir comment construire le flux de travail étape par étape.
Configuration du flux de travail et déclencheurs
Tout d'abord, nous définissons les métadonnées de base. Ce flux de travail bloque les adresses IP trouvées dans les alertes de l'activité de découverte du serveur Web ou de Fuzzing. Le flux de travail est activé et dispose d'un délai d'attente de 30 secondes pour la demande d'API. Dans ce cas, il est basé sur une alerte, et s'exécute donc automatiquement lorsqu'une alerte de sécurité est déclenchée.
# =========================================================================
# Workflow: Block IP at Cloudflare test
# Category: security/response
# =========================================================================
version: '1'
name: Block IP at Cloudflare
enabled: true
triggers:
- type: alert
Constantes et authentification
Cette section contient les variables d'authentification. N'oubliez pas de remplacer les chaînes de caractères par votre jeton API et votre ID de zone.
consts:
cloudflare_api: "<cloudflare API>"
cloudflare_zone: "<cloudflare ZONE>"
Étape 1 : Récupération de la liste de blocage actuelle
La séquence vérifie si la règle de pare-feu existe déjà. Le flux de travail effectue une requête HTTP GET pour récupérer la règle de blocage IP existante.
steps:
- name: cloudflare_current_block
type: http
with:
url: "https://api.cloudflare.com/client/v4/zones/{{consts.cloudflare_zone}}/rulesets/phases/http_request_firewall_custom/entrypoint"
headers:
Authorization: Bearer {{consts.cloudflare_api}}
method: GET
on-failure:
continue: true
Étape 2 : Mise à jour ou création de la règle de pare-feu
Si elle existe, la règle est complétée par l'adresse IP, sinon la règle est créée. Le flux de travail identifie si le bloc d'analyse "webserver" description est présent. Si c'est le cas, il ajoute la nouvelle adresse IP à la liste actuelle des adresses IP bloquées par le biais d'une requête PUT. Si ce n'est pas le cas, il revient à la création d'une nouvelle règle.
- name: cloudflare_block
type: if
condition: 'steps.cloudflare_current_block.output.data.result.rules[0].description == "webserver scanning block"'
steps:
- name: ip-block-cloudflare_add
type: http
with:
url: "https://api.cloudflare.com/client/v4/zones/{{consts.cloudflare_zone}}/rulesets/phases/http_request_firewall_custom/entrypoint"
method: PUT
headers:
Authorization: Bearer {{consts.cloudflare_api}}
timeout: 30s
body: '{ "rules": [ { "description": "webserver scanning block", "expression": "{{steps.cloudflare_current_block.output.data.result.rules[0].expression}} or (ip.src eq {{event.alerts[0].source.ip}})", "action": "block" } ]}'
else:
- name: ip-block-cloudflare_new
type: http
with:
url: "https://api.cloudflare.com/client/v4/zones/{{consts.cloudflare_zone}}/rulesets/phases/http_request_firewall_custom/entrypoint"
method: PUT
headers:
Authorization: Bearer {{consts.cloudflare_api}}
timeout: 30s
body: '{ "rules":[ { "description": "webserver scanning block", "expression": "(ip.src eq {{event.alerts[0].source.ip}})", "action": "block" } ]}'
on-failure:
continue: true
Étape 3 : Accuser réception de l'alerte
L'alerte est ensuite acquittée. Cette étape utilise l'action kibana.SetAlertsStatus pour clôturer automatiquement l'alerte dans Elastic Security.
- name: update_alert_status
type: kibana.SetAlertsStatus
with:
status: "acknowledged"
signal_ids: ["{{event.alerts[0]._id}}"]
Étape 4 : Attacher le flux de travail à la règle
Une fois le flux de travail entièrement construit, la dernière étape consiste à l'associer à la règle de détection afin qu'elle se déclenche automatiquement. Dans les paramètres de la règle Elastic Security pour la règle "Web Server Discovery or Fuzzing Activity", je navigue vers l'onglet Rule actions et j'ajoute une nouvelle action. Dans la liste déroulante des connecteurs, je sélectionne simplement le flux de travail Cloudflare que je viens de créer.
Note sur les limites du WAF
Comme ce flux de travail concatène les adresses IP à l'aide d'une instruction or (or (ip.src eq <IP>)), n'oubliez pas que Cloudflare a une limite de caractères pour les expressions WAF personnalisées (généralement 4096 caractères pour les niveaux standard). Dans les environnements très ciblés, cette chaîne peut éventuellement atteindre la limite. Pour les homelabs et les petites équipes, la suppression manuelle de cette règle WAF constitue une remise à zéro salutaire.
Essais et validation
Pour vérifier que le pipeline fonctionne de bout en bout, nous pouvons générer du bruit à l'aide d'un outil de fuzzing standard. Vous pouvez simuler une attaque par balayage contre votre propre homelab à l'aide d'un outil de fuzzing tel que ffuf ou gobuster.
Exécutez une analyse rapide d'un répertoire inexistant sur votre domaine Traefik accessible au public :
ffuf -u https://your-domain.com/FUZZ -w /path/to/wordlist.txt
Une fois la simulation lancée, nous pouvons observer la chaîne de défense automatisée en action. Les erreurs de 404 apparaissent presque immédiatement dans le flux de données de logs-traefik.access-default. Dans l'intervalle d'interrogation, la règle ES|QL identifie le modèle et génère une nouvelle alerte dans la page Alertes de sécurité élastiques. À partir de là, le flux de travail prend le relais : il fait passer l'état d'alerte à "acknowledged" et envoie le bloc IP à notre règle WAF Cloudflare, neutralisant ainsi efficacement le scanner à la périphérie avant qu'il ne puisse poursuivre sa reconnaissance.
Vous pouvez confirmer que le blocage a réussi en consultant votre tableau de bord Cloudflare à l'adresse Security -> WAF -> Custom rules. (Remarque : veillez à supprimer votre IP de la règle Cloudflare par la suite afin de ne pas vous bloquer vous-même).
Élargir la défense
L'intérêt de cette configuration est que notre flux de travail Cloudflare ne se limite pas à la détection de fuzzing. Une fois l'automatisation construite, nous pouvons l'attacher à n'importe quelle règle Elastic qui signale un trafic proxy suspect. Par exemple, nous pouvons lier cette même action de réponse à des règles prêtes à l'emploi ciblant des exploits d'application spécifiques, comme l'activité d'inclusion de fichier local du serveur Web, l' activité potentielle d'inclusion de fichier à distance du serveur Web, afin d'éliminer immédiatement l'attaquant. Il s'associe également parfaitement à Potential Spike in Web Server Error Logs et Unusual Web User Agent pour repérer les scraper mal configurés et les bruits de réseau plus généraux. Nous construisons la plomberie une fois, et tout d'un coup l'ensemble du périmètre devient plus intelligent.
Conclusion
L'intégration de Traefik et de Cloudflare dans Elastic Security est un excellent moyen de transformer des journaux d'accès de base en une défense active. Les laboratoires domestiques sont constamment bombardés par des scanners automatisés à la recherche de fruits faciles à attraper. Ce flux de travail automatisé permet non seulement de bloquer les attaquants à la périphérie, mais aussi de réduire la fatigue liée aux alertes en acquittant automatiquement les incidents. Il s'agit d'un exemple concret de la manière dont l'orchestration et la réponse en matière de sécurité peuvent vous faire gagner du temps tout en améliorant considérablement votre position en matière de sécurité.