InfraGuard

自動ブロックパイプライン

コレクターとスケジューラが、設定したトリガーに合致する攻撃元 IP を自動的にリスト化し、カーネルの ipset で遮断するバックグラウンド防御の流れ。

概要 — 何をする機能か

自動ブロックは、攻撃元 IP を人手を介さずに検知・審査・遮断する InfraGuard のバックグラウンドパイプラインです。これは画面ではなく、コレクター・スケジューラ・カーネル ipset をまたぐ流れです。本記事ではその全体構造を解説します。

このパイプラインには、単一の適用点(ipset)に合流する2つの独立したブロック経路があります。

経路 実行主体 書き込み先 単位 情報源
① コレクター自動ブロック 各ホスト上の Node コレクター(srct_tx · kts_tx · eve_ingest) blacklist_info /24(C クラス) Suricata L7 · Kitsune ML
② スケジューラ自動ブロック InfraGuard アプリ(infr:auto-block → AutoBlockService) infr_block /32(個別)または /24 suricata_alert_ct · suricata_tls_ct
③ 適用(共通) infr_sync_black.mjs(ホストの cron) カーネル ipset blacklist hash:net ① + ② の和集合

どちらの経路も、ブロックの直前にホワイトリストと無罪判定のチェックを実行します。 確証のある悪用だけが残り、誤検知の可能性が高い候補は免責されます。経路 ②(スケジューラ)は既定で OFF であり、管理者が有効化する必要があります。

いつ使うか

画面構成

自動ブロックに専用の画面はありません。制御と観測のポイントは次のとおりです。

使い方

1. 経路 ② スケジューラ自動ブロック — 有効化とチューニング

既定は OFF です(autoblock_on=0)。運用ポリシー ▸ セキュリティ設定でマスタースイッチを入れ、そのうえでポリシーを調整します。

方式(mode)

値 意味
global(既定) 1台のサーバーで観測された侵害を、全サーバーに適用します(server_index=0)。
per_server 攻撃を受けたサーバーにのみ適用します — 対象の dest_ip を infr_server_index 経由で server_index に解決します。

範囲(scope)

値 スケジューラの書き込み 説明
balanced(推奨・既定) 個別の /32 IDS プログラムは /24 を使い、InfraGuard は個別の /32 を追加します — sync_black は、すでに /24 に含まれている /32 をスキップします。
broad /24 C クラス全体をブロックします — 広く覆えますが、無関係な近隣 IP を巻き込む危険があります。
granular 個別の /32 1 IP ずつ — 正確ですが、ローテーションに対しては後手に回ります。

トリガー(OR — 候補はどちらか一方を満たすだけで成立)

① IDS ルールセット重大度   suricata_alert_ct
   WHERE alert_ts >= NOW() - INTERVAL {window_min} MINUTE
     AND severity <= {sev_max}          -- crit=1, warn=2(Suricata: 1=最重大 … 3=低)
   GROUP BY src_ip HAVING COUNT(*) >= {sev_count}

② 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}

重大度トリガーが使う時刻カラムは alert_ts ですが、JA3 トリガーが使うのは event_ts です(テーブルごとに異なります)。しきい値を調整する際は、それぞれの期間がどのカラムで絞り込まれるのかに注意してください。

ポリシーの既定値(OpsPolicy::autoBlock())

設定キー 既定値 制限 意味
autoblock_on 0 — マスタースイッチ(1=有効)。既定は OFF
autoblock_mode global global|per_server ブロック方式
autoblock_scope balanced broad|granular|balanced ブロック範囲
autoblock_interval_min 10 ≥1 実効スイープ間隔(分)
autoblock_window_min 10 ≥1 重大度の評価期間(分)
autoblock_sev_on 1 — トリガー ① を有効化
autoblock_severity crit crit|warn crit=sev≤1、warn=sev≤2
autoblock_sev_count 1 ≥1 期間内の最小警報件数
autoblock_ja3_on 1 — トリガー ② を有効化
autoblock_ja3_rotation 50 ≥2 相異なる JA3 フィンガープリントが N 個以上
autoblock_ja3_window_min 360 ≥1 JA3 の評価期間(分・6時間)
autoblock_innocent_on 1 — 無罪判定による拒否を有効化
autoblock_innocent_days 30 ≥1 自動ホワイトリスト登録の期間(日)
autoblock_reputation_cap 25 0–200 1スイープあたりの評判照会回数

JA3 ローテーションのチューニング(実測): 実環境の JA3 ローテーション攻撃者は、/32 セッションあたり相異なる JA3 が約 32 個でピークに達するのが典型です(データセンター/クラウドのボットで、GREASE を使わないため安定していてブロックしやすい)。したがって既定の ja3_rotation=50 では何も捕捉できません。 実際に発火させるには 15–20 程度まで下げてください。まず --dry を実行して候補の件数を確認します。

2. 候補の審査順序(AutoBlockService::run)

収集された候補 IP は、実際にブロックされる前に、次の関門を順番に通過しなければなりません。

  1. 内部・自社網の除外 — SecurityScope::isInternal($ip) が真ならスキップします(skipped_internal)。この判定は、登録済みインスタンスの IP(/24 接頭辞+完全一致 IP)と、運用ポリシーの internal_networks ホワイトリストを統合したものです。クエリ段階でも excludePrefixes() を NOT LIKE であらかじめ除外しています。
  2. ホワイトリストによる免責 — infr_whitelist に有効かつ期限切れでない /32 または /24 のエントリがあればスキップします(skipped_wl)。
  3. 無罪判定による拒否 — ハードシグナル(重大度トリガー)を持たない JA3 単独の候補にのみ適用されます。reputation_cap の予算内で AbuseIPDB の評判を照会し、その IP が完全に潔白(悪用スコア 0 かつ 通報 0 かつ Tor でない)であれば、ブロックする代わりに innocent_days 日間の自動ホワイトリスト登録(infr_whitelist(source=auto))を行います(innocent)。重大度による候補はこの関門を飛ばし、そのままブロックされます。
  4. server_index の解決 — global→[0]、per_server→対象の dest_ip を ServerIndexResolver::byIp で解決します(解決できなければ [0])。
  5. 書き込み — InfrBlock::updateOrCreate([server_index, cidr], …) により infr_block へ upsert し、source='schedule'、is_active=true、reason='[InfraGuard Auto] …' を付与します。
候補の収集(OR) → 内部の除外 → ホワイトリスト → (JA3 単独)無罪判定による拒否 → server_index → infr_block へ書き込み

isSpotless() は、評判の照会が失敗した場合・未設定の場合・判定できなかった場合に false(=慎重にブロックする)を返します。無罪による免責は、IP が明らかに潔白なときにだけ発動する保守的な関門です。

3. スケジューラとコマンド

infr:auto-block はデーモンではなく、1回だけ評価して終了する単発コマンドです。スケジューラは毎分 tick しますが、実効的な間隔は autoblock_interval_min です。

# ゲートを確認し(ポリシーが OFF なら即座に no-op)、1回だけ評価して書き込む
php artisan infr:auto-block

# 書き込みを行わず候補の集計だけを行う(チューニング・検証用)
php artisan infr:auto-block --dry

# ポリシーのゲート(有効化・間隔)を迂回して1回だけ強制実行する
php artisan infr:auto-block --force

# 何もブロックしなかった場合は出力を抑制する(スケジュール用)
php artisan infr:auto-block --quiet-if-ok

スケジュールへの登録(routes/console.php):

Schedule::command('infr:auto-block --quiet-if-ok')
    ->everyMinute()
    ->withoutOverlapping(2)
    ->onOneServer()
    ->when($is_leader);   // リーダーゲーティング — 複数台のうち1ノードだけ

ゲートのロジック:

出力例:

infr:auto-block — 候補 12(sev 3 · ja3 9) · ブロック 7 · wl-skip 1 · internal-skip 2 · innocent 2

4. 経路 ① コレクター自動ブロック(Node)

各ホスト上の Node コレクターは、Suricata のイベントを取り込み、/24 単位で blacklist_info に直接ブロックを書き込みます。この経路はスケジューラ(経路 ②)から独立しており、常に動作します。

コレクター 層 検知内容
infr_eve_ingest.cjs 取り込み Suricata の eve.json → suricata_http_ct · suricata_tls_ct · suricata_flow_ct · suricata_alert_ct へ投入
infr_srct_tx.cjs シグネチャ/ヒューリスティック Suricata L7 を集計 → 5分類のスキャナー/ボット検知 → blacklist_info /24
infr_kts_tx.cjs Kitsune ML conntrack + オートエンコーダによる異常検知(anomaly_score) → blacklist_info /24

srct_tx の5つの脅威分類:

(A) [HTTP] URL スキャナー      .env / .git / wp-login などスキャナー特有の URL
(B) [HTTP] ボット User-Agent   curl / python-requests / sqlmap などツールの痕跡
(C) [HTTP] 総当たり探索        短時間に大量の 4xx 応答(パスの総当たり)
(D) [TLS]  JA3 異常            JA3 が多数、SNI が欠落などボットネットのフィンガープリント
(E) [FLOW] TCP フラグ異常      短いスキャンセッションが多数(ポートスキャン)

srct_tx もブロックの直前にホワイトリストによる絞り込みと自動無罪免責を実行します。AbuseIPDB の評判を照会するのは E-only(短いスキャン単独)の候補だけで、明らかに潔白(通報 0 · 悪用スコア 0 · Tor でない)であれば 30 日間の免責(infr_whitelist(source=auto))として登録し、ブロックを見送ります。ハードシグナル(A/A2/B/C/D)が1つでもあれば、そのままブロックします。定数としきい値は規則としきい値で管理します。

5. 経路 ③ 適用 — sync_black → ipset

infr_sync_black.mjs は各ホストで定期的に実行され、両方のリストをカーネル ipset blacklist に同期します。

# ホストごとに、その server_index を指定して実行する(root 権限が必要)
node infr_sync_black.mjs sv=4

# crontab(5分ごと。重複実行を防ぐため flock を使用)
*/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

動作:

  1. server_index IN (0, <sv>) AND is_active/is_use=1 の条件で blacklist_info(/24)+ infr_block(/32)を読み込みます。
  2. balanced の重複排除 — 親の /24 がすでに覆っている /32 はスキップします。
  3. カーネル ipset を hash:net に強制します(型が異なる場合は作り直し)。一時セットに読み込んだうえで、アトミックに入れ替えます(無停止)。
  4. iptables -I INPUT -m set --match-set blacklist src -j DROP が存在することを保証します(冪等)。
  5. 安全網 — プライベート(RFC1918)・ループバック・自社網の接頭辞(HOME_NET_PREFIX)は、たとえ DB に紛れ込んだとしても ipset には決して読み込みません。

sync_black には root 権限とカーネルの ipset/iptables ツールが必要で、さらに対象ホストに blacklist ipset があらかじめ存在していなければなりません:

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

データソース

情報源テーブルと記録テーブルはすべて legacy_glory 接続(コレクターと適用スクリプトが共有する DB)上にあります。

テーブル 接続 役割 単位
suricata_alert_ct legacy_glory 重大度トリガーの情報源(カラム alert_ts · severity · src_ip · dest_ip · signature) —
suricata_tls_ct legacy_glory JA3 ローテーショントリガーの情報源(カラム event_ts · ja3_hash · src_ip) —
blacklist_info legacy_glory コレクターによる自動ブロックのリスト(IDS プログラム · srct/kts) /24
infr_block legacy_glory InfraGuard のスケジューラが所有するブロックリスト(マイグレーション 000751) /32·/24
infr_whitelist legacy_glory ブロックの免責(手動 · 自動無罪 · シード) /32·/24
infr_server_index default(MAIN) 疎で連番でない server_index ↔ エイリアス/インスタンスの対応表(000750) —

infr_block のスキーマ(要約)

カラム 型 意味
server_index int 0=全体 · それ以外=infr_server_index で解決したサーバー
cidr varchar(43) 個別 IP(/32)または正規化した /24 · UNIQUE(server_index,cidr)
ip varchar(45) 元の IP(表示用)
reason varchar(500) トリガーの根拠([InfraGuard Auto] sev1 x3 …)
source varchar(16) auto · manual · schedule
is_active bool sync_black が読み込むかどうか
expires_at datetime NULL=無期限
last_seen_at datetime 最後に再検知した時刻(削除判断用)

アクセス権限

自動ブロックに利用者向けの実行 UI はありません。関係する権限のゲートは次のとおりです(レベル: demo=1 · staff=5 · admin=10)。

対象 必要な権限
自動ブロックのポリシー設定(運用ポリシー ▸ セキュリティ設定) 管理者(管理、レベル 5 以上 / admin)
ブロック結果の閲覧(ブロックリスト) セキュリティの閲覧(staff、レベル 2 以上)
手動のブロック/解除 · ホワイトリストへの書き込み staff(レベル 2 以上)+監査ログ
スケジューラの実行(infr:auto-block) システム(ログイン利用者ではありません) — リーダーゲーティング

スケジューラが使う認証情報はハードコードされておらず、infr_collector / .env に外部化されています。sync_black の DB 認証情報と自社網の接頭辞も同様に、環境変数またはインベントリ ▸ ツールのマッシュアップ置換によって注入されます(ハードコードなし)。

トラブルシューティング・FAQ

有効にしたのに何もブロックされません。

ブロックが実際のファイアウォールに届いていません。

無関係な IP がブロックされました。

per_server なのに、記録が全体(server_index=0)として残ります。

スケジューラが複数のサーバーで同時に実行されます。

関連項目

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