InfraGuard

Chaîne de blocage automatique

Le flux de défense en arrière-plan par lequel les collecteurs et le planificateur inscrivent automatiquement les IP attaquantes qui remplissent des déclencheurs configurables, puis les appliquent via l’ipset du noyau.

Vue d’ensemble — à quoi sert cette fonction

Le blocage automatique est la chaîne d’arrière-plan d’InfraGuard qui détecte, vérifie et bloque les IP attaquantes sans intervention humaine. Ce n’est pas un écran : c’est un flux qui traverse les collecteurs, le planificateur et l’ipset du noyau. Cet article documente l’ensemble de cette structure.

La chaîne comporte deux voies de blocage indépendantes qui convergent vers un unique point d’application (ipset).

Voie S’exécute comme Écrit dans Granularité Source
① Blocage automatique du collecteur Collecteurs Node sur chaque hôte (srct_tx · kts_tx · eve_ingest) blacklist_info /24 (classe C) Suricata L7 · Kitsune ML
② Blocage automatique du planificateur Application InfraGuard (infr:auto-block → AutoBlockService) infr_block /32 (individuelle) ou /24 suricata_alert_ct · suricata_tls_ct
③ Application (partagée) infr_sync_black.mjs (cron de l’hôte) ipset blacklist du noyau hash:net union de ①+②

Les deux voies exécutent un contrôle de liste blanche et d’innocence juste avant de bloquer. Seul l’abus confirmé subsiste ; les candidats vraisemblablement faux positifs sont innocentés. La voie ② (planificateur) est désactivée par défaut et doit être activée par un administrateur.

Quand l’utiliser

Disposition

Le blocage automatique n’a pas d’écran dédié. Ses points de contrôle et d’observation sont :

Utilisation

1. Voie ② blocage automatique du planificateur — activation et réglage

La valeur par défaut est désactivée (autoblock_on=0). Basculez l’interrupteur principal dans Politique d’exploitation ▸ Paramètres de sécurité, puis ajustez la politique.

Mode

Valeur Signification
global (par défaut) Une compromission constatée sur un serveur est appliquée à l’ensemble du parc (server_index=0).
per_server Appliqué uniquement au serveur attaqué — la dest_ip cible est résolue en server_index via infr_server_index.

Portée

Valeur Ce qu’écrit le planificateur Description
balanced (recommandé, par défaut) /32 individuelle Les programmes IDS utilisent des /24 ; InfraGuard ajoute des /32 individuelles — sync_black ignore toute /32 déjà couverte par une /24.
broad /24 Bloque toute la classe C — couverture large, mais risque d’atteindre des IP voisines innocentes.
granular /32 individuelle Une IP à la fois — précis, mais lent face à la rotation.

Déclencheurs (OU — un seul suffit à un candidat)

① Gravité du jeu de règles IDS   suricata_alert_ct
   WHERE alert_ts >= NOW() - INTERVAL {window_min} MINUTE
     AND severity <= {sev_max}          -- crit=1, warn=2 (Suricata : 1=critique … 3=faible)
   GROUP BY src_ip HAVING COUNT(*) >= {sev_count}

② Botnet à rotation JA3   suricata_tls_ct
   WHERE event_ts >= NOW() - INTERVAL {ja3_window_min} MINUTE
     AND ja3_hash IS NOT NULL
   GROUP BY src_ip HAVING COUNT(DISTINCT ja3_hash) >= {ja3_rotation}

La colonne d’horodatage du déclencheur de gravité est alert_ts, tandis que le déclencheur JA3 utilise event_ts (elles diffèrent selon la table). Lors du réglage des seuils, gardez à l’esprit sur quelle colonne chaque fenêtre filtre.

Valeurs par défaut de la politique (OpsPolicy::autoBlock())

Clé de réglage Défaut Bornes Signification
autoblock_on 0 — Interrupteur principal (1=activé). Désactivé par défaut
autoblock_mode global global|per_server Mode de blocage
autoblock_scope balanced broad|granular|balanced Portée du blocage
autoblock_interval_min 10 ≥1 Intervalle de balayage effectif (min)
autoblock_window_min 10 ≥1 Fenêtre d’évaluation de la gravité (min)
autoblock_sev_on 1 — Déclencheur ① activé
autoblock_severity crit crit|warn crit=sev≤1, warn=sev≤2
autoblock_sev_count 1 ≥1 Nombre minimal d’alertes dans la fenêtre
autoblock_ja3_on 1 — Déclencheur ② activé
autoblock_ja3_rotation 50 ≥2 empreintes JA3 distinctes ≥ N
autoblock_ja3_window_min 360 ≥1 Fenêtre d’évaluation JA3 (min · 6 h)
autoblock_innocent_on 1 — Veto d’innocence activé
autoblock_innocent_days 30 ≥1 Durée de la mise en liste blanche automatique (jours)
autoblock_reputation_cap 25 0–200 Consultations de réputation par balayage

Réglage de la rotation JA3 (mesuré) : dans la réalité, les auteurs de rotation JA3 plafonnent généralement autour de 32 JA3 distincts par session /32 (bots de centre de données ou de cloud, sans GREASE = stables et blocables). Le ja3_rotation=50 par défaut ne capture donc rien. Pour qu’il se déclenche réellement, abaissez-le à environ 15–20. Exécutez d’abord --dry pour voir le nombre de candidats.

2. Ordre de vérification des candidats (AutoBlockService::run)

Chaque IP candidate collectée doit franchir ces filtres dans l’ordre avant d’être réellement bloquée.

  1. Exclusion du réseau interne / propre — ignorée si SecurityScope::isInternal($ip) (skipped_internal). Cette décision réunit les IP des instances enregistrées (préfixe /24 + IP exacte) et la liste blanche internal_networks de la politique d’exploitation. L’étape de requête pré-exclut également excludePrefixes() via NOT LIKE.
  2. Innocentement par liste blanche — ignorée si infr_whitelist contient une entrée /32 ou /24 active et non expirée (skipped_wl).
  3. Veto d’innocence — s’applique uniquement aux candidats issus du seul JA3, sans signal fort (déclencheur de gravité). Dans la limite du budget reputation_cap, il consulte la réputation AbuseIPDB ; si l’IP est irréprochable (score d’abus 0 ET signalements 0 ET pas Tor), elle est mise automatiquement en liste blanche pour innocent_days (infr_whitelist(source=auto)) au lieu d’être bloquée (innocent). Les candidats issus de la gravité sautent ce filtre et sont bloqués sans délai.
  4. Résolution de server_index — global→[0], per_server→résolution de la dest_ip cible via ServerIndexResolver::byIp (repli [0]).
  5. Écriture — upsert dans infr_block via InfrBlock::updateOrCreate([server_index, cidr], …) avec source='schedule', is_active=true, reason='[InfraGuard Auto] …'.
collecte des candidats (OU) → exclusion des internes → liste blanche → (JA3 seul) veto d’innocence → server_index → écriture dans infr_block

isSpotless() renvoie false (c’est-à-dire : bloquer par prudence) si la consultation de réputation échoue, n’est pas configurée ou reste indéterminée. L’innocentement est un filtre conservateur qui ne se déclenche que lorsqu’une IP est manifestement propre.

3. Planificateur et commande

infr:auto-block est une commande à passage unique qui évalue une fois puis se termine — ce n’est pas un démon. Le planificateur se réveille chaque minute, mais l’intervalle effectif est autoblock_interval_min.

# Vérifier le filtre (aucune action immédiate si la politique est désactivée), puis évaluer et écrire une fois
php artisan infr:auto-block

# Compter uniquement les candidats, sans écriture (réglage/validation)
php artisan infr:auto-block --dry

# Forcer une exécution en contournant le filtre de la politique (activation + intervalle)
php artisan infr:auto-block --force

# Supprimer la sortie lorsqu’aucun blocage n’a eu lieu (pour la planification)
php artisan infr:auto-block --quiet-if-ok

Enregistrement dans la planification (routes/console.php) :

Schedule::command('infr:auto-block --quiet-if-ok')
    ->everyMinute()
    ->withoutOverlapping(2)
    ->onOneServer()
    ->when($is_leader);   // filtrage par nœud leader — un seul nœud dans tout le parc

Logique du filtre :

Exemple de sortie :

infr:auto-block — candidats 12 (sev 3 · ja3 9) · bloqués 7 · wl-skip 1 · internal-skip 2 · innocent 2

4. Voie ① blocage automatique du collecteur (Node)

Les collecteurs Node de chaque hôte consomment les événements Suricata et bloquent directement dans blacklist_info au niveau /24. Cette voie est indépendante du planificateur (voie ②) et s’exécute en permanence.

Collecteur Couche Ce qu’il détecte
infr_eve_ingest.cjs Ingestion eve.json de Suricata → alimente suricata_http_ct · suricata_tls_ct · suricata_flow_ct · suricata_alert_ct
infr_srct_tx.cjs Signature/heuristique Agrège Suricata L7 → détection de scanners/bots en 5 catégories → blacklist_info /24
infr_kts_tx.cjs Kitsune ML conntrack + détection d’anomalies par auto-encodeur (anomaly_score) → blacklist_info /24

Les cinq catégories de menaces de srct_tx :

(A) [HTTP] scanner d’URL         .env / .git / wp-login et autres URL à signature de scanner
(B) [HTTP] User-Agent de bot     curl / python-requests / sqlmap et autres signatures d’outils
(C) [HTTP] sondage en force      beaucoup de réponses 4xx sur une fenêtre courte (force brute de chemins)
(D) [TLS]  anomalie JA3          nombreux JA3, SNI absent et autres empreintes de botnet
(E) [FLOW] anomalie de flags TCP  nombreuses sessions de scan courtes (balayage de ports)

srct_tx exécute lui aussi un filtrage par liste blanche + un innocentement automatique juste avant de bloquer : seuls les candidats E-only (scan court isolé) font l’objet d’une consultation de réputation AbuseIPDB et, s’ils sont manifestement propres (0 signalement · score d’abus 0 · pas Tor), ils sont enregistrés comme exemption de 30 jours (infr_whitelist(source=auto)) et le blocage est ignoré. Si un signal fort quelconque (A/A2/B/C/D) est présent, le blocage est immédiat. Ses constantes et seuils sont gérés dans Règles et seuils.

5. Voie ③ application — sync_black → ipset

infr_sync_black.mjs s’exécute périodiquement sur chaque hôte et synchronise les deux listes dans l’ipset blacklist du noyau.

# Exécuter par hôte avec son server_index (nécessite root)
node infr_sync_black.mjs sv=4

# crontab (toutes les 5 min, flock pour éviter les recouvrements)
*/5 * * * * /usr/bin/flock -n /var/run/sync_black.lock \
  /usr/bin/node /root/server_monitor/infr_sync_black.mjs sv=4 \
  >> /var/log/sync_black.log 2>&1

Comportement :

  1. Charger depuis blacklist_info (/24) + infr_block (/32) là où server_index IN (0, <sv>) AND is_active/is_use=1.
  2. Déduplication balanced — ignorer toute /32 dont la /24 parente la couvre déjà.
  3. Forcer l’ipset du noyau en hash:net (le recréer s’il est d’un autre type), charger dans un ensemble temporaire, puis procéder à un échange atomique (sans interruption).
  4. S’assurer que iptables -I INPUT -m set --match-set blacklist src -j DROP existe (idempotent).
  5. Filet de sécurité — les préfixes privés (RFC1918), de bouclage et du réseau propre (HOME_NET_PREFIX) ne sont jamais chargés dans l’ipset, même s’ils se glissent dans la base.

sync_black requiert root ainsi que les outils noyau ipset/iptables, et l’ipset blacklist doit déjà exister sur l’hôte cible :

ipset create blacklist hash:net family inet hashsize 8192 maxelem 65536
iptables -I INPUT -m set --match-set blacklist src -j DROP

Sources de données

Toutes les tables sources et d’enregistrement résident sur la connexion legacy_glory (la base partagée par les collecteurs et les scripts d’application).

Table Connexion Rôle Granularité
suricata_alert_ct legacy_glory Source du déclencheur de gravité (colonnes alert_ts · severity · src_ip · dest_ip · signature) —
suricata_tls_ct legacy_glory Source du déclencheur de rotation JA3 (colonnes event_ts · ja3_hash · src_ip) —
blacklist_info legacy_glory Liste de blocage automatique du collecteur (programmes IDS · srct/kts) /24
infr_block legacy_glory Liste de blocage détenue par le planificateur InfraGuard (migration 000751) /32·/24
infr_whitelist legacy_glory Exemptions de blocage (manuelle · innocentement automatique · amorce) /32·/24
infr_server_index default (MAIN) Correspondance éparse et non séquentielle entre server_index et alias/instance (000750) —

Schéma de infr_block (résumé)

Colonne Type Signification
server_index int 0=global · sinon=serveur résolu via infr_server_index
cidr varchar(43) IP individuelle (/32) ou /24 normalisée · UNIQUE(server_index,cidr)
ip varchar(45) IP d’origine (affichage)
reason varchar(500) preuve du déclencheur ([InfraGuard Auto] sev1 x3 …)
source varchar(16) auto · manual · schedule
is_active bool si sync_black la charge
expires_at datetime NULL=permanent
last_seen_at datetime dernière redétection (décision de purge)

Accès

Le blocage automatique n’a pas d’interface d’exécution destinée aux utilisateurs. Les contrôles de droits concernés sont (niveaux : demo=1 · staff=5 · admin=10) :

Cible Accès requis
Configuration de la politique de blocage automatique (Politique d’exploitation ▸ Paramètres de sécurité) Administrateur (Administration, niveau ≥5 / admin)
Consultation des résultats de blocage (Liste de blocage) Lecture sécurité (staff, niveau ≥2)
Blocage/levée manuels · écritures dans la Liste blanche staff (niveau ≥2) + journal d’audit
Exécution du planificateur (infr:auto-block) Système (pas un utilisateur connecté) — filtré par nœud leader

Les identifiants utilisés par le planificateur ne sont jamais codés en dur — ils sont externalisés vers infr_collector / .env. Les identifiants de base de données de sync_black et les préfixes du réseau propre sont de même injectés via des variables d’environnement ou la substitution du mashup Inventaire ▸ Outils (aucun codage en dur).

Dépannage et FAQ

Je l’ai activé, mais rien n’est bloqué.

Les blocages n’atteignent pas le pare-feu réel.

Une IP innocente a été bloquée.

Le mode est per_server, mais les enregistrements arrivent en global (server_index=0).

Le planificateur s’exécute sur plusieurs serveurs à la fois.

Voir aussi

자동 차단 스위치가 있는 운영 정책 보안 탭
자동 차단 스위치가 있는 운영 정책 보안 탭
자동 차단 결과가 쌓이는 차단 목록
자동 차단 결과가 쌓이는 차단 목록