Raccogli i log di Oracle NetSuite - NetSuite Applications Suite

Supportato in:

Questo documento spiega come importare i log di Oracle NetSuite - NetSuite Applications Suite in Google Security Operations utilizzando Google Cloud Storage V2.

Oracle NetSuite è una piattaforma di pianificazione delle risorse aziendali (ERP) basata su cloud che fornisce funzionalità complete di gestione aziendale, tra cui gestione finanziaria, gestione dei rapporti con i clienti (CRM), e-commerce e gestione dell'inventario. NetSuite genera audit log estesi, tra cui tracce di accesso degli utenti, note di sistema che monitorano le modifiche ai record e log di accesso alle API che possono essere recuperati tramite l'API REST SuiteQL per il monitoraggio della sicurezza e la conformità.

Prima di iniziare

Assicurati di soddisfare i seguenti prerequisiti:

  • Un'istanza Google SecOps
  • Un progetto GCP con le API Cloud Storage, Cloud Run, Pub/Sub e Cloud Scheduler abilitate
  • Autorizzazioni per creare e gestire bucket GCS
  • Autorizzazioni per gestire le policy IAM sui bucket GCS
  • Autorizzazioni per creare servizi Cloud Run, argomenti Pub/Sub e job Cloud Scheduler
  • Un account NetSuite con accesso amministrativo
  • Servizi web REST di NetSuite abilitati
  • Autorizzazioni per creare record di integrazione e token di accesso in NetSuite

Configurare l'accesso all'API NetSuite

Per abilitare la raccolta dei log tramite l'API REST SuiteQL, devi abilitare i servizi web REST, creare un record di integrazione e generare le credenziali di autenticazione basata su token (TBA) in NetSuite.

Abilita le funzionalità NetSuite richieste

  1. Accedi al tuo account NetSuite come amministratore.
  2. Vai a Setup > Company > Enable Features.
  3. Fai clic sulla scheda SuiteCloud.
  4. Nella sezione SuiteScript, seleziona le seguenti caselle:
    • Client SuiteScript
    • Server SuiteScript
  5. Nella sezione SuiteTalk (servizi web), seleziona la seguente casella:
    • Servizi web REST
  6. Nella sezione Gestisci autenticazione, seleziona la casella Autenticazione basata su token.
  7. Fai clic su Accetto nella pagina Termini di servizio di SuiteCloud.
  8. Fai clic su Salva.

Crea un record di integrazione

  1. In NetSuite, vai a Setup (Configurazione) > Integration (Integrazione) > Manage Integrations (Gestisci integrazioni) > New (Nuova).
  2. Nel campo Nome, inserisci Google SecOps Integration.
  3. Nel campo Descrizione, inserisci Integration for Google Security Operations log collection.
  4. Nel campo Stato, lascia selezionata l'opzione predefinita Abilitato.
  5. Fai clic sulla scheda Authentication (Autenticazione).
  6. Nella sezione Autenticazione basata su token, seleziona la casella Autenticazione basata su token.
  7. Lascia deselezionata la casella TBA: Authorization Flow (TBA: Authorization Flow).
  8. Seleziona la casella TBA: ISSUETOKEN ENDPOINT.
  9. Fai clic su Salva.
  10. Nella pagina di conferma, copia e salva la chiave utente/Client ID e il Consumer Secret/Client Secret.

Creare un ruolo personalizzato per l'accesso API

  1. Vai a Setup (Configurazione) > Users/Roles (Utenti/Ruoli) > Manage Roles (Gestisci ruoli) > New (Nuovo).
  2. Nel campo Nome, inserisci Google SecOps API Role.
  3. Nel campo ID, inserisci google_secops_api_role.
  4. Fai clic sulla scheda secondaria Autorizzazioni.
  5. Fai clic sulla scheda secondaria Configurazione.
  6. Aggiungi le seguenti autorizzazioni con livello di accesso Completo:
    • Accedere utilizzando i token di accesso
    • Token di accesso utente
    • Servizi web REST
  7. Fai clic sulla sottoscheda Report.
  8. Aggiungi le seguenti autorizzazioni con il livello di accesso Visualizza:
    • SuiteAnalytics Workbook
  9. Fai clic sulla sottoscheda Elenchi.
  10. Aggiungi le seguenti autorizzazioni con il livello di accesso Visualizza:
    • Audit trail degli accessi
  11. Fai clic su Salva.

Assegnare il ruolo a un utente

  1. Vai a Lists (Elenchi) > Employees (Dipendenti) > Employees (Dipendenti).
  2. Seleziona l'account utente da utilizzare per l'integrazione (o crea un nuovo utente di integrazione dedicato).
  3. Fai clic su Modifica.
  4. Fai clic sulla scheda Accesso.
  5. Nella sezione Ruoli, fai clic su Aggiungi.
  6. Seleziona Ruolo API Google SecOps dall'elenco a discesa.
  7. Fai clic su Salva.

Crea un token di accesso

  1. Accedi a NetSuite come utente a cui è stato assegnato il ruolo API Google SecOps.
  2. Vai a Configurazione > Utenti/Ruoli > Token di accesso > Nuovo.
  3. Nella pagina Token di accesso:
    • Nell'elenco a discesa Nome applicazione, seleziona Integrazione di Google SecOps.
    • Nell'elenco a discesa Utente, seleziona l'account utente a cui è stato assegnato il ruolo API Google SecOps.
    • Nell'elenco a discesa Ruolo, seleziona Ruolo API Google SecOps.
    • Il campo Nome token viene compilato automaticamente. Se preferisci, puoi modificarlo.
  4. Fai clic su Salva.
  5. Nella pagina di conferma, copia e salva l'ID token e il segreto del token.

Trovare l'ID account NetSuite

  1. In NetSuite, vai a Configurazione > Azienda > Informazioni sull'azienda.
  2. Individua il campo ID account (visualizzato sotto l'impostazione Fuso orario).
  3. Copia e salva il tuo ID account (ad esempio, 1234567 o 1234567_SB1 per gli account sandbox).

Verifica le autorizzazioni

Per verificare che l'account disponga delle autorizzazioni richieste:

  1. Accedi a NetSuite con l'utente a cui è stato assegnato il ruolo API Google SecOps.
  2. Vai a Configurazione > Utenti/Ruoli > Visualizza audit trail di accesso.
  3. Se riesci a visualizzare la pagina Traccia audit degli accessi, l'account dispone delle autorizzazioni necessarie.
  4. Se non riesci a visualizzare questa opzione, contatta l'amministratore di NetSuite per concedere l'autorizzazione Traccia di audit accesso nella sottoscheda Elenchi.

Testare l'accesso API

  • Testa le tue credenziali prima di procedere con l'integrazione:

    # Replace with your actual values
    ACCOUNT_ID="your-account-id"
    
    # Replace underscores with hyphens in the account ID for the URL
    # For example: 1234567_SB1 becomes 1234567-sb1
    URL_ACCOUNT_ID=$(echo "$ACCOUNT_ID" | tr '_' '-' | tr '[:upper:]' '[:lower:]')
    
    CONSUMER_KEY="your-consumer-key"
    CONSUMER_SECRET="your-consumer-secret"
    TOKEN_ID="your-token-id"
    TOKEN_SECRET="your-token-secret"
    
    # Test SuiteQL API access using OAuth 1.0 TBA
    # Note: This example requires the oauth1 CLI tool or Postman.
    # Use the following endpoint and headers to verify connectivity:
    # POST https://${URL_ACCOUNT_ID}.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql?limit=5
    # Headers:
    #   Authorization: OAuth (with consumer key, token, HMAC-SHA256 signature)
    #   Content-Type: application/json
    #   Prefer: transient
    # Body: {"q": "SELECT id, date, status, user, emailaddress FROM LoginAudit ORDER BY date DESC"}
    

Una risposta positiva restituisce un oggetto JSON contenente i record LoginAudit.

Crea un bucket Google Cloud Storage

  1. Vai alla console Google Cloud.
  2. Seleziona il tuo progetto o creane uno nuovo.
  3. Nel menu di navigazione, vai a Cloud Storage > Bucket.
  4. Fai clic su Crea bucket.
  5. Fornisci i seguenti dettagli di configurazione:

    Impostazione Valore
    Assegna un nome al bucket Inserisci un nome globalmente univoco (ad esempio netsuite-audit-logs)
    Tipo di località Scegli in base alle tue esigenze (regione singola, a due regioni, multiregionale)
    Località Seleziona la posizione (ad esempio, us-central1).
    Classe di archiviazione Standard (consigliato per i log a cui si accede di frequente)
    Controllo dell'accesso Uniforme (consigliato)
    Strumenti di protezione (Facoltativo) Abilita il controllo delle versioni degli oggetti o la policy di conservazione
  6. Fai clic su Crea.

Crea un account di servizio per la funzione Cloud Run

La funzione Cloud Run richiede un account di servizio con autorizzazioni di scrittura nel bucket GCS e di invocazione da parte di Pub/Sub.

Crea service account

  1. Nella console Google Cloud, vai a IAM e amministrazione > Service account.
  2. Fai clic su Crea account di servizio.
  3. Fornisci i seguenti dettagli di configurazione:
    • Nome del service account: inserisci netsuite-audit-collector-sa
    • Descrizione service account: inserisci Service account for Cloud Run function to collect NetSuite audit logs
  4. Fai clic su Crea e continua.
  5. Nella sezione Concedi a questo account di servizio l'accesso al progetto, aggiungi i seguenti ruoli:
    1. Fai clic su Seleziona un ruolo.
    2. Cerca e seleziona Storage Object Admin.
    3. Fai clic su + Aggiungi un altro ruolo.
    4. Cerca e seleziona Cloud Run Invoker.
    5. Fai clic su + Aggiungi un altro ruolo.
    6. Cerca e seleziona Cloud Functions Invoker.
  6. Fai clic su Continua.
  7. Fai clic su Fine.

Questi ruoli sono obbligatori per:

  • Storage Object Admin: scrive i log nel bucket GCS e gestisce i file di stato
  • Cloud Run Invoker: consente a Pub/Sub di richiamare la funzione
  • Cloud Functions Invoker: consente la chiamata della funzione

Concedi autorizzazioni IAM sul bucket GCS

  1. Vai a Cloud Storage > Bucket.
  2. Fai clic sul nome del bucket (netsuite-audit-logs).
  3. Vai alla scheda Autorizzazioni.
  4. Fai clic su Concedi l'accesso.
  5. Fornisci i seguenti dettagli di configurazione:
    • Aggiungi entità: inserisci l'email del account di servizio (netsuite-audit-collector-sa@PROJECT_ID.iam.gserviceaccount.com).
    • Assegna i ruoli: seleziona Storage Object Admin.
  6. Fai clic su Salva.

Crea argomento Pub/Sub

  1. Nella console Google Cloud, vai a Pub/Sub > Argomenti.
  2. Fai clic su Crea argomento.
  3. Fornisci i seguenti dettagli di configurazione:
    • ID argomento: inserisci netsuite-audit-trigger
    • Lascia invariate le altre impostazioni predefinite.
  4. Fai clic su Crea.

Crea una funzione Cloud Run per raccogliere i log

La funzione Cloud Run verrà attivata dai messaggi Pub/Sub di Cloud Scheduler per recuperare i log dall'API REST SuiteQL di NetSuite e scriverli in GCS.

  1. Nella console Google Cloud, vai a Cloud Run.
  2. Fai clic su Crea servizio.
  3. Seleziona Funzione (utilizza la modifica in linea per creare una funzione).
  4. Nella sezione Configura, fornisci i seguenti dettagli di configurazione:

    Impostazione Valore
    Nome servizio netsuite-audit-collector
    Regione Seleziona la regione corrispondente al tuo bucket GCS (ad esempio, us-central1)
    Tempo di esecuzione Seleziona Python 3.12 o versioni successive
  5. Nella sezione Trigger (facoltativo):

    1. Fai clic su + Aggiungi trigger.
    2. Seleziona Cloud Pub/Sub.
    3. In Seleziona un argomento Cloud Pub/Sub, scegli netsuite-audit-trigger.
    4. Fai clic su Salva.
  6. Nella sezione Autenticazione:

    1. Seleziona Richiedi autenticazione.
    2. Controlla Identity and Access Management (IAM).
  7. Scorri verso il basso ed espandi Container, networking, sicurezza.

  8. Vai alla scheda Sicurezza:

    • Service account: seleziona netsuite-audit-collector-sa.
  9. Vai alla scheda Container:

    1. Fai clic su Variabili e secret.
    2. Fai clic su + Aggiungi variabile per ogni variabile di ambiente:
    Nome variabile Valore di esempio Descrizione
    GCS_BUCKET netsuite-audit-logs Nome bucket GCS
    GCS_PREFIX netsuite-audit Prefisso per i file di log
    STATE_KEY netsuite-audit/state.json Percorso file di stato
    NS_ACCOUNT_ID 1234567 ID account NetSuite
    NS_CONSUMER_KEY your-consumer-key Chiave utente dal record di integrazione
    NS_CONSUMER_SECRET your-consumer-secret Secret consumer dal record di integrazione
    NS_TOKEN_ID your-token-id ID token dal token di accesso
    NS_TOKEN_SECRET your-token-secret Secret del token dal token di accesso
    MAX_RECORDS 10000 Numero massimo di record per esecuzione
    PAGE_SIZE 1000 Record per pagina SuiteQL
    LOOKBACK_HOURS 24 Periodo di riferimento iniziale
  10. Nella sezione Variabili e secret, scorri verso il basso fino a Richieste:

    • Timeout richiesta: inserisci 600 secondi (10 minuti)
  11. Vai alla scheda Impostazioni:

    • Nella sezione Risorse:
      • Memoria: seleziona 512 MiB o un valore superiore.
      • CPU: seleziona 1
  12. Nella sezione Scalabilità della revisione:

    • Numero minimo di istanze: inserisci 0
    • Numero massimo di istanze: inserisci 100
  13. Fai clic su Crea.

  14. Attendi la creazione del servizio (1-2 minuti).

  15. Dopo aver creato il servizio, si aprirà automaticamente l'editor di codice incorporato.

Aggiungi codice per la funzione

  1. Inserisci main nel campo Entry point (Punto di ingresso).
  2. Nell'editor di codice incorporato, crea due file:

    • main.py:
    import functions_framework
    from google.cloud import storage
    import json
    import os
    import urllib3
    import hashlib
    import hmac
    import base64
    import time
    import secrets
    import urllib.parse
    from datetime import datetime, timezone, timedelta
    
    # Initialize HTTP client with timeouts
    http = urllib3.PoolManager(
      timeout=urllib3.Timeout(connect=10.0, read=60.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', 'netsuite-audit')
    STATE_KEY = os.environ.get('STATE_KEY', 'netsuite-audit/state.json')
    NS_ACCOUNT_ID = os.environ.get('NS_ACCOUNT_ID')
    NS_CONSUMER_KEY = os.environ.get('NS_CONSUMER_KEY')
    NS_CONSUMER_SECRET = os.environ.get('NS_CONSUMER_SECRET')
    NS_TOKEN_ID = os.environ.get('NS_TOKEN_ID')
    NS_TOKEN_SECRET = os.environ.get('NS_TOKEN_SECRET')
    MAX_RECORDS = int(os.environ.get('MAX_RECORDS', '10000'))
    PAGE_SIZE = int(os.environ.get('PAGE_SIZE', '1000'))
    LOOKBACK_HOURS = int(os.environ.get('LOOKBACK_HOURS', '24'))
    
    def get_netsuite_base_url(account_id):
      """Build the NetSuite REST API base URL from the account ID."""
      url_account = account_id.replace('_', '-').lower()
      return f"https://{url_account}.suitetalk.api.netsuite.com"
    
    def generate_oauth_header(method, url, account_id, consumer_key,
      consumer_secret, token_id, token_secret):
      """Generate OAuth 1.0 Authorization header using HMAC-SHA256."""
      timestamp = str(int(time.time()))
      nonce = secrets.token_hex(16)
    
      # Parse URL to separate base URL and query parameters
      parsed = urllib.parse.urlparse(url)
      base_url = f"{parsed.scheme}://{parsed.netloc}{parsed.path}"
      query_params = urllib.parse.parse_qs(parsed.query, keep_blank_values=True)
    
      # Build parameter string (OAuth params + query params)
      params = {
        'oauth_consumer_key': consumer_key,
        'oauth_token': token_id,
        'oauth_nonce': nonce,
        'oauth_timestamp': timestamp,
        'oauth_signature_method': 'HMAC-SHA256',
        'oauth_version': '1.0',
      }
      for key, values in query_params.items():
        params[key] = values[0]
    
      # Sort parameters and create parameter string
      sorted_params = sorted(params.items())
      param_string = '&'.join(
        f"{urllib.parse.quote(k, safe='')}={urllib.parse.quote(v, safe='')}"
        for k, v in sorted_params
      )
    
      # Create signature base string
      signature_base = (
        f"{method.upper()}&"
        f"{urllib.parse.quote(base_url, safe='')}&"
        f"{urllib.parse.quote(param_string, safe='')}"
      )
    
      # Create signing key
      signing_key = (
        f"{urllib.parse.quote(consumer_secret, safe='')}&"
        f"{urllib.parse.quote(token_secret, safe='')}"
      )
    
      # Generate HMAC-SHA256 signature
      signature = base64.b64encode(
        hmac.new(
          signing_key.encode('utf-8'),
          signature_base.encode('utf-8'),
          hashlib.sha256
        ).digest()
      ).decode('utf-8')
    
      # Build realm from account ID
      realm = account_id.replace('-', '_').upper()
    
      # Build Authorization header
      auth_header = (
        f'OAuth realm="{realm}",'
        f'oauth_consumer_key="{consumer_key}",'
        f'oauth_token="{token_id}",'
        f'oauth_nonce="{nonce}",'
        f'oauth_timestamp="{timestamp}",'
        f'oauth_signature_method="HMAC-SHA256",'
        f'oauth_version="1.0",'
        f'oauth_signature="{urllib.parse.quote(signature, safe="")}"'
      )
      return auth_header
    
    @functions_framework.cloud_event
    def main(cloud_event):
      """
      Cloud Run function triggered by Pub/Sub to fetch NetSuite
      LoginAudit logs via SuiteQL and write to GCS.
      """
      if not all([GCS_BUCKET, NS_ACCOUNT_ID, NS_CONSUMER_KEY,
        NS_CONSUMER_SECRET, NS_TOKEN_ID, NS_TOKEN_SECRET]):
        print('Error: Missing required environment variables')
        return
    
      try:
        bucket = storage_client.bucket(GCS_BUCKET)
        state = load_state(bucket)
        now = datetime.now(timezone.utc)
    
        if isinstance(state, dict) and state.get('last_event_time'):
          try:
            last_val = state['last_event_time']
            if last_val.endswith('Z'):
              last_val = last_val[:-1] + '+00:00'
            last_time = datetime.fromisoformat(last_val)
            last_time = last_time - timedelta(minutes=2)
          except Exception as e:
            print(f"Warning: Could not parse last_event_time: {e}")
            last_time = now - timedelta(hours=LOOKBACK_HOURS)
        else:
          last_time = now - timedelta(hours=LOOKBACK_HOURS)
    
        print(f"Fetching logs from {last_time.isoformat()} to {now.isoformat()}")
    
        records, newest_time = fetch_login_audit(last_time, now)
    
        if not records:
          print("No new log records found.")
          save_state(bucket, now.isoformat())
          return
    
        timestamp = now.strftime('%Y%m%d_%H%M%S')
        object_key = f"{GCS_PREFIX}/netsuite_audit_{timestamp}.ndjson"
        blob = bucket.blob(object_key)
    
        ndjson = '\n'.join(
          [json.dumps(r, ensure_ascii=False, default=str) for r in records]
        ) + '\n'
        blob.upload_from_string(ndjson, content_type='application/x-ndjson')
    
        print(f"Wrote {len(records)} records to gs://{GCS_BUCKET}/{object_key}")
    
        if newest_time:
          save_state(bucket, newest_time)
        else:
          save_state(bucket, now.isoformat())
    
        print(f"Successfully processed {len(records)} records")
    
      except Exception as e:
        print(f'Error processing logs: {str(e)}')
        raise
    
    def fetch_login_audit(start_time, end_time):
      """
      Fetch LoginAudit records from NetSuite SuiteQL API with pagination.
    
      Returns:
        Tuple of (records list, newest_event_time ISO string)
      """
      base_url = get_netsuite_base_url(NS_ACCOUNT_ID)
      suiteql_endpoint = f"{base_url}/services/rest/query/v1/suiteql"
    
      start_str = start_time.strftime('%Y-%m-%d %H:%M:%S')
      end_str = end_time.strftime('%Y-%m-%d %H:%M:%S')
    
      query = (
        "SELECT id, date, status, user, role, emailaddress, "
        "ipaddress, useragent, detail, requesturi, "
        "oauthaccesstokenname, oauthappname "
        "FROM LoginAudit "
        f"WHERE date BETWEEN TO_DATE('{start_str}', 'YYYY-MM-DD HH24:MI:SS') "
        f"AND TO_DATE('{end_str}', 'YYYY-MM-DD HH24:MI:SS') "
        "ORDER BY date ASC"
      )
    
      records = []
      newest_time = None
      offset = 0
      backoff = 1.0
    
      while True:
        if len(records) >= MAX_RECORDS:
          print(f"Reached max_records limit ({MAX_RECORDS})")
          break
    
        remaining = min(PAGE_SIZE, MAX_RECORDS - len(records))
        url = f"{suiteql_endpoint}?limit={remaining}&offset={offset}"
    
        auth_header = generate_oauth_header(
          'POST', url, NS_ACCOUNT_ID, NS_CONSUMER_KEY,
          NS_CONSUMER_SECRET, NS_TOKEN_ID, NS_TOKEN_SECRET
        )
    
        headers = {
          'Authorization': auth_header,
          'Content-Type': 'application/json',
          'Prefer': 'transient',
          'User-Agent': 'GoogleSecOps-NetSuiteCollector/1.0',
        }
    
        body = json.dumps({'q': query}).encode('utf-8')
    
        try:
          response = http.request('POST', url, headers=headers, body=body)
    
          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, 60.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 records, newest_time
    
          data = json.loads(response.data.decode('utf-8'))
    
          page_results = data.get('items', [])
    
          if not page_results:
            print("No more results (empty page)")
            break
    
          page_num = (offset // PAGE_SIZE) + 1
          print(f"Page {page_num}: Retrieved {len(page_results)} records")
          records.extend(page_results)
    
          for event in page_results:
            try:
              event_time = event.get('date')
              if event_time:
                if newest_time is None or event_time > newest_time:
                  newest_time = event_time
            except Exception as e:
              print(f"Warning: Could not parse event time: {e}")
    
          has_more = data.get('hasMore', False)
          if not has_more:
            print("Reached last page (hasMore=false)")
            break
    
          offset += len(page_results)
    
        except Exception as e:
          print(f"Error fetching logs: {e}")
          return records, newest_time
    
      print(f"Retrieved {len(records)} total records")
      return records, newest_time
    
    def load_state(bucket):
      """Load state from GCS."""
      try:
        blob = bucket.blob(STATE_KEY)
        if blob.exists():
          return json.loads(blob.download_as_text())
      except Exception as e:
        print(f"Warning: Could not load state: {e}")
      return {}
    
    def save_state(bucket, last_event_time_iso):
      """Save the last event timestamp to GCS state file."""
      try:
        state = {
          'last_event_time': last_event_time_iso,
          'last_run': datetime.now(timezone.utc).isoformat()
        }
        blob = bucket.blob(STATE_KEY)
        blob.upload_from_string(
          json.dumps(state, indent=2),
          content_type='application/json'
        )
        print(f"Saved state: last_event_time={last_event_time_iso}")
      except Exception as e:
        print(f"Warning: Could not save state: {e}")
    
    • requirements.txt:
    functions-framework==3.*
    google-cloud-storage==2.*
    urllib3>=2.0.0
    
  3. Fai clic su Esegui il deployment per salvare la funzione ed eseguirne il deployment.

  4. Attendi il completamento del deployment (2-3 minuti).

Crea job Cloud Scheduler

Cloud Scheduler pubblicherà messaggi nell'argomento Pub/Sub a intervalli regolari, attivando la funzione Cloud Run.

  1. Nella console Google Cloud, vai a Cloud Scheduler.
  2. Fai clic su Crea job.
  3. Fornisci i seguenti dettagli di configurazione:

    Impostazione Valore
    Nome netsuite-audit-collector-hourly
    Regione Seleziona la stessa regione della funzione Cloud Run
    Frequenza 0 * * * * (ogni ora, allo scoccare dell'ora)
    Fuso orario Seleziona il fuso orario (consigliato UTC)
    Tipo di target Pub/Sub
    Argomento Seleziona netsuite-audit-trigger
    Corpo del messaggio {} (oggetto JSON vuoto)
  4. Fai clic su Crea.

Opzioni di frequenza di pianificazione

Scegli la frequenza in base al volume dei log e ai requisiti di latenza:

Frequenza Espressione cron Caso d'uso
Ogni 5 minuti */5 * * * * Volume elevato, bassa latenza
Ogni 15 minuti */15 * * * * Volume medio
Ogni ora 0 * * * * Standard (consigliato)
Ogni 6 ore 0 */6 * * * Volume basso, elaborazione batch
Ogni giorno 0 0 * * * Raccolta dei dati storici

Testare l'integrazione

  1. Nella console Cloud Scheduler, individua il tuo job (netsuite-audit-collector-hourly).
  2. Fai clic su Forza esecuzione per attivare il job manualmente.
  3. Attendi alcuni secondi.
  4. Vai a Cloud Run > Servizi.
  5. Fai clic su netsuite-audit-collector.
  6. Fai clic sulla scheda Log.
  7. Verifica che la funzione sia stata eseguita correttamente. Cerca:

    Fetching logs from YYYY-MM-DDTHH:MM:SS+00:00 to YYYY-MM-DDTHH:MM:SS+00:00
    Page 1: Retrieved X records
    Wrote X records to gs://netsuite-audit-logs/netsuite-audit/netsuite_audit_YYYYMMDD_HHMMSS.ndjson
    Successfully processed X records
    
  8. Vai a Cloud Storage > Bucket.

  9. Fai clic su netsuite-audit-logs.

  10. Vai alla cartella netsuite-audit/.

  11. Verifica che sia stato creato un nuovo file .ndjson con il timestamp corrente.

Se nei log vengono visualizzati errori:

  • HTTP 401: verifica che le credenziali OAuth (NS_CONSUMER_KEY, NS_CONSUMER_SECRET, NS_TOKEN_ID, NS_TOKEN_SECRET) e le variabili di ambiente NS_ACCOUNT_ID siano corrette
  • HTTP 403: verifica che il ruolo NetSuite disponga delle autorizzazioni richieste (servizi web REST, traccia di audit di accesso, cartella di lavoro SuiteAnalytics)
  • HTTP 429: limitazione di frequenza. La funzione riproverà automaticamente con backoff esponenziale
  • Variabili di ambiente mancanti: verifica che tutte le variabili richieste siano impostate nella configurazione della funzione Cloud Run

Recuperare il account di servizio Google SecOps

  1. Vai a Impostazioni SIEM > Feed.
  2. Fai clic su Aggiungi nuovo feed di notizie.
  3. Fai clic su Configura un singolo feed.
  4. Nel campo Nome feed, inserisci un nome per il feed (ad esempio, NetSuite Audit Logs).
  5. Seleziona Google Cloud Storage V2 come Tipo di origine.
  6. Seleziona Oracle NetSuite - NetSuite Applications Suite come Tipo di log.
  7. Fai clic su Ottieni service account. Verrà visualizzato un indirizzo email del account di servizio univoco. Ad esempio:

    chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com
    
  8. Copia questo indirizzo email per utilizzarlo nel passaggio successivo.

  9. Fai clic su Avanti.

  10. Specifica i valori per i seguenti parametri di input:

    • URL del bucket di archiviazione: inserisci l'URI del bucket GCS con il percorso del prefisso:

      gs://netsuite-audit-logs/netsuite-audit/
      
    • Opzione di eliminazione dell'origine: seleziona l'opzione di eliminazione in base alle tue preferenze:
      • Mai: non elimina mai i file dopo i trasferimenti (opzione consigliata per i test).
      • Elimina file trasferiti: elimina i file dopo il trasferimento riuscito.
      • Elimina file trasferiti e directory vuote: elimina i file e le directory vuote dopo il trasferimento riuscito.
    • Età massima dei file: includi i file modificati negli ultimi giorni (il valore predefinito è 180 giorni)
    • Spazio dei nomi dell'asset: lo spazio dei nomi dell'asset
    • Etichette di importazione: l'etichetta da applicare agli eventi di questo feed
  11. Fai clic su Avanti.

  12. Controlla la nuova configurazione del feed nella schermata Finalizza e poi fai clic su Invia.

Concedi le autorizzazioni IAM al account di servizio Google SecOps

Il account di servizio Google SecOps deve avere il ruolo Visualizzatore oggetti Storage nel tuo bucket GCS.

  1. Vai a Cloud Storage > Bucket.
  2. Fai clic su netsuite-audit-logs.
  3. Vai alla scheda Autorizzazioni.
  4. Fai clic su Concedi l'accesso.
  5. Fornisci i seguenti dettagli di configurazione:
    • Aggiungi entità: incolla l'indirizzo email del account di servizio Google SecOps
    • Assegna i ruoli: seleziona Storage Object Viewer
  6. Fai clic su Salva.

Limiti di frequenza delle richieste API NetSuite

L'API NetSuite presenta i seguenti limiti di concorrenza e frequenza:

Tipo di limite Valore predefinito Note
Richieste in parallelo 15 richieste Valido per le richieste API SOAP e API REST combinate per account
Risultati della query SuiteQL Massimo 100.000 righe Numero massimo di righe restituite per query SuiteQL
Oggetti per richiesta Massimo 1000 oggetti Numero massimo di oggetti restituiti per richiesta API

La funzione Cloud Run gestisce automaticamente la limitazione di frequenza con backoff esponenziale. Se riscontri errori di limite di frequenza persistenti (HTTP 429), contatta l'assistenza NetSuite per aumentare i limiti API o modificare la frequenza di Cloud Scheduler.

Tabella di mappatura UDM

Campo log Mappatura UDM Logica
utente extensions.auth.type Tipo di meccanismo di autenticazione utilizzato
data metadata.event_timestamp Timestamp in cui si è verificato l'evento
event_type metadata.event_type Tipo di evento (ad es. USER_LOGIN, NETWORK_CONNECTION)
security_result security_result Dettagli sul risultato di sicurezza dell'evento
oauthaccesstokenname security_result.about.resource.attribute.labels Etichette coppia chiave-valore che descrivono gli attributi della risorsa coinvolta nel risultato di sicurezza
secchallenge security_result.about.resource.attribute.labels
stato security_result.summary Descrizione riepilogativa del risultato di sicurezza
oauthappname target.application Nome dell'applicazione di destinazione
useragent target.application
ipaddress target.ip Indirizzo IP del target
requesturi target.url URL della risorsa di destinazione
emailaddress target.user.email_addresses Indirizzi email associati all'utente di destinazione
ruolo target.user.role_name Nome del ruolo assegnato all'utente di destinazione
utente target.user.userid Identificatore univoco dell'utente di destinazione

Log delle modifiche

Visualizza il log delle modifiche per questo parser

Hai bisogno di ulteriore assistenza? Ricevi risposte dai membri della community e dai professionisti di Google SecOps.