概要 — 何をする機能か
自動ブロックは、攻撃元 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 であり、管理者が有効化する必要があります。
いつ使うか
- ボットネット・スキャナー・ブルートフォース探索が絶え間なく到来し、手動のブロックでは追いつかないときに、自動防御を有効にします。
- 検知 ▸ JA3 にフィンガープリントをローテーションするボットネットが現れたら、それを自動的に捕捉できるようしきい値を調整します。
- 脅威 で特定の重大度(赤/橙)の IDS 警報を繰り返し発生させる送信元を、自動的にブロックしたいとき。
- ブロックリスト・評判 に蓄積されるブロック理由を確認し、過剰なブロックをホワイトリストで免責するとき。
画面構成
自動ブロックに専用の画面はありません。制御と観測のポイントは次のとおりです。
- 設定 — 運用ポリシー ▸ セキュリティ設定タブ ▸ 自動ブロックカード(マスタースイッチ・方式・範囲・トリガー・無罪判定)。
- 結果の観測 — ブロックリスト・評判(コレクターの /24 + スケジューラの /32 のブロック、理由、解除)。
- 免責 — ホワイトリスト(手動/自動無罪判定の IP・CIDR、有効期限つき)。
- トリガー元 — 脅威(IDS 重大度)、検知(JA3 ローテーション)。
使い方
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 は、実際にブロックされる前に、次の関門を順番に通過しなければなりません。
- 内部・自社網の除外 —
SecurityScope::isInternal($ip)が真ならスキップします(skipped_internal)。この判定は、登録済みインスタンスの IP(/24 接頭辞+完全一致 IP)と、運用ポリシーのinternal_networksホワイトリストを統合したものです。クエリ段階でもexcludePrefixes()をNOT LIKEであらかじめ除外しています。 - ホワイトリストによる免責 —
infr_whitelistに有効かつ期限切れでない /32 または /24 のエントリがあればスキップします(skipped_wl)。 - 無罪判定による拒否 — ハードシグナル(重大度トリガー)を持たない JA3 単独の候補にのみ適用されます。
reputation_capの予算内で AbuseIPDB の評判を照会し、その IP が完全に潔白(悪用スコア 0 かつ 通報 0 かつ Tor でない)であれば、ブロックする代わりにinnocent_days日間の自動ホワイトリスト登録(infr_whitelist(source=auto))を行います(innocent)。重大度による候補はこの関門を飛ばし、そのままブロックされます。 - server_index の解決 —
global→[0]、per_server→対象のdest_ipをServerIndexResolver::byIpで解決します(解決できなければ[0])。 - 書き込み —
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ノードだけ
ゲートのロジック:
autoblock_on=0→ コマンドは即座に「スキップ」と報告します(既定は OFF で安全)。- 前回の実行から間隔がまだ経過していない → スキップします。
--forceと--dryはゲートを迂回します。
出力例:
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
動作:
server_index IN (0, <sv>) AND is_active/is_use=1の条件でblacklist_info(/24)+infr_block(/32)を読み込みます。- balanced の重複排除 — 親の /24 がすでに覆っている /32 はスキップします。
- カーネル ipset を
hash:netに強制します(型が異なる場合は作り直し)。一時セットに読み込んだうえで、アトミックに入れ替えます(無停止)。 iptables -I INPUT -m set --match-set blacklist src -j DROPが存在することを保証します(冪等)。- 安全網 — プライベート(RFC1918)・ループバック・自社網の接頭辞(
HOME_NET_PREFIX)は、たとえ DB に紛れ込んだとしても ipset には決して読み込みません。
sync_blackには root 権限とカーネルのipset/iptablesツールが必要で、さらに対象ホストにblacklistipset があらかじめ存在していなければなりません: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
有効にしたのに何もブロックされません。
--dryで候補の件数を確認します:php artisan infr:auto-block --dry。- JA3 のしきい値が高すぎる可能性が高いです(既定は 50)。実際の攻撃者は約 32 前後なので、15–20 まで下げてください。
- 重大度トリガー:
autoblock_severity=critは sev≤1(赤)しか捕捉しません。橙も含めるにはwarn(sev≤2)に設定します。 - 候補がすべて
internal-skip/wl-skipになる場合は、運用ポリシーの内部網ホワイトリスト、またはホワイトリストを確認してください。
ブロックが実際のファイアウォールに届いていません。
infr_blockのエントリは、sync_blackが実行されるまで適用されません。対象ホストの cron、sv=<server_index>引数、blacklistipset の存在を確認してください。balancedの範囲では、親の /24 にすでに含まれる /32 は意図的に重複排除され、個別には読み込まれません(これは正常です)。
無関係な IP がブロックされました。
- ホワイトリストに /32 または /24 で登録すると、次のスイープから免責されます(既存の
infr_blockの行はブロックリストから解除してください)。 - 自動無罪による免責は JA3 単独の候補にのみ適用されます。重大度トリガーで捕捉された IP は評判に関係なくブロックされるため、手動での免責が必要です。
per_server なのに、記録が全体(server_index=0)として残ります。
- 対象の
dest_ipをinfr_server_indexで解決できない場合は、安全側に倒して[0]にフォールバックします。コレクター/インスタンスの IP 対応を確認してください。
スケジューラが複数のサーバーで同時に実行されます。
->onOneServer()->when($is_leader)のリーダーゲーティングにより、1ノードだけが実行します。リーダーロックの状態は観測ダッシュボードで確認してください。
関連項目
- 運用ポリシー — 自動ブロックのマスタースイッチ・トリガー・範囲(セキュリティ設定タブ)
- ブロックリスト・評判 — 自動ブロックの結果一覧・理由・解除
- ホワイトリスト — 免責する IP/CIDR、自動無罪による免責
- 検知 ▸ JA3 — JA3 ローテーショントリガーの情報源
- 脅威 — IDS 重大度トリガーの情報源
- IP 評判(AbuseIPDB) — 無罪判定による拒否のための評判照会

