ファイル スキャン フレームワークのログを収集する
パーサーのバージョン: 3.0
このドキュメントでは、Google Cloud Storage V2 を使用して File Scanning Framework ログを Google Security Operations に取り込む方法について説明します。
File Scanning Framework(FSF)は、Emerson Electric Co. が開発したオープンソースのモジュール型再帰ファイル スキャン ソリューションです。FSF はクライアント サーバー アーキテクチャを使用してファイルを分析し、ファイル メタデータ、YARA シグネチャの一致、抽出されたサブオブジェクト、モジュール固有のメタデータなどの詳細な JSON スキャン結果を生成します。
始める前に
次の前提条件を満たしていることを確認します。
- Google SecOps インスタンス
- Cloud Storage API が有効になっている GCP プロジェクト
- GCS バケットを作成および管理する権限
- GCS バケットの IAM ポリシーを管理する権限
- ログ ディレクトリへの書き込みアクセス権を持つデプロイ済みの FSF サーバー インスタンス
- FSF サーバーホストへの root または sudo アクセス権
Google Cloud Storage バケットを作成する
- Google Cloud コンソールに移動します。
- プロジェクトを選択するか、新しいプロジェクトを作成します。
- ナビゲーション メニューで、[Cloud Storage > バケット] に移動します。
- [バケットを作成] をクリックします。
次の構成情報を提供してください。
設定 値 バケットに名前を付ける グローバルに一意の名前( fsf-logs-secopsなど)を入力します。ロケーション タイプ ニーズに応じて選択します(リージョン、デュアルリージョン、マルチリージョン)。 ロケーション ロケーションを選択します(例: us-central1)。ストレージ クラス Standard(アクセス頻度の高いログにおすすめ)。 アクセス制御 均一(推奨)。 保護ツール 省略可: オブジェクトのバージョニングまたは保持ポリシーを有効にします。 [作成] をクリックします。
FSF ログの出力ディレクトリを構成する
FSF は、構成可能なログ ディレクトリに JSON スキャン結果を書き込みます。Google SecOps の取り込み専用のディレクトリを構成します。
- SSH 経由で FSF サーバーホストに接続します。
FSF サーバー構成ファイルを開きます。
sudo nano /opt/fsf/fsf-server/conf/config.pySCANNER_CONFIG辞書を見つけます。LOG_PATHパラメータを専用ディレクトリに更新します。SCANNER_CONFIG = { 'LOG_PATH': '/var/log/fsf', 'YARA_PATH': '/opt/fsf/fsf-server/yara/rules.yara', 'PID_PATH': '/tmp/scanner.pid', 'EXPORT_PATH': '/tmp', 'TIMEOUT': 60, 'MAX_DEPTH': 10 }ファイルを保存して閉じます。
適切な権限でログ ディレクトリを作成します。
sudo mkdir -p /var/log/fsf sudo chown -R fsf:fsf /var/log/fsf sudo chmod 755 /var/log/fsfFSF サーバーを再起動して変更を適用します。
sudo systemctl restart fsfFSF が新しいディレクトリにログを書き込んでいることを確認します。
ls -lh /var/log/fsf/
Fluentd をインストールして構成する
Fluentd は FSF ログファイルを追跡し、Google Cloud Storage に送信します。
Fluentd をインストールする
FSF サーバーホストに Fluentd(td-agent)をインストールします。
curl -fsSL https://toolbelt.treasuredata.com/sh/install-ubuntu-jammy-td-agent4.sh | shGCS 出力プラグインをインストールします。
sudo td-agent-gem install fluent-plugin-gcsプラグインのインストールを確認します。
td-agent-gem list | grep fluent-plugin-gcs
Fluentd 用の GCP サービス アカウントを作成する
- GCP Console で、[IAM と管理>サービス アカウント] に移動します。
- [サービス アカウントを作成] をクリックします。
- 次の構成の詳細を指定します。
- サービス アカウント名: 「
fsf-fluentd-shipper」と入力します。 - サービス アカウントの説明: 「
Service account for Fluentd to ship FSF logs to GCS」と入力します。
- サービス アカウント名: 「
- [作成して続行] をクリックします。
- [このサービス アカウントにプロジェクトへのアクセスを許可する] セクションで、次の操作を行います。
- [ロールを選択] をクリックします。
- [ストレージ オブジェクト管理者] を検索して選択します。
- [続行] をクリックします。
- [完了] をクリックします。
サービス アカウントキーの作成
- [サービス アカウント] リストで、サービス アカウント(
fsf-fluentd-shipper)をクリックします。 - [キー] タブに移動します。
- [鍵を追加] > [新しい鍵を作成] の順にクリックします。
- キーのタイプとして [JSON] を選択します。
- [作成] をクリックします。
- JSON キーファイルがパソコンにダウンロードされます。
鍵ファイルを FSF サーバーホストに転送します。
scp /path/to/downloaded-key.json user@fsf-server:/etc/td-agent/gcp-key.json鍵ファイルに適切な権限を設定します。
sudo chown td-agent:td-agent /etc/td-agent/gcp-key.json sudo chmod 600 /etc/td-agent/gcp-key.json
GCS バケットに対する IAM 権限を付与する
- [Cloud Storage] > [バケット] に移動します。
- バケット名(
fsf-logs-secops)をクリックします。 - [権限] タブに移動します。
- [アクセス権を付与] をクリックします。
- 次の構成の詳細を指定します。
- プリンシパルを追加: サービス アカウントのメールアドレス(例:
fsf-fluentd-shipper@PROJECT_ID.iam.gserviceaccount.com)を入力します。 - ロールを割り当てる: [ストレージ オブジェクト管理者] を選択します。
- プリンシパルを追加: サービス アカウントのメールアドレス(例:
- [保存] をクリックします。
Fluentd を構成する
FSF サーバーホストで、Fluentd 構成ファイルを作成します。
sudo nano /etc/td-agent/td-agent.conf次の構成を追加します。
# Tail FSF JSON logs <source> @type tail path /var/log/fsf/*.log pos_file /var/log/td-agent/fsf.log.pos tag fsf.scan read_from_head true <parse> @type json time_key timestamp time_format %Y-%m-%dT%H:%M:%S.%L%z </parse> </source> # Ship to Google Cloud Storage <match fsf.scan> @type gcs project YOUR_GCP_PROJECT_ID keyfile /etc/td-agent/gcp-key.json bucket fsf-logs-secops object_key_format %{path}%{time_slice}_%{index}.%{file_extension} path fsf-logs/ <buffer tag,time> @type file path /var/log/td-agent/buffer/gcs timekey 3600 timekey_wait 10m timekey_use_utc true chunk_limit_size 10MB </buffer> <format> @type json </format> store_as json auto_create_bucket false </match>YOUR_GCP_PROJECT_IDは実際の GCP プロジェクト ID に置き換えます。ファイルを保存して閉じます。
バッファ ディレクトリを作成します。
sudo mkdir -p /var/log/td-agent/buffer/gcs sudo chown -R td-agent:td-agent /var/log/td-agent/bufferFluentd を再起動して構成を適用します。
sudo systemctl restart td-agent起動時に Fluentd を起動できるようにします。
sudo systemctl enable td-agentFluentd が実行されていることを確認します。
sudo systemctl status td-agent
ログ転送を確認する
Fluentd ログでエラーを確認します。
sudo tail -f /var/log/td-agent/td-agent.logテスト FSF スキャンをトリガーしてログを生成します。
echo "test content" > /tmp/test.txt /opt/fsf/fsf-client/fsf_client.py /tmp/test.txt --suppress-reportFluentd がログを処理して送信するまで 1 ~ 2 分待ちます。
GCP Console で、[Cloud Storage] > [バケット] に移動します。
バケット名(
fsf-logs-secops)をクリックします。fsf-logs/接頭辞に移動します。タイムスタンプ付きの JSON ファイルが作成されていることを確認します。
ファイルをダウンロードして検査し、FSF スキャン結果が JSON 形式で含まれていることを確認します。
Google SecOps サービス アカウントを取得する
Google SecOps は、一意のサービス アカウントを使用して GCS バケットからデータを読み取ります。このサービス アカウントにバケットへのアクセス権を付与する必要があります。
サービス アカウントのメールアドレスを取得する
- [SIEM 設定] > [フィード] に移動します。
- [Add New Feed] をクリックします。
- [単一フィードを設定] をクリックします。
- [フィード名] フィールドに、フィードの名前を入力します(例:
FSF File Scanning Logs)。 - [ソースタイプ] として [Google Cloud Storage V2] を選択します。
- [ログタイプ] として [ファイル スキャン フレームワーク] を選択します。
[サービス アカウントを取得する] をクリックします。一意のサービス アカウントのメールアドレスが表示されます(例:)。
secops-12345678@secops-gcp-prod.iam.gserviceaccount.com次のステップで使用するメールアドレスをコピーします。
[次へ] をクリックします。
次の入力パラメータの値を指定します。
ストレージ バケットの URL: 接頭辞パスを含む GCS バケット URI を入力します。
gs://fsf-logs-secops/fsf-logs/Source deletion option: 必要に応じて削除オプションを選択します。
- なし: 転送後にファイルを削除しません(テストにおすすめ)。
- 転送されたファイルを削除する: 転送が完了した後にファイルを削除します。
転送されたファイルと空のディレクトリを削除する: 転送が完了した後にファイルと空のディレクトリを削除します。
ファイルの最大経過日数: 指定した日数以内に変更されたファイルを含めます(デフォルトは 180 日)。
アセットの名前空間: アセットの名前空間。
Ingestion labels: このフィードのイベントに適用されるラベル。
[次へ] をクリックします。
[Finalize] 画面で新しいフィードの設定を確認し、[送信] をクリックします。
Google SecOps サービス アカウントに IAM 権限を付与する
Google SecOps サービス アカウントには、GCS バケットに対する Storage オブジェクト閲覧者ロールが必要です。
- [Cloud Storage] > [バケット] に移動します。
- バケット名(
fsf-logs-secops)をクリックします。 - [権限] タブに移動します。
- [アクセス権を付与] をクリックします。
- 次の構成の詳細を指定します。
- プリンシパルを追加: Google SecOps サービス アカウントのメールアドレスを貼り付けます。
- ロールを割り当てる: [Storage オブジェクト閲覧者] を選択します。
- [保存] をクリックします。
取り込みを確認する
- 最初の取り込みが完了するまで 10 ~ 15 分待ちます。
- Google SecOps で、[SIEM 設定] > [フィード] に移動します。
- フィードを見つけます(
FSF File Scanning Logs)。 - [ステータス] が [アクティブ] と表示されていることを確認します。
- フィード名をクリックして、取り込み指標を表示します。
- [取り込まれたイベント] の数が増加していることを確認します。
- Google SecOps の [検索] に移動します。
検索クエリを実行して、FSF ログが取り込まれていることを確認します。
metadata.log_type = "FILE_SCANNING_FRAMEWORK"FSF スキャン結果が検索結果に表示されることを確認します。
トラブルシューティング
GCS にログが表示されない
FSF が
/var/log/fsf/にログを書き込んでいることを確認します。ls -lh /var/log/fsf/ tail -f /var/log/fsf/*.logFluentd ログでエラーを確認します。
sudo tail -f /var/log/td-agent/td-agent.logGCP サービス アカウント キーが有効で、正しい権限が付与されていることを確認します。
Fluentd 構成のバケット名が実際のバケット名と一致していることを確認します。
Fluentd の権限エラー
- サービス アカウント(
fsf-fluentd-shipper)にバケットに対するストレージ オブジェクト管理者ロールがあることを確認します。 - Fluentd 構成の鍵パスが正しいことを確認します。
キーファイルに適切な所有者と権限があることを確認します。
ls -l /etc/td-agent/gcp-key.json
Google SecOps でログが取り込まれない
- Google SecOps サービス アカウントにバケットに対する Storage オブジェクト閲覧者ロールがあることを確認します。
- フィード構成のバケット URI が正しく、末尾のスラッシュが含まれていることを確認します。
- 指定された接頭辞パスの GCS バケットにファイルが存在することを確認します。
- [SIEM 設定] > [フィード] でフィードのステータスを確認し、エラー メッセージがないか確認します。
FSF ログが想定される形式になっていない
- FSF が JSON 出力を書き込むように構成されていることを確認します(デフォルトの動作)。
- Fluentd の
<parse>セクションが@type jsonで構成されていることを確認します。 ログファイルを検査して、有効な JSON が含まれていることを確認します。
head -n 1 /var/log/fsf/*.log | jq .
UDM マッピング テーブル
| ログフィールド | UDM マッピング | ロジック |
|---|---|---|
| CompressType_label、compressed_parents | about.labels | CompressType_label(キー「Compress Type」、メッセージに「Compress Type」が含まれている場合は Object.EXTRACT_ZIP.Object_0.Compress Type の値)と compressed_parents(キー「Compressed Parent Files」、Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.additional_info.compressed_parents から連結)からマージ |
| Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.MD5、Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.MD5、Object.EXTRACT_SWF.META_BASIC_INFO.MD5、Object.EXTRACT_GZIP.META_BASIC_INFO.MD5、Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.MD5 | intermediary.file.md5 | EXTRACT_EMBEDDED が存在する場合は Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.MD5 の値、EXTRACT_ZIP が存在する場合は Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.MD5 の値、EXTRACT_SWF が存在する場合は Object.EXTRACT_SWF.META_BASIC_INFO.MD5 の値、EXTRACT_GZIP が存在する場合は Object.EXTRACT_GZIP.META_BASIC_INFO.MD5 の値、それ以外の場合は Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.MD5 |
| Object.EXTRACT_EMBEDDED.Object_0.Description | intermediary.file.mime_type | 値を直接コピー |
| Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.SHA1、Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.SHA1、Object.EXTRACT_SWF.META_BASIC_INFO.SHA1、Object.EXTRACT_GZIP.META_BASIC_INFO.SHA1、Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.SHA1 | intermediary.file.sha1 | EXTRACT_EMBEDDED が存在する場合は Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.SHA1 の値、EXTRACT_ZIP が存在する場合は Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.SHA1 の値、EXTRACT_SWF が存在する場合は Object.EXTRACT_SWF.META_BASIC_INFO.SHA1 の値、EXTRACT_GZIP が存在する場合は Object.EXTRACT_GZIP.META_BASIC_INFO.SHA1 の値、それ以外の場合は Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.SHA1 の値 |
| Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.SHA256、Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.SHA256、Object.EXTRACT_SWF.META_BASIC_INFO.SHA256、Object.EXTRACT_GZIP.META_BASIC_INFO.SHA256、Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.SHA256 | intermediary.file.sha256 | EXTRACT_EMBEDDED が存在する場合は Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.SHA256 の値、EXTRACT_ZIP が存在する場合は Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.SHA256 の値、EXTRACT_SWF が存在する場合は Object.EXTRACT_SWF.META_BASIC_INFO.SHA256 の値、EXTRACT_GZIP が存在する場合は Object.EXTRACT_GZIP.META_BASIC_INFO.SHA256 の値、それ以外の場合は Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.SHA256 の値 |
| Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.Size、Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.Size、Object.EXTRACT_SWF.META_BASIC_INFO.Size、Object.EXTRACT_GZIP.META_BASIC_INFO.Size、Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.Size | intermediary.file.size | EXTRACT_EMBEDDED が存在する場合は Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.Size の値、EXTRACT_ZIP が存在する場合は Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.Size の値、EXTRACT_SWF が存在する場合は Object.EXTRACT_SWF.META_BASIC_INFO.Size の値、EXTRACT_GZIP が存在する場合は Object.EXTRACT_GZIP.META_BASIC_INFO.Size の値、それ以外の場合は Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.Size。末尾の「 .*」が削除され、uinteger に変換されます。 |
| Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.scan_id | intermediary.resource.id | 値を直接コピー |
| Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.permalink | intermediary.url | 値を直接コピー |
| Object.META_EMERSON_INFO.results | intermediary.user.email_addresses | 結果配列の matched_email からマージされました |
| Summary.Observations | metadata.description | 配列から連結され、「, 」区切り文字が使用され、先頭のカンマが削除されました |
| スキャン時刻 | metadata.event_timestamp | yyyy-MM-dd HH:mm:ss 形式の日付フィルタを使用して変換 |
| ソース | metadata.event_type | Source が空でない場合は「SCAN_FILE」、それ以外の場合は「GENERIC_EVENT」に設定します。 |
| Object.META_VT_CACHE._id | metadata.product_log_id | 値を直接コピー |
| result.ad_data.message | network.http.response_code | grok パターン INT を使用して、result.ad_data.message から整数として抽出されます |
| ソース | principal.hostname | 値を直接コピー |
| Object.META_EMERSON_INFO.result_summary、Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.verbose_msg | security_result.summary | 存在する場合は Object.META_EMERSON_INFO.result_summary に設定し、存在しない場合は Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.verbose_msg に設定します。 |
| ファイル名 | target.file.full_path | 値を直接コピー |
| Object.META_BASIC_INFO.MD5 | target.file.md5 | 値を直接コピー |
| Summary.Yara | target.file.mime_type | Summary.Yara の最初のインデックスから抽出され、大文字に変換されます。Yara が存在する場合は「FT_」が削除されます。それ以外の場合は、EXTRACT_ZIP が存在する場合は「ZIP」、EXTRACT_SWF が存在する場合は「SWF」、EXTRACT_GZIP が存在する場合は「GZIP」、EXTRACT_CAB が存在する場合は「CAB」に設定されます。 |
| Object.META_BASIC_INFO.SHA1、Object.META_VT_CACHE.SHA1 | target.file.sha1 | Object.META_BASIC_INFO.SHA1 が空でない場合はその値、それ以外の場合は Object.META_VT_CACHE.SHA1 |
| Object.META_BASIC_INFO.SHA256 | target.file.sha256 | 値を直接コピー |
| Object.META_BASIC_INFO.Size | target.file.size | 末尾の「.*」が削除され、uinteger に変換されます |
| metadata.vendor_name | 「EMERSON」に設定 | |
| metadata.product_name | 「FILE SCANNING FRAMEWORK」に設定 |
さらにサポートが必要な場合 コミュニティ メンバーや Google SecOps のプロフェッショナルから回答を得ることができます。