Tenable-Audit-Logs erfassen

Unterstützt in:

In diesem Dokument wird beschrieben, wie Sie Tenable-Audit-Logs mit Cloud Storage V2 in Google Security Operations aufnehmen.

Tenable Vulnerability Management (früher Tenable.io) ist eine cloudbasierte Plattform zur Verwaltung von Sicherheitslücken (cloud.tenable.com), in deren Aktivitätsprotokoll Nutzerauthentifizierung, API-Zugriff, Konfigurationsänderungen und administrative Aktionen aufgezeichnet werden. Die Tenable Vulnerability Management REST API bietet programmatischen Zugriff auf diese Aktivitätsprotokollereignisse.

Hinweis

Prüfen Sie, ob folgende Voraussetzungen erfüllt sind:

  • Eine Google SecOps-Instanz
  • Ein Google Cloud -Projekt mit aktivierter Cloud Storage API
  • Berechtigungen zum Erstellen und Verwalten von Cloud Storage-Buckets
  • Berechtigungen zum Verwalten von IAM-Richtlinien (Identity and Access Management) für Cloud Storage-Buckets
  • Berechtigungen zum Erstellen von Cloud Run-Diensten, Pub/Sub-Themen und Cloud Scheduler-Jobs
  • Privilegierter Zugriff auf Tenable Verwaltung von Sicherheitslücken (cloud.tenable.com) mit der Rolle Administrator
  • Tenable Vulnerability Management API-Schlüssel (Zugriffsschlüssel und geheimer Schlüssel), die für ein Nutzerkonto mit der Rolle Administrator generiert wurden

Cloud Storage-Bucket erstellen

  1. Gehen Sie zur Google Cloud Console.
  2. Wählen Sie Ihr Projekt aus oder erstellen Sie ein neues.
  3. Rufen Sie im Navigationsmenü Cloud Storage > Buckets auf.
  4. Klicken Sie auf Bucket erstellen.
  5. Geben Sie die folgenden Konfigurationsdetails an:

    Einstellung Wert
    Bucket benennen Geben Sie einen global eindeutigen Namen ein (z. B. tenable-audit-logs).
    Standorttyp Wählen Sie die Option, die am besten zu Ihren Anforderungen passt (Region, Dual-Region, Multi-Region).
    Standort Wählen Sie den Standort aus (z. B. us-central1).
    Speicherklasse Standard (empfohlen für Logs, auf die häufig zugegriffen wird)
    Zugriffssteuerung Einheitlich (empfohlen)
    Schutztools Optional: Objektversionsverwaltung oder Aufbewahrungsrichtlinie aktivieren
  6. Klicken Sie auf Erstellen.

API-Anmeldedaten für Tenable Vulnerability Management erfassen

API-Schlüssel generieren

  1. Melden Sie sich bei Tenable Vulnerability Management an.
  2. Klicken Sie rechts oben auf einer beliebigen Seite auf den blauen Nutzerkreis und dann auf Mein Profil. Die Seite Mein Konto wird angezeigt.
  3. Rufen Sie den Tab API-Schlüssel auf.
  4. Klicken Sie auf Generieren. Das Fenster API-Schlüssel generieren wird mit einer Warnung angezeigt.

    „Achtung: Durch das Generieren von Schlüsseln werden alle vorhandenen API-Schlüssel in diesem Nutzerkonto ersetzt, einschließlich der Schlüssel, die bereits von anderen Integrationen verwendet werden. Verwenden Sie für diese Integration ein dediziertes Nutzerkonto oder aktualisieren Sie jede Anwendung, die die vorherigen Schlüssel verwendet hat.“

  5. Lesen Sie die Warnung und klicken Sie auf Generieren.

  6. Kopieren und speichern Sie die folgenden Details an einem sicheren Ort:

    • Zugriffsschlüssel: Der API-Zugriffsschlüssel
    • Secret Key: Der geheime API-Schlüssel

API-Zugriff prüfen

  • Testen Sie Ihre Anmeldedaten, bevor Sie mit der Integration fortfahren:

    # Replace with your actual credentials
    ACCESS_KEY="your-access-key"
    SECRET_KEY="your-secret-key"
    
    curl -s -H "X-ApiKeys: accessKey=${ACCESS_KEY};secretKey=${SECRET_KEY}" \
        "https://cloud.tenable.com/audit-log/v1/events?limit=1" | head -c 500
    

Berechtigungen prüfen

So prüfen Sie, ob das Konto die erforderlichen Berechtigungen hat:

  1. Melden Sie sich bei Tenable Vulnerability Management an.
  2. Klicken Sie im linken Navigationsbereich auf Einstellungen.
  3. Klicken Sie auf die Kachel Zugriffssteuerung.
  4. Klicken Sie auf den Tab Nutzer und dann auf das Nutzerkonto, das für diese Integration verwendet wird.
  5. Prüfen Sie, ob das Konto die Rolle Administrator hat. Für den Endpunkt des Aktivitätsprotokolls ist die Nutzerrolle „Administrator“ erforderlich. Mit benutzerdefinierten Rollen kann kein Zugriff auf das Aktivitätsprotokoll gewährt werden. Bei allen anderen Rollen wird eine HTTP 403-Antwort zurückgegeben.

  6. Wenn Sie nicht die erforderlichen Berechtigungen haben, wenden Sie sich an Ihren Tenable Vulnerability Management-Administrator.

Dienstkonto für die Cloud Run-Funktion erstellen

Die Cloud Run-Funktion benötigt ein Dienstkonto mit Berechtigungen zum Schreiben in den Cloud Storage-Bucket und zum Aufrufen durch Pub/Sub.

Erstellen Sie das Dienstkonto:

  1. Rufen Sie in der GCP Console die Seite IAM und Verwaltung > Dienstkonten auf.
  2. Klicken Sie auf Dienstkonto erstellen.
  3. Geben Sie die folgenden Konfigurationsdetails an:
    • Name des Dienstkontos: Geben Sie tenable-audit-collector-sa ein.
    • Beschreibung des Dienstkontos: Geben Sie Service account for Cloud Run function to collect Tenable Audit logs ein.
  4. Klicken Sie auf Erstellen und fortfahren.
  5. Fügen Sie im Abschnitt Diesem Dienstkonto Zugriff auf das Projekt erteilen die folgenden Rollen hinzu:
    1. Klicken Sie auf Rolle auswählen.
    2. Suchen Sie nach Storage Object Admin und wählen Sie die Rolle aus.
    3. Klicken Sie auf + Weitere Rolle hinzufügen.
    4. Suchen Sie nach Cloud Run Invoker und wählen Sie die Rolle aus.
    5. Klicken Sie auf + Weitere Rolle hinzufügen.
    6. Suchen Sie nach Cloud Functions-Aufrufer und wählen Sie die Rolle aus.
  6. Klicken Sie auf Weiter.
  7. Klicken Sie auf Fertig.

Diese Rollen sind erforderlich für:

  • Storage-Objekt-Administrator: Schreibt Logs in den Cloud Storage-Bucket und verwaltet Statusdateien
  • Cloud Run-Aufrufer: Ermöglicht Pub/Sub, die Funktion aufzurufen.
  • Cloud Functions-Invoker: Ermöglicht den Funktionsaufruf

IAM-Berechtigungen für den Cloud Storage-Bucket gewähren

Gewähren Sie dem Dienstkonto Schreibberechtigungen für den Cloud Storage-Bucket:

  1. Rufen Sie Cloud Storage > Buckets auf.
  2. Klicken Sie auf den Namen Ihres Buckets (z. B. tenable-audit-logs).
  3. Wechseln Sie zum Tab Berechtigungen.
  4. Klicken Sie auf Zugriff erlauben.
  5. Geben Sie die folgenden Konfigurationsdetails an:
    • Hauptkonten hinzufügen: Geben Sie die E-Mail-Adresse des Dienstkontos ein (z. B. tenable-audit-collector-sa@PROJECT_ID.iam.gserviceaccount.com).
    • Rollen zuweisen: Wählen Sie Storage-Objekt-Administrator aus.
  6. Klicken Sie auf Speichern.

Pub/Sub-Thema erstellen

Erstellen Sie ein Pub/Sub-Thema, in dem Cloud Scheduler Nachrichten veröffentlicht und das die Cloud Run-Funktion abonniert.

  1. Wechseln Sie in der GCP Console zu Pub/Sub > Themen.
  2. Klicken Sie auf Thema erstellen.
  3. Geben Sie die folgenden Konfigurationsdetails an:
    • Themen-ID: Geben Sie tenable-audit-trigger ein.
    • Übernehmen Sie die anderen Einstellungen.
  4. Klicken Sie auf Erstellen.

Cloud Run-Funktion zum Erfassen von Logs erstellen

Die Cloud Run-Funktion wird durch Pub/Sub-Nachrichten von Cloud Scheduler ausgelöst, um Protokolle aus der Tenable Verwaltung von Sicherheitslücken REST API abzurufen und in Cloud Storage zu schreiben.

  1. Rufen Sie in der GCP Console Cloud Run auf.
  2. Klicken Sie auf Dienst erstellen.
  3. Wählen Sie Funktion aus (Funktion mit einem Inline-Editor erstellen).
  4. Geben Sie im Abschnitt Konfigurieren die folgenden Konfigurationsdetails an:

    Einstellung Wert
    Dienstname tenable-audit-collector
    Region Wählen Sie die Region aus, die Ihrem Cloud Storage-Bucket entspricht (z. B. us-central1).
    Laufzeit Wählen Sie Python 3.12 oder höher aus.
  5. Im Abschnitt Trigger (optional):

    1. Klicken Sie auf + Trigger hinzufügen.
    2. Wählen Sie Cloud Pub/Sub aus.
    3. Wählen Sie unter Cloud Pub/Sub-Thema auswählen das Thema tenable-audit-trigger aus.
    4. Klicken Sie auf Speichern.
  6. Im Abschnitt Authentifizierung:

    1. Wählen Sie Authentifizierung erforderlich aus.
    2. Prüfen Sie Identity and Access Management (IAM).
  7. Scrollen Sie nach unten und maximieren Sie Container, Netzwerk, Sicherheit.

  8. Rufen Sie den Tab Sicherheit auf:

    • Dienstkonto: Wählen Sie das Dienstkonto tenable-audit-collector-sa aus.
  9. Rufen Sie den Tab Container auf:

    1. Klicken Sie auf Variablen und Secrets.
    2. Klicken Sie für jede Umgebungsvariable auf + Variable hinzufügen:
    Variablenname Beispielwert Beschreibung
    GCS_BUCKET tenable-audit-logs Name des Cloud Storage-Buckets
    GCS_PREFIX tenable Präfix für Logdateien
    STATE_KEY tenable-state.json Zustandspfad, außerhalb des Logpräfixes
    TENABLE_ACCESS_KEY your-access-key Zugriffsschlüssel für Tenable Vulnerability Management
    TENABLE_SECRET_KEY your-secret-key Geheimer Schlüssel für Tenable Vulnerability Management
    MAX_RECORDS 5000 Maximale Anzahl von Datensätzen pro Ausführung
    PAGE_SIZE 1000 Einträge pro Seite
    LOOKBACK_HOURS 24 Anfänglicher Rückschauzeitraum
    OVERLAP_MINUTES 2 Minuten, die vor dem Wasserzeichen noch einmal gelesen werden, um spät indexierte Ereignisse zu erfassen
  10. Gehen Sie im Bereich Variablen und Secrets zu Anfragen:

    • Zeitüberschreitung bei Anfrage: Geben Sie 600 Sekunden (10 Minuten) ein.
  11. Rufen Sie den Tab Einstellungen auf:

    • Im Abschnitt Ressourcen:
      • Arbeitsspeicher: Wählen Sie 512 MiB oder höher aus.
      • CPU: Wählen Sie 1 aus.
  12. Im Abschnitt Versionsskalierung:

    • Mindestanzahl von Instanzen: Geben Sie 0 ein.
    • Maximale Anzahl von Instanzen: Geben Sie 100 ein (oder passen Sie den Wert an die erwartete Last an).
  13. Klicken Sie auf Erstellen.

  14. Warten Sie ein bis zwei Minuten, bis der Dienst erstellt wurde.

  15. Nachdem der Dienst erstellt wurde, wird der Inline-Code-Editor automatisch geöffnet.

Funktionscode hinzufügen

  1. Geben Sie main in das Feld Einstiegspunkt ein.
  2. Erstellen Sie im Inline-Code-Editor zwei Dateien:

    • Erste Datei – main.py:
    import functions_framework
    from google.cloud import storage
    from google.cloud.exceptions import NotFound
    import json
    import os
    import re
    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', 'tenable')
    # STATE_KEY must stay OUTSIDE GCS_PREFIX. The feed ingests every object under
    # its bucket URI and, with a deletion option selected, deletes what it
    # transferred. A state file inside the prefix would be ingested as log data and
    # then deleted, resetting collection and re-ingesting duplicates.
    STATE_KEY = os.environ.get('STATE_KEY', 'tenable-state.json')
    TENABLE_ACCESS_KEY = os.environ.get('TENABLE_ACCESS_KEY')
    TENABLE_SECRET_KEY = os.environ.get('TENABLE_SECRET_KEY')
    MAX_RECORDS = int(os.environ.get('MAX_RECORDS', '5000'))
    # The audit-log API accepts a limit up to 10000.
    PAGE_SIZE = int(os.environ.get('PAGE_SIZE', '1000'))
    LOOKBACK_HOURS = int(os.environ.get('LOOKBACK_HOURS', '24'))
    # The query re-reads this many minutes before the watermark so that events
    # Tenable indexes late are still collected. Re-read events are dropped by id.
    OVERLAP_MINUTES = int(os.environ.get('OVERLAP_MINUTES', '2'))
    
    TENABLE_API_BASE = 'https://cloud.tenable.com'
    
    class FetchError(Exception):
      """Raised when the Tenable API call fails.
    
      The watermark must never advance on a failed fetch, otherwise every event in
      the failed window is skipped permanently.
      """
    
    def parse_datetime(value: str) -> datetime:
      """Parse a Tenable `received` timestamp into an aware datetime.
    
      Tenable returns ISO 8601 with either whole seconds (2018-12-31T23:09:40Z) or
      fractional seconds (2024-01-16T15:12:47.334Z). Fractional digits are trimmed
      to microseconds because fromisoformat accepts at most six.
      """
      text = str(value).strip()
      if text.endswith('Z'):
        text = text[:-1] + '+00:00'
      text = re.sub(r'\.(\d{6})\d+', r'.\1', text)
      dt = datetime.fromisoformat(text)
      if dt.tzinfo is None:
        dt = dt.replace(tzinfo=timezone.utc)
      return dt.astimezone(timezone.utc)
    
    @functions_framework.cloud_event
    def main(cloud_event):
      """Fetch Tenable Vulnerability Management activity log events and write them to Cloud Storage.
    
      Args:
        cloud_event: CloudEvent object containing the Pub/Sub message.
      """
      if not all([GCS_BUCKET, TENABLE_ACCESS_KEY, TENABLE_SECRET_KEY]):
        # Raise rather than return: a bare return acks the Pub/Sub message and
        # reports the run as successful, silently discarding the schedule tick.
        raise RuntimeError('Missing required environment variables')
    
      bucket = storage_client.bucket(GCS_BUCKET)
      state = load_state(bucket, STATE_KEY)
    
      now = datetime.now(timezone.utc)
      watermark = None
      if state.get('last_event_time'):
        watermark = parse_datetime(state['last_event_time'])
      seen_ids = set(state.get('seen_ids', []))
    
      if watermark is None:
        start_time = now - timedelta(hours=LOOKBACK_HOURS)
      else:
        start_time = watermark - timedelta(minutes=OVERLAP_MINUTES)
    
      print(f"Fetching logs from {start_time.isoformat()} to {now.isoformat()}")
    
      # A FetchError propagates: the run fails, the watermark is untouched, and the
      # next invocation retries the same window.
      records, newest_event_time = fetch_logs(
        start_time=start_time,
        page_size=PAGE_SIZE,
        max_records=MAX_RECORDS,
      )
    
      # Drop events already written by an earlier run. Without this the overlap
      # window re-emits its events on every invocation, and an idle tenant has its
      # newest events rewritten to a new object every hour.
      fresh = [r for r in records if str(r.get('id', '')) not in seen_ids]
      print(f"Fetched {len(records)} records, {len(fresh)} new after deduplication")
    
      if not fresh:
        print("No new log records found. Watermark left unchanged.")
        return
    
      if not newest_event_time:
        raise FetchError('Records were returned but no `received` timestamp could be parsed')
    
      timestamp = now.strftime('%Y%m%dT%H%M%SZ')
      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 fresh) + '\n'
      blob.upload_from_string(ndjson, content_type='application/x-ndjson')
    
      print(f"Wrote {len(fresh)} records to gs://{GCS_BUCKET}/{object_key}")
    
      # Advance the watermark only after the data is durably written.
      new_watermark = parse_datetime(newest_event_time)
      if watermark and new_watermark < watermark:
        new_watermark = watermark
    
      # Retain only the ids still inside the overlap window, so the state file
      # stays small while covering every event the next query can re-read.
      cutoff = new_watermark - timedelta(minutes=OVERLAP_MINUTES)
      retained = []
      for record in records:
        received = record.get('received')
        if not received:
          continue
        try:
          if parse_datetime(received) >= cutoff:
            retained.append(str(record.get('id', '')))
        except ValueError:
          continue
    
      save_state(bucket, STATE_KEY, {
        'last_event_time': new_watermark.isoformat(),
        'seen_ids': sorted(i for i in set(retained) if i),
      })
    
      print(f"Successfully processed {len(fresh)} records")
    
    def load_state(bucket, key):
      """Read the collector state from Cloud Storage.
    
      Only a missing object is treated as a cold start. Any other error is raised:
      swallowing it would silently reset collection to the full lookback window and
      re-ingest that entire period.
      """
      blob = bucket.blob(key)
      try:
        return json.loads(blob.download_as_text())
      except NotFound:
        print('No state file found. Starting from the lookback window.')
        return {}
    
    def save_state(bucket, key, state: dict):
      """Write the collector state to Cloud Storage.
    
      Failures are raised, not logged. If the state write fails after the data was
      uploaded, the next run repeats the same window and duplicates it.
      """
      blob = bucket.blob(key)
      blob.upload_from_string(
        json.dumps(state, indent=2),
        content_type='application/json',
      )
      print(f"Saved state: last_event_time={state.get('last_event_time')}")
    
    def fetch_logs(start_time: datetime, page_size: int, max_records: int):
      """Fetch audit events from the Tenable Vulnerability Management API.
    
      Uses offset pagination, which is what the endpoint documents: the request
      accepts `limit` (maximum 10000) and `offset`, and the response `pagination`
      object returns `offset`, `limit`, `count` and `total`.
    
      Args:
        start_time: Exclusive lower bound for the `received` timestamp
        page_size: Records per page (the API accepts up to 10000)
        max_records: Maximum total records to fetch in one run
    
      Returns:
        Tuple of (records list, newest `received` value as an ISO 8601 string).
    
      Raises:
        FetchError: on any API or transport failure, so the caller cannot mistake
          a failed fetch for an empty result and advance the watermark.
      """
      endpoint = f"{TENABLE_API_BASE}/audit-log/v1/events"
    
      headers = {
        'X-ApiKeys': f'accessKey={TENABLE_ACCESS_KEY};secretKey={TENABLE_SECRET_KEY}',
        'Accept': 'application/json',
        'User-Agent': 'GoogleSecOps-TenableAuditCollector/1.0'
      }
    
      records = []
      newest_time = None
      page_num = 0
      backoff = 1.0
      rate_limit_retries = 0
      MAX_RATE_LIMIT_RETRIES = 5
      offset = 0
    
      while True:
        page_num += 1
    
        if len(records) >= max_records:
          # Stop cleanly. The remaining events stay ahead of the watermark and
          # are collected by the next run.
          print(f"Reached max_records limit ({max_records})")
          break
    
        # Every parameter is rebuilt per page. `sort=received:asc` is required:
        # a time watermark is only correct over an ascending scan, otherwise a
        # truncated run advances the watermark past events it never read.
        params = {
          'f': f'date.gt:{start_time.strftime("%Y-%m-%dT%H:%M:%SZ")}',
          'sort': 'received:asc',
          'limit': min(page_size, max_records - len(records)),
          'offset': offset,
        }
        url = f"{endpoint}?" + '&'.join(f"{k}={v}" for k, v in params.items())
    
        try:
          response = http.request('GET', url, headers=headers)
        except Exception as e:
          raise FetchError(f'Request to {endpoint} failed: {e}') from e
    
        if response.status == 429:
          rate_limit_retries += 1
          if rate_limit_retries > MAX_RATE_LIMIT_RETRIES:
            raise FetchError('Rate limited repeatedly; giving up without advancing the watermark')
          raw_retry_after = response.headers.get('Retry-After')
          try:
            # Retry-After may also be an HTTP date, which int() cannot parse.
            retry_after = int(raw_retry_after) if raw_retry_after else int(backoff)
          except (TypeError, ValueError):
            retry_after = 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
        rate_limit_retries = 0
    
        if response.status != 200:
          body = response.data.decode('utf-8')
          raise FetchError(f'HTTP {response.status} from the Tenable audit log API: {body}')
    
        try:
          data = json.loads(response.data.decode('utf-8'))
        except json.JSONDecodeError as e:
          raise FetchError(f'Malformed JSON response from the Tenable audit log API: {e}') from e
    
        page_results = data.get('events', [])
    
        if not page_results:
          print("No more results (empty page)")
          break
    
        print(f"Page {page_num}: Retrieved {len(page_results)} events")
        records.extend(page_results)
    
        for event in page_results:
          received = event.get('received')
          if not received:
            continue
          try:
            if newest_time is None or parse_datetime(received) > parse_datetime(newest_time):
              newest_time = received
          except ValueError as e:
            print(f"Warning: Could not parse event time {received!r}: {e}")
    
        offset += len(page_results)
        total = data.get('pagination', {}).get('total')
        if total is not None and offset >= total:
          print("No more pages (all matching events retrieved)")
          break
    
      print(f"Retrieved {len(records)} total records from {page_num} pages")
      return records, newest_time
    

    • Zweite Datei – requirements.txt:
    functions-framework==3.*
    google-cloud-storage==2.*
    urllib3>=2.0.0
    
  3. Klicken Sie auf Bereitstellen, um die Funktion zu speichern und bereitzustellen.

  4. Warten Sie, bis die Bereitstellung abgeschlossen ist (2–3 Minuten).

Cloud Scheduler-Job erstellen

Cloud Scheduler veröffentlicht in regelmäßigen Abständen Nachrichten im Pub/Sub-Thema und löst so die Cloud Run-Funktion aus.

  1. Rufen Sie in der GCP Console die Option Cloud Scheduler auf.
  2. Klicken Sie auf Job erstellen.
  3. Geben Sie die folgenden Konfigurationsdetails an:

    Einstellung Wert
    Name tenable-audit-collector-hourly
    Region Wählen Sie dieselbe Region wie für die Cloud Run-Funktion aus.
    Frequenz 0 * * * * (stündlich zur vollen Stunde)
    Zeitzone Zeitzone auswählen (UTC empfohlen)
    Zieltyp Pub/Sub
    Thema Wählen Sie das Thema tenable-audit-trigger aus.
    Inhalt der Nachricht {} (leeres JSON-Objekt)
  4. Klicken Sie auf Erstellen.

Optionen für die Häufigkeit des Zeitplans

Wählen Sie die Häufigkeit basierend auf dem Logvolumen und den Latenzanforderungen aus:

Häufigkeit Cron-Ausdruck Anwendungsfall
Alle 5 Minuten */5 * * * * Hohes Volumen, niedrige Latenz
Alle 15 Minuten */15 * * * * Mittleres Suchvolumen
Stündlich 0 * * * * Standard (empfohlen)
Alle 6 Stunden 0 */6 * * * Batchverarbeitung mit geringem Volumen
Täglich 0 0 * * * Erhebung von Verlaufsdaten

Integration testen

  1. Suchen Sie in der Cloud Scheduler-Konsole nach Ihrem Job.
  2. Klicken Sie auf Ausführung erzwingen, um den Job manuell auszulösen.
  3. Warte einige Sekunden.
  4. Rufen Sie Cloud Run > Dienste auf.
  5. Klicken Sie auf tenable-audit-collector.
  6. Klicken Sie auf den Tab Logs.
  7. Prüfen Sie, ob die Funktion erfolgreich ausgeführt wurde. Achte dabei auf Folgendes:

    Fetching logs from YYYY-MM-DDTHH:MM:SS+00:00 to YYYY-MM-DDTHH:MM:SS+00:00
    Page 1: Retrieved X events
    Fetched X records, Y new after deduplication
    Wrote Y records to gs://tenable-audit-logs/tenable/logs_YYYYMMDDTHHMMSSZ.ndjson
    Saved state: last_event_time=YYYY-MM-DDTHH:MM:SS+00:00
    Successfully processed Y records
    
  8. Rufen Sie Cloud Storage > Buckets auf.

  9. Klicken Sie auf den Namen Ihres Buckets (tenable-audit-logs).

  10. Rufen Sie den Ordner tenable/ auf.

  11. Prüfen Sie, ob eine neue .ndjson-Datei mit dem aktuellen Zeitstempel erstellt wurde.

Wenn bei einer Ausführung nichts Neues eingegangen ist, protokolliert die Funktion No new log records found. Watermark left unchanged. und schreibt kein Objekt. Das ist normal: Wenn dieselben Ereignisse noch einmal geschrieben würden, würden sie in Google SecOps dupliziert werden.

Wenn Sie Fehler in den Logs sehen:

  • HTTP 401: API-Schlüssel in Umgebungsvariablen prüfen
  • HTTP 403: Das Konto ist kein Administratorkonto. Für den Endpunkt des Aktivitätsprotokolls ist die Nutzerrolle „Administrator“ [64] erforderlich.
  • HTTP 429: Ratenbegrenzung. Die Funktion versucht es mit Backoff noch einmal und schlägt dann fehl, ohne den Wasserzeichenwert zu erhöhen. Es werden also keine Ereignisse übersprungen.
  • Fehlende Umgebungsvariablen: Prüfen Sie, ob alle erforderlichen Variablen festgelegt sind.

Feed in Google SecOps konfigurieren, um Tenable-Audit-Logs aufzunehmen

  1. Rufen Sie die Einstellungen > Datenverwaltung > Feeds auf. Wenn Sie eine reine SIEM-Plattform verwenden, rufen Sie die Einstellungen > Feeds auf.
  2. Klicken Sie auf Neuen Feed hinzufügen.
  3. Klicken Sie auf Einzelnen Feed konfigurieren.
  4. Geben Sie im Feld Feedname einen Namen für den Feed ein, z. B. Tenable Audit Logs.
  5. Wählen Sie Google Cloud Storage V2 als Quelltyp aus.
  6. Wählen Sie Tenable Audit als Logtyp aus.
  7. Klicken Sie auf Dienstkonto abrufen. Eine eindeutige E-Mail-Adresse für das Dienstkonto wird angezeigt, z. B.:

    chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com
    
  8. Kopieren Sie diese E-Mail-Adresse.

  9. Klicken Sie auf Weiter.

  10. Geben Sie Werte für die folgenden Eingabeparameter an:

    • Storage-Bucket-URL: Geben Sie den Cloud Storage-Bucket-URI mit dem Präfixpfad ein:

      gs://tenable-audit-logs/tenable/
      
      • Ersetzen Sie:
        • tenable-audit-logs: Name Ihres Cloud Storage-Bucket.
        • tenable: Optionaler Präfix-/Ordnerpfad, in dem Logs gespeichert werden (leer lassen für Stammverzeichnis).
    • Option zum Löschen der Quelle: Wählen Sie die gewünschte Löschoption aus:

      • Dateien nie löschen: Dateien werden nie aus der Quelle gelöscht (empfohlen für Tests).
      • Übertragene Dateien und leere Verzeichnisse löschen: Dateien und leere Verzeichnisse werden nach einem erfolgreichen Abruf aus der Quelle gelöscht.

    • Maximales Dateialter: Dateien einschließen, die in den letzten Tagen geändert wurden (Standardwert: 180 Tage)

    • Asset-Namespace: Der Asset-Namespace

    • Labels für Datenaufnahme: Das Label, das auf die Ereignisse aus diesem Feed angewendet werden soll.

  11. Klicken Sie auf Weiter.

  12. Prüfen Sie die neue Feedkonfiguration auf dem Bildschirm Abschließen und klicken Sie dann auf Senden.

Dem Google SecOps-Dienstkonto IAM-Berechtigungen gewähren

Das Google SecOps-Dienstkonto benötigt zwei Rollen für Ihren Cloud Storage-Bucket: Storage-Objekt-Betrachter zum Lesen der Logobjekte und eine Rolle auf Bucket-Ebene zum Lesen der Bucket-Metadaten.

  1. Rufen Sie Cloud Storage > Buckets auf.
  2. Klicken Sie auf den Namen Ihres Buckets.
  3. Wechseln Sie zum Tab Berechtigungen.
  4. Klicken Sie auf Zugriff erlauben.
  5. Geben Sie die folgenden Konfigurationsdetails an:
    • Hauptkonten hinzufügen: Fügen Sie die E‑Mail-Adresse des Google SecOps-Dienstkontos ein.
    • Rollen zuweisen: Wählen Sie die beiden folgenden Rollen aus:
      • Storage-Objekt-Betrachter: Liest die Logobjekte.
      • Storage Legacy Bucket Reader: Liest die Bucket-Metadaten. Wenn Sie die Löschoption Übertragene Dateien und leere Verzeichnisse löschen ausgewählt haben, wählen Sie stattdessen Storage Legacy Bucket Writer aus. Dadurch wird auch die Löschberechtigung gewährt.
  6. Klicken Sie auf Speichern.

UDM-Zuordnungstabelle

Logfeld UDM-Zuordnung Logik
crud_label additional.fields Zusammengeführt
fields_label additional.fields Zusammengeführt
field_name extensions.auth.mechanism Zugeordnet: X-Access-Type → mech_label
mech_label extensions.auth.mechanism Zusammengeführt
extension_value extensions.auth.type Direkt zugeordnet
description metadata.description Direkt zugeordnet
received metadata.event_timestamp Geparst als ISO8601
has_principal metadata.event_type Zugeordnete Werte (insgesamt 5, z.B. true → USER_LOGIN, true → USER_CREATION, true → `USER...
has_user metadata.event_type Zugeordnet: true → USER_UNCATEGORIZED
action metadata.product_event_type Direkt zugeordnet
id metadata.product_log_id Direkt zugeordnet
field_name principal.asset.ip Zugeordnet: X-Forwarded-For → ip
ip principal.asset.ip Zusammengeführt
field_name principal.ip Zugeordnet: X-Forwarded-For → ip
ip principal.ip Zusammengeführt
actor.name principal.user.email_addresses Zusammengeführt
actor.id principal.user.userid Direkt zugeordnet
AUTH_VIOLOATION security_result.category Zusammengeführt
is_failure security_result.category Zugeordnet: true → AUTH_VIOLOATION
is_anonymous_label security_result.detection_fields Zusammengeführt
is_failure_label security_result.detection_fields Zusammengeführt
target1.name target.user.email_addresses Zusammengeführt
target1.type target.user.role_name Direkt zugeordnet
target1.id target.user.userid Direkt zugeordnet
– extensions.auth.type Konstante: AUTHTYPE_UNSPECIFIED
– metadata.event_type Konstante: USER_LOGIN
– metadata.product_name Konstante: TENABLE AUDIT
– metadata.vendor_name Konstante: TENABLE

Änderungsprotokoll

Änderungsprotokoll für diesen Parser ansehen

Benötigen Sie weitere Hilfe? Antworten von Community-Mitgliedern und Google SecOps-Experten erhalten