ESET Threat Intelligence のログを収集する
このドキュメントでは、Google Cloud Storage V2、Cloud Run 関数、Cloud Scheduler を使用して ESET Threat Intelligence ログを Google Security Operations に取り込む方法について説明します。
ESET Threat Intelligence(ETI)は、既存の脅威や新たな脅威に関する根拠に基づく情報と実践的なアドバイスを提供します。ETI サービスは、組織や顧客に脅威をもたらす可能性のある悪意のあるソフトウェアやアクティビティについて警告します。このサービスは、APT IoC、ボットネット C&C とターゲット、悪意のあるドメイン、IP、URL、ファイル、フィッシング URL、ランサムウェア、Android の脅威など、STIX 2.1 形式の TAXII 2.1 フィードを介して脅威インテリジェンス データを提供します。
始める前に
次の前提条件を満たしていることを確認してください。
- Google SecOps インスタンス
- 次の API が有効になっている Google Cloud プロジェクト。
- Cloud Storage API
- Cloud Run functions API
- Cloud Scheduler API
- Cloud Pub/Sub API
- Google Cloud Storage バケット、Cloud Run 関数、Pub/Sub トピック、Cloud Scheduler ジョブを作成して管理する権限
- Google Cloud Storage バケットの IAM ポリシーを管理する権限
- 有効な ESET Threat Intelligence サブスクリプション
- https://eti.eset.com の ESET Threat Intelligence ポータルへのアクセス
Google Cloud Storage バケットを作成する
- Google Cloud コンソールに移動します。
- プロジェクトを選択するか、新しいプロジェクトを作成します。
- ナビゲーション メニューで、[Cloud Storage > バケット] に移動します。
- [バケットを作成] をクリックします。
次の構成情報を提供してください。
設定 値 バケットに名前を付ける グローバルに一意の名前( eset-ti-logsなど)を入力します。ロケーション タイプ ニーズに基づいて選択します(リージョン、デュアルリージョン、マルチリージョン)。 ロケーション ロケーションを選択します(例: us-central1)。ストレージ クラス Standard(アクセス頻度の高いログにおすすめ) アクセス制御 均一(推奨) 保護ツール 省略可: オブジェクトのバージョニングまたは保持ポリシーを有効にする [作成] をクリックします。
ESET Threat Intelligence TAXII 認証情報を収集する
Cloud Run 関数が脅威インテリジェンス データを取得できるようにするには、ETI ポータルから TAXII フィードを有効にして TAXII 認証情報を生成する必要があります。
TAXII フィードを有効にする
- https://eti.eset.com で ESET Threat Intelligence ポータルにログインします。
- メインメニューの [データフィード] に移動します。
- 有効にするデータフィードの横にあるその他アイコンをクリックします。
- [フィードを有効にする] を選択します。
Google SecOps に取り込むフィードごとに手順 3 ~ 4 を繰り返します。
TAXII 認証情報を生成する
- ESET Threat Intelligence ポータルで、[Admin Settings > Access Credentials] に移動します。
- [Generate TAXII Credentials] をクリックします。
表示されたダイアログで、次の値をコピーして保存します。
- ユーザー名: TAXII ユーザー名
- パスワード: TAXII のパスワード
TAXII フィードの詳細を記録する
フィードを有効にして認証情報を生成したら、取り込む各フィードについて次の情報を記録します。
- ESET Threat Intelligence ポータルで、[データフィード] に移動します。
- 有効なフィードの横にあるその他アイコンをクリックします。
- [Show Data Feed detail](データフィードの詳細を表示)を選択します。
サイドパネルで、次の値をメモします。
- TAXII フィード名: フィード識別子(例:
botnet stix 2.1) - TAXII 2 ID: コレクション ID(例:
0abb06690b0b47e49cd7794396b76b20) - TAXII 2 フィードの URL: コレクションの完全な URL
- TAXII フィード名: フィード識別子(例:
利用可能な TAXII フィード
ESET Threat Intelligence は、次の TAXII 2.1 フィードを提供します。
フィード名 TAXII フィード名 コレクション ID Android infostealer フィード androidinfostealer stix 2.1 9ee501cde0c44d6db4ae995fead1a7c8 Android の脅威フィード androidthreats stix 2.1 daf3de8fab144552a1cb5af054ed07ee APT IoC apt stix 2.1 97e3eb74ae5f46dd9e22f677a6938ee7 ボットネット フィード botnet stix 2.1 0abb06690b0b47e49cd7794396b76b20 ボットネット - C&C botnet.cc stix 2.1 d1923a526e8f400dbb301259240ee3d5 ボットネット - ターゲット botnet.target stix 2.1 61b6e4f9153e411ca7a9982a2c6ae788 Cryptoscam フィード cryptoscam stix 2.1 2c183ce9551a43338c6cc2ed7c2a704d ドメイン フィード domain stix 2.1 a34aa0a4f9de419582a883863503f9c4 eCrime IoC フィード ecrime stix 2.1 08059376eac84ec4a076cfd682493f91 IP フィード ip stix 2.1 baaed2a92335418aa753fe944e13c23a メールの悪意のある添付ファイル emailattachments stix 2.1 c0d56cf7f81d482eb97fd46beaa4bae0 悪意のあるファイルのフィード file stix 2.1 ee6a153ed77e4ec3ab21e76cc2074b9f フィッシング URL フィード phishingurl stix 2.1 d0a6c0f962dd4dd2b3eeb96b18612584 PUA アドウェア ファイル フィード puaadware stix 2.1 d1bfc81202fc4c6599326771ec2da41d PUA の両用アプリ ファイル フィード puadualapps stix 2.1 970a7d0039ac4668addf058cd9feb953 ランサムウェア フィード ランサムウェア stix 2.1 8d3490d688ce4a989aee9af5c680d8bf 詐欺 URL フィード scamurl stix 2.1 2130adc3c67c43f9a3664b187931375e スミッシング フィード smishing stix 2.1 330ad7d0c736476babe5e49077b96c95 SMS 詐欺フィード smsscam stix 2.1 6e20217a2e1246b8ab11be29f759f716 URL フィード url stix 2.1 1d3208c143be49da8130f5a66fd3a0fa
Cloud Run functions のサービス アカウントを作成する
- Google Cloud コンソールで、[IAM と管理] > [サービス アカウント] に移動します。
- [サービス アカウントを作成] をクリックします。
次の構成情報を提供してください。
- サービス アカウント名: 「
eset-ti-collector」と入力します。 - サービス アカウントの説明:
Service account for ESET Threat Intelligence Cloud Run function to write STIX objects to GCSと入力します。
- サービス アカウント名: 「
[作成して続行] をクリックします。
[このサービス アカウントにプロジェクトへのアクセスを許可する] セクションで、次のロールを追加します。
- [ロールを選択] をクリックし、[ストレージ オブジェクト管理者] を検索して選択します。
- [別のロールを追加] をクリックし、[Cloud Run 起動元] を検索して選択します。
[続行] をクリックします。
[完了] をクリックします。
Google Cloud Storage バケットに対する IAM 権限を付与する
- [Cloud Storage] > [バケット] に移動します。
- バケット名(例:
eset-ti-logs)をクリックします。 - [権限] タブに移動します。
- [アクセス権を付与] をクリックします。
次の構成情報を提供してください。
- プリンシパルを追加: サービス アカウントのメールアドレス(例:
eset-ti-collector@PROJECT_ID.iam.gserviceaccount.com)を入力します。 - ロールを割り当てる: [ストレージ オブジェクト管理者] を選択します。
- プリンシパルを追加: サービス アカウントのメールアドレス(例:
[保存] をクリックします。
Pub/Sub トピックの作成
Cloud Scheduler によってメッセージがパブリッシュされると、Pub/Sub トピックが Cloud Run functions の関数をトリガーします。
- Google Cloud コンソールで、[Pub/Sub>トピック] に移動します。
- [トピックを作成] をクリックします。
- 次の構成の詳細を指定します。
- トピック ID: 「
eset-ti-trigger」と入力します。 - デフォルトのサブスクリプションを追加する: 選択したままにする
- トピック ID: 「
- [作成] をクリックします。
Cloud Run functions を作成する
- Google Cloud コンソールで、[Cloud Run functions] に移動します。
- [関数を作成] をクリックします。
次の構成情報を提供してください。
設定 値 環境 第 2 世代 関数名 eset-ti-collectorリージョン GCS バケットと同じリージョンを選択します。 トリガーのタイプ Cloud Pub/Sub Pub/Sub トピック eset-ti-trigger割り当てられたメモリ 512 MiB タイムアウト 540 秒 ランタイム サービス アカウント eset-ti-collector[次へ] をクリックします。
[ランタイム] を [Python 3.12] に設定します。
[エントリ ポイント] を
mainに設定します。requirements.txtファイルに次の依存関係を追加します。functions-framework==3.* google-cloud-storage==2.* urllib3==2.*main.pyファイルに次のコードを貼り付けます。import functions_framework import json import os import logging import time import urllib3 from datetime import datetime, timedelta, timezone from google.cloud import storage logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) HTTP = urllib3.PoolManager(retries=False) storage_client = storage.Client() API_ROOT = "https://taxii.eset.com/taxii2/643f4eb5-f8b7-46a3-a606-6d61d5ce223a" TAXII_CONTENT_TYPE = "application/taxii+json;version=2.1" def _load_state(bucket_name: str, state_key: str, lookback_hours: int) -> str: """Return ISO8601 checkpoint (UTC).""" try: bucket = storage_client.bucket(bucket_name) blob = bucket.blob(state_key) if blob.exists(): state_data = blob.download_as_text() state = json.loads(state_data) ts = state.get("last_poll_time") if ts: logger.info(f"Loaded state: {ts}") return ts except Exception as e: logger.warning(f"State read error: {e}") default_ts = ( datetime.now(timezone.utc) - timedelta(hours=lookback_hours) ).strftime("%Y-%m-%dT%H:%M:%S.000Z") logger.info(f"No previous state found, using lookback: {default_ts}") return default_ts def _save_state(bucket_name: str, state_key: str, ts: str) -> None: """Persist the checkpoint to GCS.""" bucket = storage_client.bucket(bucket_name) blob = bucket.blob(state_key) blob.upload_from_string( json.dumps({"last_poll_time": ts}), content_type="application/json", ) logger.info(f"Saved state: {ts}") def _fetch_objects( username: str, password: str, collection_id: str, added_after: str, max_records: int, ) -> list: """Query TAXII 2.1 collection objects with pagination.""" url = f"{API_ROOT}/collections/{collection_id}/objects/" headers = urllib3.make_headers(basic_auth=f"{username}:{password}") headers["Accept"] = TAXII_CONTENT_TYPE headers["User-Agent"] = "Chronicle-ESET-TI-GCS/1.0" all_objects = [] params = {"added_after": added_after} while True: qs = "&".join(f"{k}={v}" for k, v in params.items()) request_url = f"{url}?{qs}" if qs else url for attempt in range(3): try: resp = HTTP.request("GET", request_url, headers=headers) break except Exception as e: wait = 2 ** (attempt + 1) logger.warning(f"Request error: {e}, retrying in {wait}s") time.sleep(wait) else: raise RuntimeError("Exceeded retry budget for TAXII API") if resp.status == 401: raise RuntimeError("Authentication failed: check TAXII credentials") if resp.status == 404: raise RuntimeError( f"Collection not found: {collection_id}" ) if resp.status not in (200, 206): raise RuntimeError( f"TAXII API error {resp.status}: {resp.data[:500]}" ) body = json.loads(resp.data.decode("utf-8")) objects = body.get("objects", []) all_objects.extend(objects) logger.info( f"Fetched {len(objects)} objects (total: {len(all_objects)})" ) if len(all_objects) >= max_records: logger.info(f"Reached max_records limit: {max_records}") all_objects = all_objects[:max_records] break more = body.get("more", False) next_param = body.get("next") if more and next_param: params = {"added_after": added_after, "next": next_param} else: break return all_objects @functions_framework.cloud_event def main(cloud_event): """Cloud Run function entry point triggered by Pub/Sub.""" bucket_name = os.environ["GCS_BUCKET"] prefix = os.environ.get("GCS_PREFIX", "eset-ti") state_key = os.environ.get("STATE_KEY", "eset-ti/state.json") username = os.environ["TAXII_USERNAME"] password = os.environ["TAXII_PASSWORD"] collection_id = os.environ["COLLECTION_ID"] max_records = int(os.environ.get("MAX_RECORDS", "10000")) lookback_hours = int(os.environ.get("LOOKBACK_HOURS", "48")) try: last_poll = _load_state(bucket_name, state_key, lookback_hours) objects = _fetch_objects( username, password, collection_id, last_poll, max_records ) if not objects: logger.info("No new STIX objects found") return "No new objects", 200 now_str = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S") blob_path = ( f"{prefix}/eset_ti_{collection_id}_{now_str}.json" ) ndjson_body = "\n".join( json.dumps(obj, separators=(",", ":")) for obj in objects ) bucket = storage_client.bucket(bucket_name) blob = bucket.blob(blob_path) blob.upload_from_string( ndjson_body, content_type="application/x-ndjson" ) new_poll_time = datetime.now(timezone.utc).strftime( "%Y-%m-%dT%H:%M:%S.000Z" ) _save_state(bucket_name, state_key, new_poll_time) msg = ( f"Wrote {len(objects)} STIX objects to " f"gs://{bucket_name}/{blob_path}" ) logger.info(msg) return msg, 200 except Exception as e: logger.error(f"Error collecting ESET TI: {e}") raise[デプロイ] をクリックします。
関数がデプロイされるまで待ちます。デプロイが完了すると、ステータスが緑色のチェックマークに変わります。
環境変数を構成する
- 関数がデプロイされたら、[Cloud Run functions] > [eset-ti-collector] に移動します。
- [新しいリビジョンの編集とデプロイ] をクリックします。
- [変数とシークレット] タブをクリックします(または、第 1 世代の場合は [ランタイム、ビルド、接続、セキュリティの設定] を開きます)。
次の環境変数を追加します。
キー 値の例 GCS_BUCKETeset-ti-logsGCS_PREFIXeset-tiSTATE_KEYeset-ti/state.jsonTAXII_USERNAMEETI ポータルの TAXII ユーザー名 TAXII_PASSWORDETI ポータルから取得した TAXII パスワード COLLECTION_ID0abb06690b0b47e49cd7794396b76b20MAX_RECORDS10000LOOKBACK_HOURS48[デプロイ] をクリックします。
Cloud Scheduler ジョブの作成
Cloud Scheduler は、スケジュールに従って Pub/Sub トピックにメッセージをパブリッシュし、Cloud Run functions をトリガーして ESET Threat Intelligence の新しい STIX オブジェクトをポーリングします。
- Google Cloud コンソールで、[Cloud Scheduler] に移動します。
- [ジョブを作成] をクリックします。
次の構成情報を提供してください。
設定 値 名前 eset-ti-pollリージョン 関数と同じリージョンを選択します。 周波数 0 */1 * * *(1 時間ごと)タイムゾーン タイムゾーンを選択します(例: UTC)[続行] をクリックします。
[実行を構成する] セクションで、次の操作を行います。
- ターゲット タイプ: [Pub/Sub] を選択します。
- トピック:
eset-ti-triggerを選択します。 - メッセージ本文: 「
{"poll": true}」と入力します。
[作成] をクリックします。
Cloud Run functions の関数を確認する
- Cloud Scheduler で、
eset-ti-pollジョブを見つけます。 - [強制実行] をクリックして、すぐに実行するようにトリガーします。
- [Cloud Run functions] > [eset-ti-collector] > [ログ] に移動します。
次のようなログエントリを確認して、関数が正常に実行されたことを確認します。
Fetched 250 objects (total: 250) Wrote 250 STIX objects to gs://eset-ti-logs/eset-ti/eset_ti_0abb06690b0b47e49cd7794396b76b20_20250115_103000.json[Cloud Storage] > [バケット] > [eset-ti-logs] に移動します。
eset-ti/接頭辞に移動します。NDJSON ファイルが STIX オブジェクトで作成されていることを確認します。
Google SecOps サービス アカウントを取得してフィードを構成する
Google SecOps は、一意のサービス アカウントを使用して GCS バケットからデータを読み取ります。このサービス アカウントにバケットへのアクセス権を付与する必要があります。
サービス アカウントのメールアドレスを取得する
- [SIEM 設定] > [フィード] に移動します。
- [Add New Feed] をクリックします。
- [単一フィードを設定] をクリックします。
- [フィード名] フィールドに、フィードの名前を入力します(例:
ESET Threat Intelligence - Botnet)。 - [ソースタイプ] として [Google Cloud Storage V2] を選択します。
- [ログタイプ] として [ESET Threat Intelligence] を選択します。
[サービス アカウントを取得する] をクリックします。一意のサービス アカウント メールアドレスが表示されます(例:)。
chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.comこのメールアドレスをコピーして、次のステップで使用します。
[次へ] をクリックします。
次の入力パラメータの値を指定します。
ストレージ バケットの URL: 接頭辞パスを含む GCS バケット URI を入力します。
gs://eset-ti-logs/eset-ti/Source deletion option: 必要に応じて削除オプションを選択します。
- なし: 転送後にファイルを削除しません(テストにおすすめ)。
- 転送されたファイルを削除する: 転送が完了した後にファイルを削除します。
転送されたファイルと空のディレクトリを削除する: 転送が完了した後にファイルと空のディレクトリを削除します。
ファイルの最大経過日数: 指定した日数以内に変更されたファイルを含めます(デフォルトは 180 日)。
アセットの名前空間: アセットの名前空間
Ingestion labels: このフィードのイベントに適用されるラベル(
ESET_IOCなど)
[次へ] をクリックします。
[Finalize] 画面で新しいフィードの設定を確認し、[送信] をクリックします。
Google SecOps サービス アカウントに IAM 権限を付与する
Google SecOps サービス アカウントには、Google Cloud Storage バケットに対するストレージ オブジェクト閲覧者ロールが必要です。
- [Cloud Storage] > [バケット] に移動します。
- バケット名(例:
eset-ti-logs)をクリックします。 - [権限] タブに移動します。
- [アクセス権を付与] をクリックします。
- 次の構成の詳細を指定します。
- プリンシパルを追加: Google SecOps サービス アカウントのメールアドレスを貼り付けます。
- ロールを割り当てる: [Storage オブジェクト閲覧者] を選択します。
[保存] をクリックします。
UDM マッピング テーブル
| ログフィールド | UDM マッピング | ロジック |
|---|---|---|
| when | metadata.event_timestamp | イベントが発生したときのタイムスタンプ |
| metadata.event_type | イベントのタイプ(USER_LOGIN、NETWORK_CONNECTION など) | |
| messageid | metadata.id | イベントの固有識別子 |
| プロトコル | network.ip_protocol | IP プロトコル(TCP、UDP など) |
| deviceName | principal.hostname | 送信元ホスト名 |
| srcAddr | principal.ip | 接続の送信元 IP アドレス |
| srcPort | principal.port | 送信元ポート番号 |
| アクション | security_result.action | セキュリティ プロダクトによって実行されたアクション(ALLOW、BLOCK など) |
| dstAddr | target.ip | 宛先 IP アドレス |
| dstPort | target.port | 宛先ポート番号 |
| metadata.product_name | 商品名 | |
| metadata.vendor_name | ベンダー/会社名 |
さらにサポートが必要な場合 コミュニティ メンバーや Google SecOps のプロフェッショナルから回答を得ることができます。