FortiCNAPP(旧 Lacework)のログを収集する

以下でサポートされています。

このドキュメントでは、Google Cloud Storage V2 を使用して FortiCNAPP(以前の Lacework)ログを Google Security Operations に取り込む方法について説明します。

FortiCNAPP は、マルチクラウド環境全体でクラウド セキュリティ ポスチャー管理、ワークロード保護、脅威検出を提供するクラウドネイティブ アプリケーション保護プラットフォーム(CNAPP)です。Lacework REST API を介して収集できるアラート、コンプライアンス結果、監査ログを生成します。

始める前に

次の前提条件を満たしていることを確認します。

  • Google SecOps インスタンス
  • Cloud Storage API が有効になっている GCP プロジェクト
  • GCS バケットを作成および管理する権限
  • GCS バケットの IAM ポリシーを管理する権限
  • Cloud Run サービス、Pub/Sub トピック、Cloud Scheduler ジョブを作成する権限
  • 管理者権限を持つ FortiCNAPP(旧 Lacework)コンソールへの特権アクセス
  • API キー アクセスが有効になっている Lacework アカウント

Google Cloud Storage バケットを作成する

  1. Google Cloud Console に移動します。
  2. プロジェクトを選択するか、新しいプロジェクトを作成します。
  3. ナビゲーション メニューで、[Cloud Storage > バケット] に移動します。
  4. [バケットを作成] をクリックします。

  5. 次の構成情報を提供してください。

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

FortiCNAPP(旧 Lacework)API 認証情報を収集する

API キーを生成する

  1. Lacework コンソールにログインします。
  2. [設定> 構成> API キー] に移動します。
  3. [+ 新規追加] をクリックします。
  4. API キーの名前(Google SecOps Integration など)を入力します。
  5. 必要に応じて、説明を入力します。
  6. [保存] をクリックします。

  7. 次の詳細をコピーして安全な場所に保存してください。

    • キー ID: 生成された API キー ID
    • シークレット: 生成された API シークレット(1 回のみ表示)
  8. ブラウザのアドレスバーから Lacework アカウントの URL をメモします。

    • 形式: https://<ACCOUNT>.lacework.net
    • 例: Lacework コンソール URL が https://acme.lacework.net で、アカウント名が acme の場合

権限を確認する

アカウントに必要な権限があることを確認するには:

  1. Lacework コンソールにログインします。
  2. [設定> 構成> API キー] に移動します。
  3. [API キー] ページが表示され、キーを作成できる場合は、必要な権限が付与されています。
  4. このオプションが表示されない場合は、管理者にお問い合わせのうえ、管理者レベルのアクセス権を付与してもらってください。

テスト API へのアクセス

  • 統合に進む前に、認証情報をテストします。

    # Replace with your actual credentials
    LW_ACCOUNT="your-account-name"
    LW_KEY_ID="your-api-key-id"
    LW_SECRET="your-api-secret"
    
    # Get a temporary access token
    TOKEN=$(curl -s -X POST "https://${LW_ACCOUNT}.lacework.net/api/v2/access/tokens" \
        -H "X-LW-UAKS: ${LW_SECRET}" \
        -H "Content-Type: application/json" \
        -d "{\"keyId\": \"${LW_KEY_ID}\", \"expiryTime\": 3600}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('token',''))")
    
    # Test API access - list alerts
    curl -v -H "Authorization: Bearer ${TOKEN}" \
        "https://${LW_ACCOUNT}.lacework.net/api/v2/Alerts?startTime=$(date -u -v-1d +%Y-%m-%dT%H:%M:%SZ)&endTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
    

Cloud Run functions のサービス アカウントを作成する

Cloud Run 関数には、GCS バケットに書き込み、Pub/Sub によって呼び出される権限を持つサービス アカウントが必要です。

サービス アカウントの作成

  1. GCP Console で、[IAM と管理>サービス アカウント] に移動します。
  2. [サービス アカウントを作成] をクリックします。

  3. 次の構成情報を提供してください。

    • サービス アカウント名: 「lacework-logs-collector-sa」と入力します。
    • サービス アカウントの説明: Service account for Cloud Run function to collect FortiCNAPP (formerly Lacework) logs と入力します。
  4. [作成して続行] をクリックします。

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

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

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

これらのロールは、次の操作に必要です。

  • Storage オブジェクト管理者: ログを GCS バケットに書き込み、状態ファイルを管理する
  • Cloud Run 起動元: Pub/Sub が関数を呼び出すことを許可します
  • Cloud Functions 起動元: 関数の呼び出しを許可する

GCS バケットに対する IAM 権限を付与する

GCS バケットに対する書き込み権限をサービス アカウントに付与します。

  1. [Cloud Storage] > [バケット] に移動します。
  2. バケット名(例: lacework-logs)をクリックします。
  3. [権限] タブに移動します。
  4. [アクセス権を付与] をクリックします。

  5. 次の構成情報を提供してください。

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

Pub/Sub トピックの作成

Cloud Scheduler がパブリッシュし、Cloud Run functions の関数がサブスクライブする Pub/Sub トピックを作成します。

  1. GCP Console で、[Pub/Sub> トピック] に移動します。
  2. [トピックを作成] をクリックします。

  3. 次の構成情報を提供してください。

    • トピック ID: 「lacework-logs-trigger」と入力します。
    • その他の設定はデフォルトのままにします。
  4. [作成] をクリックします。

ログを収集する Cloud Run 関数を作成する

Cloud Run functions は、Cloud Scheduler からの Pub/Sub メッセージによってトリガーされ、FortiCNAPP(旧 Lacework)API からログを取得して GCS に書き込みます。

  1. GCP Console で、[Cloud Run] に移動します。
  2. [サービスを作成] をクリックします。
  3. [関数] を選択します(インライン エディタを使用して関数を作成します)。

  4. [構成] セクションで、次の構成の詳細を指定します。

    設定
    サービス名 lacework-logs-collector
    リージョン GCS バケットと一致するリージョンを選択します(例: us-central1)。
    ランタイム [Python 3.12] 以降を選択します。
  5. [トリガー(省略可)] セクションで、次の操作を行います。

    1. [+ トリガーを追加] をクリックします。
    2. [Cloud Pub/Sub] を選択します。
    3. [Cloud Pub/Sub トピックを選択してください] で、トピック lacework-logs-trigger を選択します。
    4. [保存] をクリックします。
  6. [認証] セクションで次の操作を行います。

    1. [認証が必要] を選択します。
    2. Identity and Access Management(IAM)を確認します。
  7. 下にスクロールして、[コンテナ、ネットワーキング、セキュリティ] を開きます。

  8. [セキュリティ] タブに移動します。

    • サービス アカウント: サービス アカウント lacework-logs-collector-sa を選択します。
  9. [コンテナ] タブに移動します。

    1. [変数とシークレット] をクリックします。
    2. 環境変数ごとに [+ 変数を追加] をクリックします。
    変数名 値の例 説明
    GCS_BUCKET lacework-logs GCS バケット名
    GCS_PREFIX lacework ログファイルの接頭辞
    STATE_KEY lacework/state.json 状態ファイルのパス
    LW_ACCOUNT acme Lacework アカウント名
    LW_KEY_ID your-api-key-id Lacework API キー ID
    LW_SECRET your-api-secret Lacework API シークレット
    MAX_RECORDS 5000 実行あたりの最大レコード数
    PAGE_SIZE 500 1 ページあたりのレコード数
    LOOKBACK_HOURS 24 最初のルックバック期間
  10. [変数とシークレット] セクションで、[リクエスト] まで下にスクロールします。

    • リクエストのタイムアウト: 600 秒(10 分)を入力します。
  11. [設定] タブに移動します。

    • [リソース] セクションで次の操作を行います。
      • メモリ: 512 MiB 以上を選択します。
      • CPU: 1 を選択します。
  12. [リビジョン スケーリング] セクションで、次の操作を行います。

    • [インスタンスの最小数]: 「0」と入力します。
    • インスタンスの最大数: 100 と入力します(または、予想される負荷に基づいて調整します)。
  13. [作成] をクリックします。

  14. サービスが作成されるまで待ちます(1 ~ 2 分)。

  15. サービスが作成されると、インライン コードエディタが自動的に開きます。

関数コードを追加する

  1. [エントリ ポイント] フィールドに「main」と入力します。
  2. インライン コードエディタで、次の 2 つのファイルを作成します。

    • main.py:

      import functions_framework
      from google.cloud import storage
      import json
      import os
      import urllib3
      from datetime import datetime, timezone, timedelta
      import time
      
      # Initialize HTTP client with timeouts
      http = urllib3.PoolManager(
          timeout=urllib3.Timeout(connect=5.0, read=30.0),
          retries=False,
      )
      
      # Initialize Storage client
      storage_client = storage.Client()
      
      # Environment variables
      GCS_BUCKET = os.environ.get('GCS_BUCKET')
      GCS_PREFIX = os.environ.get('GCS_PREFIX', 'lacework')
      STATE_KEY = os.environ.get('STATE_KEY', 'lacework/state.json')
      LW_ACCOUNT = os.environ.get('LW_ACCOUNT')
      LW_KEY_ID = os.environ.get('LW_KEY_ID')
      LW_SECRET = os.environ.get('LW_SECRET')
      MAX_RECORDS = int(os.environ.get('MAX_RECORDS', '5000'))
      PAGE_SIZE = int(os.environ.get('PAGE_SIZE', '500'))
      LOOKBACK_HOURS = int(os.environ.get('LOOKBACK_HOURS', '24'))
      
      # Lacework API base URL
      API_BASE_TEMPLATE = 'https://{account}.lacework.net/api/v2'
      
      # Log endpoints to fetch
      ENDPOINTS = [
          {'name': 'alerts', 'path': '/Alerts', 'time_field': 'startTime', 'results_key': 'data'},
          {'name': 'audit_logs', 'path': '/AuditLogs', 'time_field': 'createdTime', 'results_key': 'data'},
      ]
      
      def get_access_token(api_base: str, key_id: str, secret: str) -> str:
          """Get a temporary access token from Lacework API."""
          token_url = f"{api_base}/access/tokens"
          body = json.dumps({
              'keyId': key_id,
              'expiryTime': 3600
          }).encode('utf-8')
          headers = {
              'X-LW-UAKS': secret,
              'Content-Type': 'application/json',
          }
          response = http.request('POST', token_url, body=body, headers=headers)
          if response.status != 201:
              raise Exception(f"Failed to get access token: HTTP {response.status} - {response.data.decode('utf-8')}")
          token_data = json.loads(response.data.decode('utf-8'))
          return token_data['token']
      
      @functions_framework.cloud_event
      def main(cloud_event):
          """
          Cloud Run function triggered by Pub/Sub to fetch FortiCNAPP
          (formerly Lacework) logs and write to GCS.
      
          Args:
              cloud_event: CloudEvent object containing Pub/Sub message
          """
      
          if not all([GCS_BUCKET, LW_ACCOUNT, LW_KEY_ID, LW_SECRET]):
              print('Error: Missing required environment variables')
              return
      
          try:
              bucket = storage_client.bucket(GCS_BUCKET)
              api_base = API_BASE_TEMPLATE.format(account=LW_ACCOUNT)
      
              # Get access token
              token = get_access_token(api_base, LW_KEY_ID, LW_SECRET)
              print("Successfully obtained access token")
      
              # Load state
              state = load_state(bucket, STATE_KEY)
      
              # Determine time window
              now = datetime.now(timezone.utc)
              all_records = []
      
              for endpoint in ENDPOINTS:
                  ep_name = endpoint['name']
                  last_time_str = None
      
                  if isinstance(state, dict) and state.get(f"last_{ep_name}_time"):
                      try:
                          last_time = parse_datetime(state[f"last_{ep_name}_time"])
                          # Overlap by 2 minutes to catch any delayed events
                          last_time = last_time - timedelta(minutes=2)
                          last_time_str = last_time.strftime('%Y-%m-%dT%H:%M:%SZ')
                      except Exception as e:
                          print(f"Warning: Could not parse last_{ep_name}_time: {e}")
      
                  if last_time_str is None:
                      last_time = now - timedelta(hours=LOOKBACK_HOURS)
                      last_time_str = last_time.strftime('%Y-%m-%dT%H:%M:%SZ')
      
                  end_time_str = now.strftime('%Y-%m-%dT%H:%M:%SZ')
      
                  print(f"Fetching {ep_name} from {last_time_str} to {end_time_str}")
      
                  records, newest_event_time = fetch_logs(
                      api_base=api_base,
                      token=token,
                      endpoint=endpoint,
                      start_time=last_time_str,
                      end_time=end_time_str,
                      page_size=PAGE_SIZE,
                      max_records=MAX_RECORDS,
                  )
      
                  # Tag records with endpoint type
                  for record in records:
                      record['_lw_log_type'] = ep_name
      
                  all_records.extend(records)
      
                  # Update state for this endpoint
                  if newest_event_time:
                      state[f"last_{ep_name}_time"] = newest_event_time
                  else:
                      state[f"last_{ep_name}_time"] = end_time_str
      
                  print(f"Fetched {len(records)} {ep_name} records")
      
              if not all_records:
                  print("No new log records found.")
                  save_state(bucket, STATE_KEY, state)
                  return
      
              # Write to GCS as NDJSON
              timestamp = now.strftime('%Y%m%d_%H%M%S')
              object_key = f"{GCS_PREFIX}/logs_{timestamp}.ndjson"
              blob = bucket.blob(object_key)
      
              ndjson = '\n'.join([json.dumps(record, ensure_ascii=False) for record in all_records]) + '\n'
              blob.upload_from_string(ndjson, content_type='application/x-ndjson')
      
              print(f"Wrote {len(all_records)} records to gs://{GCS_BUCKET}/{object_key}")
      
              # Save state
              save_state(bucket, STATE_KEY, state)
      
              print(f"Successfully processed {len(all_records)} records")
      
          except Exception as e:
              print(f'Error processing logs: {str(e)}')
              raise
      
      def parse_datetime(value: str) -> datetime:
          """Parse ISO datetime string to datetime object."""
          if value.endswith("Z"):
              value = value[:-1] + "+00:00"
          return datetime.fromisoformat(value)
      
      def load_state(bucket, key):
          """Load state from GCS."""
          try:
              blob = bucket.blob(key)
              if blob.exists():
                  state_data = blob.download_as_text()
                  return json.loads(state_data)
          except Exception as e:
              print(f"Warning: Could not load state: {e}")
      
          return {}
      
      def save_state(bucket, key, state: dict):
          """Save the state to GCS state file."""
          try:
              blob = bucket.blob(key)
              blob.upload_from_string(
                  json.dumps(state, indent=2),
                  content_type='application/json'
              )
              print(f"Saved state: {json.dumps(state)}")
          except Exception as e:
              print(f"Warning: Could not save state: {e}")
      
      def fetch_logs(api_base: str, token: str, endpoint: dict, start_time: str, end_time: str, page_size: int, max_records: int):
          """
          Fetch logs from Lacework API with pagination and rate limiting.
      
          Args:
              api_base: API base URL
              token: Bearer access token
              endpoint: Endpoint configuration dict
              start_time: Start time in ISO format
              end_time: End time in ISO format
              page_size: Number of records per page
              max_records: Maximum total records to fetch
      
          Returns:
              Tuple of (records list, newest_event_time ISO string)
          """
          headers = {
              'Authorization': f'Bearer {token}',
              'Accept': 'application/json',
              'Content-Type': 'application/json',
              'User-Agent': 'GoogleSecOps-LaceworkCollector/1.0'
          }
      
          ep_path = endpoint['path']
          time_field = endpoint['time_field']
          results_key = endpoint['results_key']
      
          records = []
          newest_time = None
          page_num = 0
          backoff = 1.0
          next_page = None
      
          while True:
              page_num += 1
      
              if len(records) >= max_records:
                  print(f"Reached max_records limit ({max_records}) for {endpoint['name']}")
                  break
      
              # Build request URL
              if next_page:
                  url = next_page
              else:
                  url = f"{api_base}{ep_path}?startTime={start_time}&endTime={end_time}"
      
              try:
                  response = http.request('GET', url, headers=headers)
      
                  # Handle rate limiting with exponential backoff
                  if response.status == 429:
                      retry_after = int(response.headers.get('Retry-After', str(int(backoff))))
                      print(f"Rate limited (429). Retrying after {retry_after}s...")
                      time.sleep(retry_after)
                      backoff = min(backoff * 2, 30.0)
                      continue
      
                  backoff = 1.0
      
                  if response.status != 200:
                      print(f"HTTP Error: {response.status}")
                      response_text = response.data.decode('utf-8')
                      print(f"Response body: {response_text}")
                      return [], None
      
                  data = json.loads(response.data.decode('utf-8'))
      
                  page_results = data.get(results_key, [])
      
                  if not page_results:
                      print(f"No more results (empty page) for {endpoint['name']}")
                      break
      
                  print(f"Page {page_num}: Retrieved {len(page_results)} {endpoint['name']} events")
                  records.extend(page_results)
      
                  # Track newest event time
                  for event in page_results:
                      try:
                          event_time = event.get(time_field)
                          if event_time:
                              if newest_time is None or parse_datetime(event_time) > parse_datetime(newest_time):
                                  newest_time = event_time
                      except Exception as e:
                          print(f"Warning: Could not parse event time: {e}")
      
                  # Check for next page via paging object
                  paging = data.get('paging', {})
                  next_page_url = paging.get('urls', {}).get('nextPage')
                  if not next_page_url:
                      print(f"No more pages for {endpoint['name']}")
                      break
                  next_page = next_page_url
      
              except Exception as e:
                  print(f"Error fetching {endpoint['name']} logs: {e}")
                  return [], None
      
          print(f"Retrieved {len(records)} total {endpoint['name']} records from {page_num} pages")
          return records, newest_time
      
    • requirements.txt:

      functions-framework==3.*
      google-cloud-storage==2.*
      urllib3>=2.0.0
      
  3. [デプロイ] をクリックして、関数を保存してデプロイします。

  4. デプロイが完了するまで待ちます(2 ~ 3 分)。

Cloud Scheduler ジョブの作成

Cloud Scheduler は、定期的に Pub/Sub トピックにメッセージをパブリッシュし、Cloud Run functions の関数をトリガーします。

  1. GCP Console で、[Cloud Scheduler] に移動します。
  2. [ジョブを作成] をクリックします。

  3. 次の構成情報を提供してください。

    設定
    名前 lacework-logs-collector-hourly
    リージョン Cloud Run functions と同じリージョンを選択する
    周波数 0 * * * *(1 時間ごとに正時)
    タイムゾーン タイムゾーンを選択します(UTC を推奨)
    ターゲット タイプ Pub/Sub
    トピック トピック lacework-logs-trigger を選択します。
    メッセージ本文 {}(空の JSON オブジェクト)
  4. [作成] をクリックします。

スケジュールの頻度のオプション

ログの量とレイテンシの要件に基づいて頻度を選択します。

頻度 CRON 式 ユースケース
5 分おき */5 * * * * 大容量、低レイテンシ
15 分ごと */15 * * * * 検索ボリュームが普通
1 時間ごと 0 * * * * 標準(推奨)
6 時間ごと 0 */6 * * * 少量、バッチ処理
毎日 0 0 * * * 過去のデータの収集

統合をテストする

  1. Cloud Scheduler コンソールで、ジョブを見つけます。
  2. [強制実行] をクリックして、ジョブを手動でトリガーします。
  3. 数秒待ちます。
  4. Cloud Run > サービスに移動します。
  5. lacework-logs-collector をクリックします。
  6. [Logs] タブをクリックします。
  7. 関数が正常に実行されたことを確認します。以下のものを探します。

    Successfully obtained access token
    Fetching alerts from YYYY-MM-DDTHH:MM:SSZ to YYYY-MM-DDTHH:MM:SSZ
    Page 1: Retrieved X alerts events
    Fetched X alerts records
    Fetching audit_logs from YYYY-MM-DDTHH:MM:SSZ to YYYY-MM-DDTHH:MM:SSZ
    Page 1: Retrieved X audit_logs events
    Fetched X audit_logs records
    Wrote X records to gs://lacework-logs/lacework/logs_YYYYMMDD_HHMMSS.ndjson
    Successfully processed X records
    
  8. [Cloud Storage] > [バケット] に移動します。

  9. バケット名(lacework-logs)をクリックします。

  10. lacework/ フォルダに移動します。

  11. 現在のタイムスタンプで新しい .ndjson ファイルが作成されたことを確認します。

ログにエラーが表示された場合:

  • HTTP 401: 環境変数の API 認証情報を確認するか、トークンの有効期限が切れている可能性があります
  • HTTP 403: Lacework コンソールで、API キーに必要な権限があることを確認します。
  • HTTP 429: レート制限 - 関数はバックオフで自動的に再試行されます
  • 環境変数が不足している: 必要な変数がすべて設定されていることを確認します

FortiCNAPP(旧 Lacework)のログを取り込むように Google SecOps でフィードを構成する

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

    chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com
    
  8. このメールアドレスをコピーします。

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

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

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

      gs://lacework-logs/lacework/
      
      • 次のように置き換えます。
        • lacework-logs: GCS バケット名。
        • lacework: ログが保存されるオプションの接頭辞/フォルダパス(ルートの場合は空のままにします)。
    • Source deletion option: 必要に応じて削除オプションを選択します。

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

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

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

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

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

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

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

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

  1. [Cloud Storage] > [バケット] に移動します。
  2. バケット名をクリックします。
  3. [権限] タブに移動します。
  4. [アクセス権を付与] をクリックします。

  5. 次の構成情報を提供してください。

    • プリンシパルを追加: Google SecOps サービス アカウントのメールアドレスを貼り付けます。
    • ロールを割り当てる: [Storage オブジェクト閲覧者] を選択します。
  6. [保存] をクリックします。

サポートされている Lacework Cloud Security のサンプルログ

  • エージェントまたはマシン情報(ホスト インベントリ)

    {
      "AGENT_VERSION": "6.7.6-4ce73a7b",
      "CREATED_TIME": "Thu, 03 Nov 2022 02:09:36 -0700",
      "HOSTNAME": "host-agent-1",
      "IP_ADDR": "10.0.0.1",
      "LAST_UPDATE": "Wed, 18 Oct 2023 17:59:09 -0700",
      "MID": 6516601498285932156,
      "MODE": "ebpf",
      "OS": "Linux",
      "STATUS": "ACTIVE",
      "TAGS": {
        "Account": "999999999999",
        "AmiId": "ami-00000000000000000",
        "ExternalIp": "203.0.113.10",
        "Hostname": "internal-host-1.zone.compute.internal",
        "InstanceId": "i-00000000000000000",
        "InternalIp": "172.16.1.10",
        "LwTokenShort": "DUMMYTOKENABCD123456",
        "Name": "proxy-DMZ-app-1",
        "ResourceType": "proxy-machines",
        "SubnetId": "subnet-00000000000000000",
        "VmInstanceType": "t3.small",
        "VmProvider": "AWS",
        "VpcId": "vpc-00000000000000000",
        "Zone": "us-west-2a",
        "arch": "amd64",
        "falconx.io/application": "proxy-machines",
        "falconx.io/environment": "prod",
        "falconx.io/project": "edge",
        "falconx.io/team": "edge",
        "os": "linux"
      }
    }
    
  • ファイル メタデータまたは整合性

    {
    "CREATED_TIME": "Wed, 18 Oct 2023 17:02:01 -0700",
    "FILEDATA_HASH": "DUMMYHASH582C741AD91CA817B4718DEAA4E8A83C0B9D92E2",
    "FILE_PATH": "/usr/local/bin/secure_config",
    "MID": 7371220731851617371,
    "MTIME": "Fri, 25 Aug 2023 13:03:09 -0700",
    "SIZE": 8078
    }
    
  • ホストの脆弱性評価

    {
    "CVE_PROPS": {
      "description": "DOCUMENTATION: The MITRE CVE dictionary describes this issue as: "
                     "This CVE ID has been rejected or withdrawn by its CVE Numbering "
                     "Authority for the following reason: This CVE ID has been rejected "
                     "or withdrawn by its CVE Numbering Authority.",
      "link": "https://vendor.example.com/security/cve/CVE-2021-47472",
      "metadata": null
    },
    "CVE_RISK_INFO": {
      "HOST_COUNT": 1249,
      "IMAGE_COUNT": 0,
      "PKG_COUNT": 0,
      "SEVERITY_LEVEL": 2,
      "score": 0.5154245281584533
    },
    "CVE_RISK_SCORE": 3.77,
    "END_TIME": "2024-09-04 07:00:00.000",
    "EVAL_CTX": {
      "collector_type": "Agent",
      "exception_props": [],
      "hostname": "vuln-host-1.example.net"
    },
    "EVAL_GUID": "3dc61df780e3b722aa59b0ffcac85683",
    "FEATURE_KEY": {
      "name": "kernel-headers",
      "namespace": "centos:7",
      "package_active": 1,
      "package_path": "",
      "version_installed": "0:3.10.0-1160.119.1.el7.tuxcare.els2"
    },
    "MACHINE_TAGS": {
      "Account": "999999999999",
      "AmiId": "ami-00000000000000000",
      "ExternalIp": "203.0.113.10",
      "Hostname": "ip-172-16-1-10.example-prod.aws.featurespace.net",
      "InternalIp": "10.0.0.1",
      "LwTokenShort": "DUMMYTOKENABCD123456",
      "VmProvider": "AWS",
      "VpcId": "vpc-00000000000000000",
      "os": "linux"
    },
    "MID": 5746003737030963813,
    "PACKAGE_STATUS": "ACTIVE",
    "REGION": "eu-west-2",
    "RISK_SCORE": 10,
    "SEVERITY": "Low",
    "START_TIME": "2024-09-04 06:00:00.000",
    "STATUS": "Exception",
    "VULN_ID": "CVE-2021-47472"
    }
    
  • クラウド構成のコンプライアンス(監査)

    {
    "ACCOUNT": {
      "AccountId": "999999999999",
      "Account_Alias": ""
    },
    "EVAL_TYPE": "LW_SA",
    "ID": "lacework-global-87",
    "REASON": "Default security group does not restrict traffic",
    "RECOMMENDATION": "Ensure the default security group of every Virtual Private Cloud (VPC) restricts all traffic",
    "REGION": "eu-north-1",
    "REPORT_TIME": "2024-11-10 18:00:00.000",
    "RESOURCE_ID": "arn:aws:ec2:eu-west-1:999999999999:security-group/sg-00000000000000000",
    "SECTION": "",
    "SEVERITY": "High",
    "STATUS": "NonCompliant"
    }
    
  • DNS クエリまたは解決

    {
    "CREATED_TIME": "2024-11-06 05:14:44.329",
    "DNS_SERVER_IP": "10.0.0.53",
    "FQDN": "data-service-prod-1234567890.s3.eu-west-2.amazonaws.com",
    "HOST_IP_ADDR": "172.16.1.20",
    "MID": 8843985456817096491,
    "TTL": 5
    }
    
  • イメージの脆弱性評価

    {
    "CVE_PROPS": null,
    "EVAL_CTX": {
      "collector_type": "Agentless",
      "image_info": {
        "digest": "sha256:52d5cb782dad7a8a03c8bd1b285bbd32bdbfa8fcc435614bb1e6ceefcf26ae1d",
        "id": "sha256:31427c44cac7ab632d541181073bbd46a964e4ed38d087d8a47f60bb66eef4df",
        "registry": "999999999999.dkr.ecr.eu-west-1.amazonaws.com",
        "repo": "amazon/aws-network-policy-agent"
      }
    },
    "EVAL_GUID": "3a17a74f0a65eed2bddd2d37bb02e6af",
    "FEATURE_KEY": {
      "name": "perl-threads",
      "namespace": "amzn:2",
      "version": "1.87-4.amzn2.0.2"
    },
    "FIX_INFO": {
      "fix_available": 0,
      "fixed_version": ""
    },
    "IMAGE_ID": "sha256:31427c44cac7ab632d541181073bbd46a964e4ed38d087d8a47f60bb66eef4df",
    "IMAGE_RISK_INFO": {
      "factors": [
        "cve",
        "reachability"
      ],
      "factors_breakdown": {
        "cve_counts": {
          "Critical": 0,
          "High": 21,
          "Medium": 73
        },
        "internet_reachability": "Unknown"
      }
    },
    "IMAGE_RISK_SCORE": 6.4,
    "PACKAGE_STATUS": "NO_AGENT_AVAILABLE",
    "RISK_SCORE": 6.4,
    "START_TIME": "2024-11-05 19:05:03.553",
    "STATUS": "GOOD"
    }
    
  • ネットワーク トラフィックまたは接続の概要

    {
    "DST_ENTITY_ID": {
      "hostname": "service-A.region.amazonaws.com",
      "ip_internal": 0,
      "port": 443,
      "protocol": "TCP"
    },
    "DST_ENTITY_TYPE": "DnsSep",
    "DST_IN_BYTES": 0,
    "DST_OUT_BYTES": 0,
    "ENDPOINT_DETAILS": [
      {
        "dst_ip_addr": "203.0.113.10",
        "dst_port": 443,
        "protocol": "TCP",
        "src_ip_addr": "192.168.1.10"
      },
      {
        "dst_ip_addr": "198.51.100.5",
        "dst_port": 443,
        "protocol": "TCP",
        "src_ip_addr": "192.168.1.10"
      }
    ],
    "END_TIME": "2024-11-05 21:00:00.000",
    "NUM_CONNS": 4,
    "SRC_ENTITY_ID": {
      "mid": 2080882850610892909,
      "pid_hash": 744766973756676842
    },
    "SRC_ENTITY_TYPE": "Process",
    "SRC_IN_BYTES": 25028,
    "SRC_OUT_BYTES": 11962,
    "START_TIME": "2024-11-05 20:00:00.000"
    }
    
  • Package Information or Update(パッケージ情報または更新)

    {
    "ARCH": "x86_64",
    "CREATED_TIME": "2024-11-08 01:28:30.566",
    "MID": 4172267319977985370,
    "PACKAGE_NAME": "grub2",
    "VERSION": "2:2.02-0.87.0.2.el7.el7.centos.14.tuxcare.els2"
    }
    
  • コンテナ プロセス アクティビティ

    {
    "CONTAINER_ID": "4853339865add970f72213ec5d76ff51d1308c61a7680cc23c8de20c38c0a8e1",
    "END_TIME": "2024-11-08 02:00:00.000",
    "FILE_PATH": "/app/grpc-health-probe",
    "MID": 3708952045169222383,
    "PID": 177267,
    "POD_NAME": "kubernetes-pod-abc",
    "PPID": 177257,
    "PROCESS_START_TIME": "2024-11-08 01:43:29.960",
    "START_TIME": "2024-11-08 01:00:00.000",
    "UID": 0,
    "USERNAME": "serviceuser"
    }
    
  • 一般的なアラートまたはイベント(CloudTrail)

    {
    "EVENT_ID": "413328",
    "EVENT_NAME": "Unauthorized API Call",
    "EVENT_TYPE": "CloudTrailDefaultAlert",
    "SUMMARY": " For account: 999999999999 (and 22 more) : event Unauthorized API Call from a username other "
               "than whitelisted ones. Replaces lacework-global-29 occurred 3772 times by user "
               "UDM-PRINCIPAL-ID:UDM-SERVICE-ROLE (and 167 more) ",
    "START_TIME": "07 Feb 2025 12:00 GMT",
    "EVENT_CATEGORY": "Aws",
    "LINK": "https://security.example.net/ui/alert/12345/details",
    "ACCOUNT": "UDM_ACCOUNT",
    "SOURCE": "CloudTrail",
    "subject": {
      "srcEvent": {
        "event": {
          "errorCode": "AccessDenied",
          "errorMessage": "User: arn:aws:sts::999999999999:assumed-role/UDM-SERVICE-ROLE-IngestionApiRole/UDM-SERVICE-PRINCIPAL "
                          "is not authorized to perform: kinesis:ListShards on resource: "
                          "arn:aws:kinesis:us-east-1:999999999999:stream/ingestion-qa-rel-fraud-review-Stream "
                          "because no identity-based policy allows the kinesis:ListShards action",
          "eventName": "ListShards",
          "eventSource": "kinesis.amazonaws.com",
          "eventTime": "2025-02-07T12:00:24Z",
          "recipientAccountId": "999999999999",
          "sourceIPAddress": "firehose.amazonaws.com",
          "userIdentity": {
            "accessKeyId": "ACCESSKEYIDDUMMY",
            "accountId": "999999999999",
            "arn": "arn:aws:sts::999999999999:assumed-role/UDM-SERVICE-ROLE-IngestionApiRole/UDM-SERVICE-PRINCIPAL",
            "sessionContext": {
              "sessionIssuer": {
                "accountId": "999999999999",
                "arn": "arn:aws:iam::999999999999:role/UDM-SERVICE-ROLE-IngestionApiRole",
                "principalId": "PRINCIPALIDDUMMY",
                "userName": "UDM-SERVICE-ROLE-IngestionApiRole"
              }
            }
          },
          "vpcEndpointId": "vpce-00000000000000000"
        },
        "principalId": "PRINCIPALIDDUMMY:UDM-SERVICE-PRINCIPAL",
        "recipientAccountId": "999999999999",
        "sourceIPAddress": "firehose.amazonaws.com",
        "userIdentityName": "UDM-SERVICE-ROLE-IngestionApiRole"
      }
    }
    }
    

UDM マッピング テーブル

ログフィールド UDM マッピング ロジック
alertId metadata.product_log_id 値を直接コピーしました
alertName security_result.rule_name 値を直接コピーしました
重要度 security_result.severity UDM の重大度にマッピングされます
ステータス security_result.summary 値を直接コピーしました
alertType security_result.category_details 値を直接コピーしました
startTime metadata.event_timestamp ISO 8601 タイムスタンプとして解析されます
endTime additional.fields end_time ラベルとして保存
alertInfo.description security_result.description 値を直接コピーしました
alertInfo.subject metadata.description 値を直接コピーしました
entityMap.Machine.hostname principal.hostname 値を直接コピーしました
entityMap.Machine.externalIp principal.ip 値を直接コピーしました
entityMap.User.username principal.user.userid 値を直接コピーしました
entityMap.Region.region principal.location.name 値を直接コピーしました
entityMap.CT_User.accountId principal.user.product_object_id 値を直接コピーしました

さらにサポートが必要な場合 コミュニティ メンバーや Google SecOps のプロフェッショナルから回答を得ることができます。