Collecter les journaux Oracle NetSuite – NetSuite Applications Suite
Ce document explique comment ingérer les journaux Oracle NetSuite – NetSuite Applications Suite dans Google Security Operations à l'aide de Google Cloud Storage V2.
Oracle NetSuite est une plate-forme de planification des ressources d'entreprise (ERP) basée dans le cloud. Elle offre des fonctionnalités complètes de gestion d'entreprise, y compris la gestion financière, la gestion de la relation client (CRM), l'e-commerce et la gestion de l'inventaire. NetSuite génère des journaux d'audit complets, y compris les pistes de connexion des utilisateurs, les notes système qui suivent les modifications des enregistrements et les journaux d'accès à l'API, qui peuvent être récupérés via l'API REST SuiteQL à des fins de surveillance de la sécurité et de conformité.
Avant de commencer
Assurez-vous de remplir les conditions préalables suivantes :
- Une instance Google SecOps
- Un projet GCP avec les API Cloud Storage, Cloud Run, Pub/Sub et Cloud Scheduler activées
- Autorisations permettant de créer et de gérer des buckets GCS
- Autorisations permettant de gérer les stratégies IAM sur les buckets GCS
- Autorisations permettant de créer des services Cloud Run, des sujets Pub/Sub et des jobs Cloud Scheduler
- Un compte NetSuite avec accès administrateur
- Services Web REST NetSuite activés
- Autorisations permettant de créer des enregistrements d'intégration et des jetons d'accès dans NetSuite
Configurer l'accès à l'API NetSuite
Pour activer la collecte de journaux via l'API REST SuiteQL, vous devez activer les services Web REST, créer un enregistrement d'intégration et générer des identifiants d'authentification basée sur un jeton (TBA) dans NetSuite.
Activer les fonctionnalités NetSuite requises
- Connectez-vous à votre compte NetSuite en tant qu'administrateur.
- Accédez à Configuration> Société> Activer les fonctionnalités.
- Cliquez sur l'onglet SuiteCloud.
- Dans la section SuiteScript, cochez les cases suivantes :
- Client SuiteScript
- SuiteScript côté serveur
- Dans la section SuiteTalk (Web Services), cochez la case suivante :
- Services Web REST
- Dans la section Gérer l'authentification, cochez la case Authentification basée sur un jeton.
- Cliquez sur J'accepte sur la page des conditions d'utilisation de SuiteCloud.
- Cliquez sur Enregistrer.
Créer un enregistrement d'intégration
- Dans NetSuite, accédez à Setup> Integration> Manage Integrations> New (Configuration > Intégration > Gérer les intégrations > Nouveau).
- Dans le champ Nom, saisissez
Google SecOps Integration. - Dans le champ Description, saisissez
Integration for Google Security Operations log collection. - Dans le champ État, laissez l'option par défaut Activé sélectionnée.
- Cliquez sur l'onglet Authentification.
- Dans la section Authentification basée sur un jeton, cochez la case Authentification basée sur un jeton.
- Ne cochez pas la case TBA: Authorization Flow (À déterminer : flux d'autorisation).
- Cochez la case TBA: ISSUETOKEN ENDPOINT (À DÉTERMINER : POINT DE TERMINAISON ISSUETOKEN).
- Cliquez sur Enregistrer.
Sur la page de confirmation, copiez et enregistrez la clé client/ID client et le code secret du client.
Créer un rôle personnalisé pour l'accès à l'API
- Accédez à Configuration > Utilisateurs/Rôles > Gérer les rôles > Nouveau.
- Dans le champ Nom, saisissez
Google SecOps API Role. - Dans le champ ID, saisissez
google_secops_api_role. - Cliquez sur le sous-onglet Autorisations.
- Cliquez sur le sous-onglet Configuration.
- Ajoutez les autorisations suivantes avec le niveau d'accès Complet :
- Se connecter à l'aide de jetons d'accès
- Jetons d'accès utilisateur
- Services Web REST
- Cliquez sur le sous-onglet Rapports.
- Ajoutez les autorisations suivantes avec le niveau d'accès Afficher :
- SuiteAnalytics Workbook
- Cliquez sur le sous-onglet Listes.
- Ajoutez les autorisations suivantes avec le niveau d'accès Afficher :
- Piste d'audit des connexions
- Cliquez sur Enregistrer.
Attribuer le rôle à un utilisateur
- Accédez à Listes > Employés > Employés.
- Sélectionnez le compte utilisateur qui sera utilisé pour l'intégration (ou créez un compte utilisateur dédié à l'intégration).
- Cliquez sur Modifier.
- Cliquez sur l'onglet Accès.
- Dans la section Rôles, cliquez sur Ajouter.
- Sélectionnez Rôle d'API Google SecOps dans la liste déroulante.
- Cliquez sur Enregistrer.
Créer un jeton d'accès
- Connectez-vous à NetSuite en tant qu'utilisateur auquel le rôle d'API Google SecOps est attribué.
- Accédez à Configuration > Utilisateurs/Rôles > Jetons d'accès > Nouveau.
- Sur la page Jeton d'accès :
- Dans la liste déroulante Nom de l'application, sélectionnez Intégration Google SecOps.
- Dans la liste déroulante Utilisateur, sélectionnez le compte utilisateur auquel le rôle d'API Google SecOps est attribué.
- Dans la liste déroulante Rôle, sélectionnez Rôle de l'API Google SecOps.
- Le champ Nom du jeton est renseigné automatiquement. Vous pouvez le modifier si vous le souhaitez.
- Cliquez sur Enregistrer.
Sur la page de confirmation, copiez et enregistrez l'ID de jeton et le code secret du jeton.
Trouver votre ID de compte NetSuite
- Dans NetSuite, accédez à Setup> Company > Company Information (Configuration > Entreprise > Informations sur l'entreprise).
- Recherchez le champ ID de compte (affiché sous le paramètre Fuseau horaire).
- Copiez et enregistrez votre ID de compte (par exemple,
1234567ou1234567_SB1pour les comptes sandbox).
Vérifier les autorisations
Pour vérifier que le compte dispose des autorisations requises :
- Connectez-vous à NetSuite avec l'utilisateur auquel le rôle d'API Google SecOps a été attribué.
- Accédez à Configuration > Utilisateurs/Rôles > Afficher la piste d'audit des connexions.
- Si vous pouvez accéder à la page "Piste d'audit des connexions", cela signifie que le compte dispose des autorisations requises.
- Si vous ne voyez pas cette option, contactez votre administrateur NetSuite pour qu'il vous accorde l'autorisation Login Audit Trail (Piste d'audit des connexions) dans le sous-onglet Lists (Listes).
Tester l'accès à l'API
Testez vos identifiants avant de procéder à l'intégration :
# 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"}
Une réponse réussie renvoie un objet JSON contenant des enregistrements LoginAudit.
Créer un bucket Google Cloud Storage
- Accédez à la console Google Cloud.
- Sélectionnez votre projet ou créez-en un.
- Dans le menu de navigation, accédez à Cloud Storage > Buckets.
- Cliquez sur Créer un bucket.
Fournissez les informations de configuration suivantes :
Paramètre Valeur Attribuez un nom au bucket Saisissez un nom unique (par exemple, netsuite-audit-logs).Type d'emplacement Choisissez en fonction de vos besoins (région, birégion, multirégion). Emplacement Sélectionnez l'emplacement (par exemple, us-central1).Classe de stockage Standard (recommandé pour les journaux auxquels vous accédez fréquemment) Access control (Contrôle des accès) Uniforme (recommandé) Outils de protection Facultatif : Activez la gestion des versions des objets ou la règle de conservation. Cliquez sur Créer.
Créer un compte de service pour la fonction Cloud Run
La fonction Cloud Run a besoin d'un compte de service disposant des autorisations nécessaires pour écrire dans le bucket GCS et être appelée par Pub/Sub.
Créer un compte de service
- Dans la console GCP, accédez à IAM et administration > Comptes de service.
- Cliquez sur Créer un compte de service.
- Fournissez les informations de configuration suivantes :
- Nom du compte de service : saisissez
netsuite-audit-collector-sa. - Description du compte de service : saisissez
Service account for Cloud Run function to collect NetSuite audit logs.
- Nom du compte de service : saisissez
- Cliquez sur Créer et continuer.
- Dans la section Autoriser ce compte de service à accéder au projet, ajoutez les rôles suivants :
- Cliquez sur Sélectionner un rôle.
- Recherchez et sélectionnez Administrateur des objets Storage.
- Cliquez sur + Ajouter un autre rôle.
- Recherchez et sélectionnez Demandeur Cloud Run.
- Cliquez sur + Ajouter un autre rôle.
- Recherchez et sélectionnez Demandeur Cloud Functions.
- Cliquez sur Continuer.
- Cliquez sur OK.
Ces rôles sont requis pour :
- Administrateur des objets Storage : écrire des journaux dans un bucket GCS et gérer les fichiers d'état
- Demandeur Cloud Run : autorise Pub/Sub à appeler la fonction
- Demandeur Cloud Functions : autorise l'appel de fonctions
Accorder des autorisations IAM sur le bucket GCS
- Accédez à Cloud Storage > Buckets.
- Cliquez sur le nom de votre bucket (
netsuite-audit-logs). - Accédez à l'onglet Autorisations.
- Cliquez sur Accorder l'accès.
- Fournissez les informations de configuration suivantes :
- Ajouter des comptes principaux : saisissez l'adresse e-mail du compte de service (
netsuite-audit-collector-sa@PROJECT_ID.iam.gserviceaccount.com). - Attribuer des rôles : sélectionnez Administrateur des objets Storage.
- Ajouter des comptes principaux : saisissez l'adresse e-mail du compte de service (
- Cliquez sur Enregistrer.
Créer un sujet Pub/Sub
- Dans la console GCP, accédez à Pub/Sub > Sujets.
- Cliquez sur Créer un sujet.
- Fournissez les informations de configuration suivantes :
- ID du sujet : saisissez
netsuite-audit-trigger. - Conservez les valeurs par défaut des autres paramètres.
- ID du sujet : saisissez
- Cliquez sur Créer.
Créer une fonction Cloud Run pour collecter les journaux
La fonction Cloud Run sera déclenchée par les messages Pub/Sub de Cloud Scheduler pour extraire les journaux de l'API REST SuiteQL de NetSuite et les écrire dans GCS.
- Dans la console GCP, accédez à Cloud Run.
- Cliquez sur Créer un service.
- Sélectionnez Fonction (utilisez un éditeur de modification directe pour créer une fonction).
Dans la section Configurer, fournissez les informations de configuration suivantes :
Paramètre Valeur Nom du service netsuite-audit-collectorRégion Sélectionnez la région correspondant à votre bucket GCS (par exemple, us-central1).Durée d'exécution Sélectionnez Python 3.12 ou version ultérieure. Dans la section Déclencheur (facultatif) :
- Cliquez sur + Ajouter un déclencheur.
- Sélectionnez Cloud Pub/Sub.
- Dans Sélectionner un sujet Cloud Pub/Sub, choisissez
netsuite-audit-trigger. - Cliquez sur Enregistrer.
Dans la section Authentification :
- Sélectionnez Exiger l'authentification.
- Consultez Identity and Access Management (IAM).
Faites défiler la page vers le bas, puis développez Conteneurs, mise en réseau, sécurité.
Accédez à l'onglet Sécurité :
- Compte de service : sélectionnez
netsuite-audit-collector-sa.
- Compte de service : sélectionnez
Accédez à l'onglet Conteneurs :
- Cliquez sur Variables et secrets.
- Cliquez sur + Ajouter une variable pour chaque variable d'environnement :
Nom de la variable Exemple de valeur Description GCS_BUCKETnetsuite-audit-logsNom du bucket GCS GCS_PREFIXnetsuite-auditPréfixe des fichiers journaux STATE_KEYnetsuite-audit/state.jsonChemin d'accès au fichier d'état NS_ACCOUNT_ID1234567ID de compte NetSuite NS_CONSUMER_KEYyour-consumer-keyClé client issue de l'enregistrement de l'intégration NS_CONSUMER_SECRETyour-consumer-secretSecret client de l'enregistrement d'intégration NS_TOKEN_IDyour-token-idID de jeton à partir du jeton d'accès NS_TOKEN_SECRETyour-token-secretSecret du jeton d'accès MAX_RECORDS10000Nombre maximal d'enregistrements par exécution PAGE_SIZE1000Enregistrements par page SuiteQL LOOKBACK_HOURS24Période d'analyse initiale Dans la section Variables et secrets, faites défiler la page jusqu'à Requêtes :
- Délai avant expiration de la requête : saisissez
600secondes (10 minutes).
- Délai avant expiration de la requête : saisissez
Accédez à l'onglet Paramètres :
- Dans la section Ressources :
- Mémoire : sélectionnez 512 Mio ou plus.
- CPU : sélectionnez 1.
- Dans la section Ressources :
Dans la section Scaling de révision :
- Nombre minimal d'instances : saisissez
0. - Nombre maximal d'instances : saisissez
100.
- Nombre minimal d'instances : saisissez
Cliquez sur Créer.
Attendez que le service soit créé (une à deux minutes).
Une fois le service créé, l'éditeur de code intégré s'ouvre automatiquement.
Ajouter un code de fonction
- Saisissez main dans le champ Point d'entrée.
Dans l'éditeur de code intégré, créez deux fichiers :
- 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.0Cliquez sur Déployer pour enregistrer et déployer la fonction.
Attendez la fin du déploiement (deux à trois minutes).
Créer une tâche Cloud Scheduler
Cloud Scheduler publiera des messages dans le sujet Pub/Sub à intervalles réguliers, ce qui déclenchera la fonction Cloud Run.
- Dans la console GCP, accédez à Cloud Scheduler.
- Cliquez sur Créer une tâche.
Fournissez les informations de configuration suivantes :
Paramètre Valeur Nom netsuite-audit-collector-hourlyRégion Sélectionnez la même région que la fonction Cloud Run. Fréquence 0 * * * *(toutes les heures, à l'heure pile)Fuseau horaire Sélectionnez un fuseau horaire (UTC recommandé) Type de cible Pub/Sub Sujet Sélectionner netsuite-audit-triggerCorps du message {}(objet JSON vide)Cliquez sur Créer.
Options de fréquence de programmation
Choisissez la fréquence en fonction du volume de journaux et des exigences de latence :
| Fréquence | Expression Cron | Cas d'utilisation |
|---|---|---|
| Toutes les 5 minutes | */5 * * * * |
Volume élevé, faible latence |
| Toutes les 15 minutes | */15 * * * * |
Volume moyen |
| Toutes les heures | 0 * * * * |
Standard (recommandé) |
| Toutes les 6 heures | 0 */6 * * * |
Traitement par lot à faible volume |
| Tous les jours | 0 0 * * * |
Collecte de données historiques |
Tester l'intégration
- Dans la console Cloud Scheduler, recherchez votre job (
netsuite-audit-collector-hourly). - Cliquez sur Exécuter de force pour déclencher le job manuellement.
- Patientez quelques secondes.
- Accédez à Cloud Run > Services.
- Cliquez sur
netsuite-audit-collector. - Cliquez sur l'onglet Journaux.
Vérifiez que la fonction s'est exécutée correctement. Par exemple :
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 recordsAccédez à Cloud Storage > Buckets.
Cliquez sur
netsuite-audit-logs.Accédez au dossier
netsuite-audit/.Vérifiez qu'un nouveau fichier
.ndjsona été créé avec le code temporel actuel.
Si des erreurs s'affichent dans les journaux :
- HTTP 401 : vérifiez que les identifiants OAuth (
NS_CONSUMER_KEY,NS_CONSUMER_SECRET,NS_TOKEN_ID,NS_TOKEN_SECRET) et les variables d'environnementNS_ACCOUNT_IDsont corrects. - HTTP 403 : vérifiez que le rôle NetSuite dispose des autorisations requises (services Web REST, piste d'audit de connexion, classeur SuiteAnalytics).
- HTTP 429 : limitation du débit. La fonction effectuera automatiquement une nouvelle tentative avec un intervalle exponentiel entre les tentatives.
- Variables d'environnement manquantes : vérifiez que toutes les variables requises sont définies dans la configuration de la fonction Cloud Run.
Récupérer le compte de service Google SecOps
- Accédez à Paramètres SIEM> Flux.
- Cliquez sur Ajouter un flux.
- Cliquez sur Configurer un flux unique.
- Dans le champ Nom du flux, saisissez un nom pour le flux (par exemple,
NetSuite Audit Logs). - Sélectionnez Google Cloud Storage V2 comme Type de source.
- Sélectionnez Oracle NetSuite – Suite d'applications NetSuite comme Type de journal.
Cliquez sur Obtenir un compte de service. Une adresse e-mail de compte de service unique s'affiche. Exemple :
chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.comCopiez cette adresse e-mail pour l'utiliser à l'étape suivante.
Cliquez sur Suivant.
Spécifiez les valeurs des paramètres d'entrée suivants :
URL du bucket de stockage : saisissez l'URI du bucket GCS avec le chemin d'accès du préfixe :
gs://netsuite-audit-logs/netsuite-audit/
- Option de suppression de la source : sélectionnez l'option de suppression de votre choix :
- Jamais : ne supprime jamais aucun fichier après les transferts (recommandé pour les tests).
- Supprimer les fichiers transférés : supprime les fichiers une fois le transfert réussi.
- Supprimer les fichiers transférés et les répertoires vides : supprime les fichiers et les répertoires vides une fois le transfert réussi.
- Âge maximal du fichier : incluez les fichiers modifiés au cours d'un certain nombre de jours (180 jours par défaut).
- Espace de noms de l'élément : espace de noms de l'élément
- Étiquettes d'ingestion : étiquette à appliquer aux événements de ce flux
Cliquez sur Suivant.
Vérifiez la configuration de votre nouveau flux sur l'écran Finaliser, puis cliquez sur Envoyer.
Accorder des autorisations IAM au compte de service Google SecOps
Le compte de service Google SecOps a besoin du rôle Lecteur des objets Storage sur votre bucket GCS.
- Accédez à Cloud Storage > Buckets.
- Cliquez sur
netsuite-audit-logs. - Accédez à l'onglet Autorisations.
- Cliquez sur Accorder l'accès.
- Fournissez les informations de configuration suivantes :
- Ajouter des comptes principaux : collez l'adresse e-mail du compte de service Google SecOps.
- Attribuer des rôles : sélectionnez Lecteur d'objets Storage.
Cliquez sur Enregistrer.
Limites de débit de l'API NetSuite
L'API NetSuite présente les limites de simultanéité et de limitation du débit suivantes :
| Type de limite | Valeur par défaut | Remarques |
|---|---|---|
| Requêtes simultanées | 15 requêtes | S'applique aux requêtes API SOAP et REST combinées par compte |
| Résultats de requête SuiteQL | 100 000 lignes maximum | Nombre maximal de lignes renvoyées par requête SuiteQL |
| Objets par requête | 1 000 objets maximum | Nombre maximal d'objets renvoyés par requête API |
La fonction Cloud Run gère automatiquement la limitation du débit avec un intervalle exponentiel entre les tentatives. Si vous rencontrez des erreurs de limite de fréquence persistantes (HTTP 429), contactez l'assistance NetSuite pour augmenter vos limites d'API ou ajuster la fréquence de Cloud Scheduler.
Table de mappage UDM
| Champ de journal | Mappage UDM | Logique |
|---|---|---|
| utilisateur | extensions.auth.type | Type de mécanisme d'authentification utilisé |
| date | metadata.event_timestamp | Code temporel de l'événement |
| event_type | metadata.event_type | Type d'événement (par exemple, USER_LOGIN, NETWORK_CONNECTION) |
| security_result | security_result | Détails sur le résultat de sécurité de l'événement |
| oauthaccesstokenname | security_result.about.resource.attribute.labels | Étiquettes clé-valeur décrivant les attributs de la ressource concernée par le résultat de sécurité |
| secchallenge | security_result.about.resource.attribute.labels | |
| état | security_result.summary | Description récapitulative du résultat de sécurité |
| oauthappname | target.application | Nom de l'application cible |
| User-agent | target.application | |
| ipaddress | target.ip | Adresse IP de la cible |
| requesturi | target.url | URL de la ressource cible |
| emailaddress | target.user.email_addresses | Adresses e-mail associées à l'utilisateur cible |
| rôle | target.user.role_name | Nom du rôle attribué à l'utilisateur cible |
| utilisateur | target.user.userid | Identifiant unique de l'utilisateur cible |
Journal des modifications
Afficher le journal des modifications de ce parseur
Vous avez encore besoin d'aide ? Obtenez des réponses de membres de la communauté et de professionnels Google SecOps.