【実務・中級編】 ノードレベルのログ収集とSIEMへの転送(Fluentd/Vector) – インフラ・ネットワーク & クラウドセキュリティ防御ガイド

「ログは出しているが、誰も見ていない」を卒業する。侵害の予兆を掴むログパイプラインの実践的設計

インシデント対応の現場で最も絶望するのは、「攻撃が完了してからログを解析する」ことだ。攻撃者は痕跡を消す。ログがローカルにしか存在しなければ、侵害された瞬間にそのログ自体が改ざん、あるいは削除される。

SIEM(Security Information and Event Management)への転送は、単なるコンプライアンス対応ではない。「敵が侵入した瞬間に、その足跡を外部の安全な領域へ避難させる」という、究極の防衛線だ。今回は、私が現場で徹底している「ログの生存戦略」と、Vectorを用いた堅牢なパイプライン構築について伝授する。

—

攻撃者は「ノードの隙間」を縫う

攻撃者は、OSの脆弱性(CVE)やWebアプリのインジェクションを足がかりに、まずは「権限昇格」を狙う。その後、彼らはrm -rf /var/log/*を打つ前に、まずシェル履歴を隠滅する。

もし君たちが、ログを収集するだけで「転送」の仕組みを疎かにしていれば、攻撃者が特権を得た瞬間に、君たちの監視網は無力化する。SIEMへのリアルタイム転送がなぜ重要か? それは、攻撃者が自身の痕跡を消すよりも速く、異常のシグナルを別の場所へ退避させるためだ。

—

Vectorによる「倒れない」ログ収集パイプライン

Fluentdも良いが、Go言語で書かれ、メモリ効率と堅牢性に優れた Vector を私は推奨する。特にコンテナ環境では、サイドカーパターンでVectorを動かし、OSログとアプリログを分離してSIEMへ流し込むのが定石だ。

1. Vectorによるログ転送設定 (vector.toml)

ただログを垂れ流すのではなく、転送前に「機密情報のマスク」と「構造化」を行う。これができていないログは、SIEM側での相関分析を困難にするノイズでしかない。

# ログソース:syslogとDockerコンテナログを同時監視
[sources.os_logs]
type = "file"
include = ["/var/log/auth.log", "/var/log/syslog"]

[sources.app_logs]
type = "docker_logs"

# 変換:機密情報のマスク(正規表現でメールアドレスやクレカ番号を伏せる)
[transforms.mask_sensitive_data]
type = "remap"
inputs = ["app_logs"]
source = '''
.message = replace!(.message, r"(\d{4}-){3}\d{4}", "****-****-****-****")
'''

# 出力:SIEM(ここではDatadogやElasticsearchを想定)へ転送
[sinks.siem_backend]
type = "elasticsearch"
inputs = ["mask_sensitive_data", "os_logs"]
endpoints = ["https://your-siem-endpoint:9200"]
# ネットワーク切断時に備え、メモリバッファを持たせる
[sinks.siem_backend.buffer]
type = "memory"
max_events = 500

—

防御の要:SIEMで検知すべき「3つの異常」

ログを転送しただけで満足してはいけない。SIEM側で以下のルールを実装せよ。特に、WebアプリのログとOSの認証ログを「相関」させるのがコツだ。

1. 異常な認証試行: auth.log における特定のIPからの「Failed password」が1分間に5回以上発生した場合。
2. Web攻撃の成功: Nginxのログで 404 や 403 が連続した直後に、200 応答かつレスポンスサイズが異常に大きい(データ持ち出しの予兆)場合。
3. 権限昇格の予兆: sudo の使用ログが、普段の業務時間外や、特定のセッションID以外から発生した場合。

—

実践:PHPアプリでのログ出力の作法

アプリ開発者が error_log() を適当に書くと、インフラ側のログ収集が破綻する。必ずJSON形式で出力し、コンテキストを持たせるルールを徹底させること。

<?php
/**
 * セキュアなログ出力サンプル
 * 攻撃者がユーザー入力値をログに紛れ込ませる「Log Injection」を防ぐために、
 * 入力値の改行コードを除去し、JSONで構造化する。
 */
function secure_logger($level, $message, $context = []) {
    $log_entry = [
        'timestamp' => date('Y-m-d H:i:s'),
        'level'     => $level,
        'message'   => str_replace(["\r", "\n"], '', $message), // CRLFインジェクション対策
        'user_id'   => $_SESSION['user_id'] ?? 'anonymous',
        'ip'        => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
        'context'   => $context
    ];
    
    // JSONとして出力することで、Vector側でのパースが容易になる
    error_log(json_encode($log_entry));
}

// 使用例
secure_logger('WARNING', 'ログイン失敗', ['username' => $_POST['username']]);

—

最後に:エンジニアへの提言

セキュリティは「設定して終わり」の静的なものではない。攻撃手法は日々進化する。君たちが構築したログパイプラインも、いつか攻撃者にその存在を認識され、ログの「送信元」を偽装されたり、ログ送信自体をブロックするような攻撃を受けるかもしれない。

「ログは絶対に改ざんされ、削除される」という性悪説に立ち、SIEM側での「ログ受信の欠落検知(Heartbeat監視)」までセットで構築して初めて、君たちのシステムは「戦える」状態になる。

現場の泥臭い戦いにおいて、最後に自分を守るのは「ログの分析能力」と「異常を即座に感知する直感」だ。まずは今日、手元のサーバーの /var/log/auth.log が正しく中央集権的な場所に転送されているか、その確認から始めてほしい。

コメント

タイトルとURLをコピーしました