LinuxでSuricata IDS/IPSを導入:リアルタイムトラフィック解析とネットワーク防御

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

半半年前、私たちの境界エッジゲートウェイは10Gbpsアップリンクの負荷で逼迫していました。旧来のSnort環境では、午後のトラフィック急増時に受信パケットの最大12%がドロップしていました。可視性が最も求められるタイミングで生じたこの死角は、セキュリティ体制に大きな打撃を与えていました。Suricataへの移行はこのボトルネックを劇的に解消しました。ネイティブなマルチスレッド機能とゼロコピーのAF_PACKETキャプチャエンジンにより、マイクロバーストも難なく吸収できるようになったのです。

本稿では、6か月間の本番トラフィックから得られたメトリクスに基づき、UbuntuまたはDebian環境でSuricataをパッシブセンサー(IDS)およびインラインゲートキーパー(IPS)として導入・運用する手順を解説します。

クイックスタート(5分)

公式リポジトリと自動ルールアップデータを使用すれば、基本的なIDSの立ち上げは約5分で完了します。

1. Suricataのインストール

UbuntuのuniverseリポジトリにもSuricataは含まれていますが、そのパッケージは数マイナーバージョン遅れていることがよくあります。最新のプロトコルパーサーやバグ修正、パフォーマンスアップデートを利用するために、公式のOpen Information Security Foundation(OISF)PPAを使用しましょう。

sudo add-apt-repository ppa:oisf/suricata-stable -y
sudo apt update
sudo apt install suricata jq ethtool -y

2. Emerging Threatsルールの取得

Suricataにはsuricata-updateが同梱されています。このツールはEmerging Threats(ET)Openなどの厳選されたフィードから脅威シグネチャを直接取得してマージし、45,000件以上のアクティブな検知ルールを数秒でダウンロードします。

sudo suricata-update
sudo suricata -T -c /etc/suricata/suricata.yaml -v

本番稼働させる前には、必ず設定を検証してください。-Tフラグを指定すると、ルールの構文やYAML設定のドライランチェックが実行されます。出力の最後にConfiguration provided was successfully testedと表示されることを確認してください。

3. パッシブIDSモードでのSuricataの実行

ip -br addrでインターフェースを確認し、プライマリインターフェース(ここではeth0)にバインドしてSuricataを起動します:

sudo systemctl stop suricata
sudo suricata -c /etc/suricata/suricata.yaml -i eth0 --init-errors-fatal

別のターミナルウィンドウで、jqを使用して構造化されたセキュリティアラートをリアルタイムで監視します:

sudo tail -f /var/log/suricata/eve.json | jq 'select(.event_type=="alert")'

詳細解説

Suricataには明確に異なる2つの運用形態があります。IDSとしては、ネットワークフローに一切手を加えることなく、SPANポートやミラーリングされたトラフィックを受動的に検査します。一方IPSとしては、トラフィック経路に直接配置され、カーネルがルーティングする前にパケットを評価してドロップ判定を下します。ギガビット規模のスループットを持続的に処理できるかどうかは、スレッド分散とバッファ管理にかかっています。

マルチスレッドアーキテクチャ

シングルスレッドのエンジンは1つのCPUコアがボトルネックとなり、帯域幅の増加に伴ってパケットドロップが発生します。Suricataはパケット取得、プロトコルデコード、ストリーム/フロー再構築、シグネチャ検査、ログ記録を独立したスレッドに分散させます。

  • 実行モード「autofp」(Automatic Flow Pinning):専用のキャプチャスレッドがパケットを取り込み、5タプル(送信元IP、宛先IP、ポート番号、プロトコル)のハッシュを計算します。Suricataは同一セッションのすべてのパケットを同じワーカースレッドに固定(ピン留め)します。これによりCPUのL2/L3キャッシュの局所性が維持され、順不同のパケット再構築を防ぎます。
  • 実行モード「workers」:割り当てられたキューまたはインターフェースに対して、各スレッドがキャプチャ、デコード、ストリーム再構築、検査というライフサイクル全体を処理します。専用アプライアンスなどで、スレッド間のスケジューリングオーバーヘッドなしに最大限のラインレートスループットを引き出したい場合にこのモードを使用します。

suricata.yamlにおけるAF_PACKETの最適化

標準のlibpcapドライバは、すべてのフレームをカーネルメモリからユーザー空間へコピーするシステムコールに依存しています。1Gbpsを超える高負荷環境では、このメモリコピーが大量のCPUサイクルを消費し、深刻なパケットドロップを招きます。一方、LinuxのAF_PACKETリングバッファはカーネルメモリをユーザー空間に直接マッピングするため、そのオーバーヘッドを完全に回避できます。

/etc/suricata/suricata.yamlを開き、監視対象インターフェースのキャプチャ設定を調整します:

af-packet:
  - interface: eth0
    threads: auto
    cluster-id: 99
    cluster-type: cluster_flow
    defrag: yes
    use-mmap: yes
    mmap-locked: yes
    tpacket-v3: yes
    ring-size: 204800

その成果は数値にも如実に表れました。このチューニングを実施する前、ゲートウェイでは日中の6Gbpsバースト時に約7.4%のパケットドロップが発生していました。スレッドあたり204,800フレームのtpacket-v3リングバッファを割り当てたところ、パケットドロップ率は0.001%まで急減しました。また、テスト機のIntel Xeon Silver(16コア)全体でCPU使用率が均等に平準化されました。

eve.jsonからの有用なシグナルの抽出

Suricataは、アラート、HTTPメタデータ、DNSルックアップ、TLS証明書、生のフローテレメトリなど、あらゆるイベントを個別のJSONレコードとして/var/log/suricata/eve.jsonに記録します。外部のSIEMを待つことなく、標準のコマンドラインツールを使って大量のログストリームを解析できます:

# 直近10,000件のエントリでトリガーされたアラートシグネチャの上位5件を集計
tail -n 10000 /var/log/suricata/eve.json | \
  jq -r 'select(.event_type=="alert") | .alert.signature' | \
  sort | uniq -c | sort -nr | head -n 5

高度な活用法

パッシブアラートは可視性を提供しますが、アクティブな脅威には自動化された防御措置が必要です。SuricataをNetfilterキュー(NFQ)と連携させることで、受動的な監視からインライン防御ファイアウォールへと進化させることができます。

NFQueueを用いたインラインIPSの設定

NFQモードでは、iptablesが一致するパケットをユーザー空間キューにルーティングします。Suricataはアクティブなルールに照らして各ペイロードを検査し、パケットを通過させるNF_ACCEPT、または破棄するNF_DROPの判定結果を返します。

まず、/etc/suricata/suricata.yamlでNFQブロックを確認または追加します:

nfq:
  mode: accept
  repeat-mark: 1
  repeat-mask: 1
  bypass-mark: 1
  bypass-mask: 1
  route-queue: 2

次に、iptablesを使用して受信またはルーティングされるトラフィックをキュー0に転送します:

# ルーティングされる転送トラフィックをNFQueue 0に転送
sudo iptables -I FORWARD -j NFQUEUE --queue-num 0 --queue-bypass

# またはWebポートへの着信サービストラフィックを直接検査
sudo iptables -I INPUT -p tcp -m multiport --dports 80,443 -j NFQUEUE --queue-num 0 --queue-bypass

--queue-bypassフラグは極めて重要です。Suricataが再起動したり、クラッシュしたり、メモリ枯渇で停止したりした場合でも、Linuxカーネルはキューをバイパスして通常どおりパケットを通過させます。このフラグを設定しないと、デーモンが停止した際にネットワーク全体が不通になってしまいます。

カスタムインラインドロップルールの作成

Suricataはプロトコル認識型のキーワードバッファを使用し、正規表現のオーバーヘッドを最小限に抑えながらHTTP、TLS、DNS、SSHのペイロードを検査します。カスタムシグネチャを/var/lib/suricata/rules/local.rulesに記述します:

# WordPressログインエンドポイントを標的とする自動スキャンをドロップ
drop http any any -> $HOME_NET any (
    msg:"セキュリティブロック - 不審なwp-login POST試行";
    flow:established,to_server;
    http.method; content:"POST";
    http.uri; content:"/wp-login.php";
    threshold:type threshold, track by_src, count 5, seconds 60;
    classtype:web-application-attack;
    sid:1000001;
    rev:1;
)

# 不審なダイナミックDNSホストを要求するTLSハンドシェイクをブロック
drop tls any any -> any any (
    msg:"セキュリティブロック - ブラックリスト登録されたDynamic DNS SNI";
    flow:established,to_server;
    tls.sni; content:"duckdns.org"; endswith; nocase;
    classtype:bad-unknown;
    sid:1000002;
    rev:1;
)

/etc/suricata/suricata.yamlのrule-filesリストにlocal.rulesを追加し、suricata -Tでルール構文をテストした上で、キューモードでSuricataを起動します:

sudo suricata -c /etc/suricata/suricata.yaml -q 0 -D

悪意のあるペイロードがルールに抵触すると、SuricataはNetfilterに通知してパケットを即座にドロップさせます。接続はリセットされ、Suricataはeve.jsonに"action":"blocked"としてインシデントを記録します。

実践的なTips

高速なパケット処理環境では、整った検証環境では決して遭遇しないエッジケースが表面化します。パケットロスをほぼゼロに抑え、ディスク容量の枯渇トラブルを防ぐための3つの本番向け堅牢化チューニングを紹介します。

1. NICのハードウェアオフロードの無効化

近年のネットワークカードは、Large Receive Offload(LRO)やGeneric Receive Offload(GRO)を使用して、カーネルに渡す前に受信フレームを最大64KBの疑似パケットにまとめます。この再構築によりパケットサイズが変わり、標準の1500バイトMTU境界に基づくシグネチャマッチングが機能しなくなる恐れがあります。

ethtoolを使用して、キャプチャ対象インターフェースのオフロード機能を無効化します:

sudo ethtool -K eth0 rx off tx off gro off lro off tso off gso off

再起動後もこの設定を維持するには、Netplan設定にethtoolフックを追加するか、専用のsystemdサービスを作成してください。

2. メモリとフロータイマーのチューニング

大規模なSYNフラッドや広範なネットワークスキャンが発生すると、Suricataのステートテーブルが孤立したハーフオープン接続で溢れかえる可能性があります。/etc/suricata/suricata.yamlでTCPステートタイマーを短縮し、停止したフローを積極的に破棄するように設定します:

flow-timeouts:
  tcp:
    new: 5
    established: 300
    closed: 0
    emergency-new: 1
    emergency-established: 60
    emergency-closed: 0

攻撃を受けている状況下では、緊急時用タイマー(emergencyタイマー)が数秒以内にメモリ使用圧力を削減し、OOM(Out of Memory)によるカーネルパニックを防止します。

3. ディスク枯渇を防ぐログローテーション

高トラフィックな10Gbpsリンクでは、毎日15GB〜40GBものeve.jsonテレメトリが生成されることがあります。ローテーションを設定しなければ、数日でルートディスクの空き容量を使い果たしてしまいます。/etc/logrotate.d/suricataに日次logrotateポリシーを設定し、圧縮とHUPシグナルによるファイル再オープンを定義します:

/var/log/suricata/*.json /var/log/suricata/*.log {
    daily
    rotate 7
    missingok
    compress
    delaycompress
    sharedscripts
    postrotate
        /bin/kill -HUP $(cat /var/run/suricata.pid 2>/dev/null) 2>/dev/null || true
    endscript
}

最初の2週間はSuricataをパッシブモードで稼働させることを推奨します。これにより、インターフェースの負荷を測定し、ノイズを特定してカスタムルールを調整する時間を確保できます。ベースラインが整ったら、トラフィックをNFQueue経由に切り替え、脅威がホストに到達する前にワイヤーレベルで遮断しましょう。

Share: