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 バケットを作成する

  1. Google Cloud コンソールに移動します。
  2. プロジェクトを選択するか、新しいプロジェクトを作成します。
  3. ナビゲーション メニューで、[Cloud Storage > バケット] に移動します。
  4. [バケットを作成] をクリックします。
  5. 次の構成情報を提供してください。

    設定
    バケットに名前を付ける グローバルに一意の名前(eset-ti-logs など)を入力します。
    ロケーション タイプ ニーズに基づいて選択します(リージョン、デュアルリージョン、マルチリージョン)。
    ロケーション ロケーションを選択します(例: us-central1)。
    ストレージ クラス Standard(アクセス頻度の高いログにおすすめ)
    アクセス制御 均一(推奨)
    保護ツール 省略可: オブジェクトのバージョニングまたは保持ポリシーを有効にする
  6. [作成] をクリックします。

ESET Threat Intelligence TAXII 認証情報を収集する

Cloud Run 関数が脅威インテリジェンス データを取得できるようにするには、ETI ポータルから TAXII フィードを有効にして TAXII 認証情報を生成する必要があります。

TAXII フィードを有効にする

  1. https://eti.eset.com で ESET Threat Intelligence ポータルにログインします。
  2. メインメニューの [データフィード] に移動します。
  3. 有効にするデータフィードの横にあるその他アイコンをクリックします。
  4. [フィードを有効にする] を選択します。
  5. Google SecOps に取り込むフィードごとに手順 3 ~ 4 を繰り返します。

TAXII 認証情報を生成する

  1. ESET Threat Intelligence ポータルで、[Admin Settings > Access Credentials] に移動します。
  2. [Generate TAXII Credentials] をクリックします。
  3. 表示されたダイアログで、次の値をコピーして保存します。

    • ユーザー名: TAXII ユーザー名
    • パスワード: TAXII のパスワード

TAXII フィードの詳細を記録する

フィードを有効にして認証情報を生成したら、取り込む各フィードについて次の情報を記録します。

  1. ESET Threat Intelligence ポータルで、[データフィード] に移動します。
  2. 有効なフィードの横にあるその他アイコンをクリックします。
  3. [Show Data Feed detail](データフィードの詳細を表示)を選択します。
  4. サイドパネルで、次の値をメモします。

    • TAXII フィード名: フィード識別子(例: botnet stix 2.1
    • TAXII 2 ID: コレクション ID(例: 0abb06690b0b47e49cd7794396b76b20
    • TAXII 2 フィードの URL: コレクションの完全な URL

利用可能な 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 のサービス アカウントを作成する

  1. Google Cloud コンソールで、[IAM と管理] > [サービス アカウント] に移動します。
  2. [サービス アカウントを作成] をクリックします。
  3. 次の構成情報を提供してください。

    • サービス アカウント名: 「eset-ti-collector」と入力します。
    • サービス アカウントの説明: Service account for ESET Threat Intelligence Cloud Run function to write STIX objects to GCS と入力します。
  4. [作成して続行] をクリックします。

  5. [このサービス アカウントにプロジェクトへのアクセスを許可する] セクションで、次のロールを追加します。

    1. [ロールを選択] をクリックし、[ストレージ オブジェクト管理者] を検索して選択します。
    2. [別のロールを追加] をクリックし、[Cloud Run 起動元] を検索して選択します。
  6. [続行] をクリックします。

  7. [完了] をクリックします。

Google Cloud Storage バケットに対する IAM 権限を付与する

  1. [Cloud Storage] > [バケット] に移動します。
  2. バケット名(例: eset-ti-logs)をクリックします。
  3. [権限] タブに移動します。
  4. [アクセス権を付与] をクリックします。
  5. 次の構成情報を提供してください。

    • プリンシパルを追加: サービス アカウントのメールアドレス(例: eset-ti-collector@PROJECT_ID.iam.gserviceaccount.com)を入力します。
    • ロールを割り当てる: [ストレージ オブジェクト管理者] を選択します。
  6. [保存] をクリックします。

Pub/Sub トピックの作成

Cloud Scheduler によってメッセージがパブリッシュされると、Pub/Sub トピックが Cloud Run functions の関数をトリガーします。

  1. Google Cloud コンソールで、[Pub/Sub>トピック] に移動します。
  2. [トピックを作成] をクリックします。
  3. 次の構成の詳細を指定します。
    • トピック ID: 「eset-ti-trigger」と入力します。
    • デフォルトのサブスクリプションを追加する: 選択したままにする
  4. [作成] をクリックします。

Cloud Run functions を作成する

  1. Google Cloud コンソールで、[Cloud Run functions] に移動します。
  2. [関数を作成] をクリックします。
  3. 次の構成情報を提供してください。

    設定
    環境 第 2 世代
    関数名 eset-ti-collector
    リージョン GCS バケットと同じリージョンを選択します。
    トリガーのタイプ Cloud Pub/Sub
    Pub/Sub トピック eset-ti-trigger
    割り当てられたメモリ 512 MiB
    タイムアウト 540 秒
    ランタイム サービス アカウント eset-ti-collector
  4. [次へ] をクリックします。

  5. [ランタイム] を [Python 3.12] に設定します。

  6. [エントリ ポイント] を main に設定します。

  7. requirements.txt ファイルに次の依存関係を追加します。

    functions-framework==3.*
    google-cloud-storage==2.*
    urllib3==2.*
    
  8. 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
    
  9. [デプロイ] をクリックします。

  10. 関数がデプロイされるまで待ちます。デプロイが完了すると、ステータスが緑色のチェックマークに変わります。

環境変数を構成する

  1. 関数がデプロイされたら、[Cloud Run functions] > [eset-ti-collector] に移動します。
  2. [新しいリビジョンの編集とデプロイ] をクリックします。
  3. [変数とシークレット] タブをクリックします(または、第 1 世代の場合は [ランタイム、ビルド、接続、セキュリティの設定] を開きます)。
  4. 次の環境変数を追加します。

    キー 値の例
    GCS_BUCKET eset-ti-logs
    GCS_PREFIX eset-ti
    STATE_KEY eset-ti/state.json
    TAXII_USERNAME ETI ポータルの TAXII ユーザー名
    TAXII_PASSWORD ETI ポータルから取得した TAXII パスワード
    COLLECTION_ID 0abb06690b0b47e49cd7794396b76b20
    MAX_RECORDS 10000
    LOOKBACK_HOURS 48
  5. [デプロイ] をクリックします。

Cloud Scheduler ジョブの作成

Cloud Scheduler は、スケジュールに従って Pub/Sub トピックにメッセージをパブリッシュし、Cloud Run functions をトリガーして ESET Threat Intelligence の新しい STIX オブジェクトをポーリングします。

  1. Google Cloud コンソールで、[Cloud Scheduler] に移動します。
  2. [ジョブを作成] をクリックします。
  3. 次の構成情報を提供してください。

    設定
    名前 eset-ti-poll
    リージョン 関数と同じリージョンを選択します。
    周波数 0 */1 * * *(1 時間ごと)
    タイムゾーン タイムゾーンを選択します(例: UTC
  4. [続行] をクリックします。

  5. [実行を構成する] セクションで、次の操作を行います。

    • ターゲット タイプ: [Pub/Sub] を選択します。
    • トピック: eset-ti-trigger を選択します。
    • メッセージ本文: 「{"poll": true}」と入力します。
  6. [作成] をクリックします。

Cloud Run functions の関数を確認する

  1. Cloud Scheduler で、eset-ti-poll ジョブを見つけます。
  2. [強制実行] をクリックして、すぐに実行するようにトリガーします。
  3. [Cloud Run functions] > [eset-ti-collector] > [ログ] に移動します。
  4. 次のようなログエントリを確認して、関数が正常に実行されたことを確認します。

    Fetched 250 objects (total: 250)
    Wrote 250 STIX objects to gs://eset-ti-logs/eset-ti/eset_ti_0abb06690b0b47e49cd7794396b76b20_20250115_103000.json
    
  5. [Cloud Storage] > [バケット] > [eset-ti-logs] に移動します。

  6. eset-ti/ 接頭辞に移動します。

  7. NDJSON ファイルが STIX オブジェクトで作成されていることを確認します。

Google SecOps サービス アカウントを取得してフィードを構成する

Google SecOps は、一意のサービス アカウントを使用して GCS バケットからデータを読み取ります。このサービス アカウントにバケットへのアクセス権を付与する必要があります。

サービス アカウントのメールアドレスを取得する

  1. [SIEM 設定] > [フィード] に移動します。
  2. [Add New Feed] をクリックします。
  3. [単一フィードを設定] をクリックします。
  4. [フィード名] フィールドに、フィードの名前を入力します(例: ESET Threat Intelligence - Botnet)。
  5. [ソースタイプ] として [Google Cloud Storage V2] を選択します。
  6. [ログタイプ] として [ESET Threat Intelligence] を選択します。
  7. [サービス アカウントを取得する] をクリックします。一意のサービス アカウント メールアドレスが表示されます(例:)。

    chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com
    
  8. このメールアドレスをコピーして、次のステップで使用します。

  9. [次へ] をクリックします。

  10. 次の入力パラメータの値を指定します。

    • ストレージ バケットの URL: 接頭辞パスを含む GCS バケット URI を入力します。

      gs://eset-ti-logs/eset-ti/
      
    • Source deletion option: 必要に応じて削除オプションを選択します。

      • なし: 転送後にファイルを削除しません(テストにおすすめ)。
      • 転送されたファイルを削除する: 転送が完了した後にファイルを削除します。
      • 転送されたファイルと空のディレクトリを削除する: 転送が完了した後にファイルと空のディレクトリを削除します。

    • ファイルの最大経過日数: 指定した日数以内に変更されたファイルを含めます(デフォルトは 180 日)。

    • アセットの名前空間: アセットの名前空間

    • Ingestion labels: このフィードのイベントに適用されるラベル(ESET_IOC など)

  11. [次へ] をクリックします。

  12. [Finalize] 画面で新しいフィードの設定を確認し、[送信] をクリックします。

Google SecOps サービス アカウントに IAM 権限を付与する

Google SecOps サービス アカウントには、Google Cloud Storage バケットに対するストレージ オブジェクト閲覧者ロールが必要です。

  1. [Cloud Storage] > [バケット] に移動します。
  2. バケット名(例: eset-ti-logs)をクリックします。
  3. [権限] タブに移動します。
  4. [アクセス権を付与] をクリックします。
  5. 次の構成の詳細を指定します。
    • プリンシパルを追加: Google SecOps サービス アカウントのメールアドレスを貼り付けます。
    • ロールを割り当てる: [Storage オブジェクト閲覧者] を選択します。
  6. [保存] をクリックします。

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 のプロフェッショナルから回答を得ることができます。