Collecter les journaux Trellix Endpoint Security HX (anciennement FireEye HX)
Version de l'analyseur : 30.0
Ce guide explique comment ingérer les journaux Trellix Endpoint Security HX (anciennement FireEye HX) dans Google Security Operations à l'aide de Google Cloud Storage V2. Trellix Endpoint Security HX est une plate-forme de détection et de réponse au niveau des points de terminaison (EDR) qui offre des fonctionnalités avancées de détection, d'investigation et de confinement des menaces. Il utilise une protection basée sur l'intelligence et des indicateurs de compromission (IOC) en temps réel pour détecter les attaques sophistiquées sur les points de terminaison et y répondre.
Avant de commencer
Assurez-vous de remplir les conditions suivantes :
- Une instance Google SecOps.
- Un projet GCP avec l'API Cloud Storage activée.
- Autorisations permettant de créer et de gérer des buckets GCS et des règles IAM.
- Autorisations pour créer des services Cloud Run, des sujets Pub/Sub et des jobs Cloud Scheduler.
- Accès privilégié à la console Trellix Endpoint Security HX avec l'accès à l'API activé.
- Un compte utilisateur de l'API Trellix HX avec au moins le rôle d'analyste.
Créer un bucket Google Cloud Storage
- Accédez à la console Google Cloud.
- Sélectionnez votre projet.
- 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, fireeye-hx-logs).Type d'emplacement Choisissez en fonction de vos besoins (région, birégion, multirégion). Emplacement Sélectionnez l'emplacement le plus proche de votre instance Google SecOps. 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.
Collecter les identifiants de l'API Trellix Endpoint Security HX
Obtenir l'URL de la console HX
- Connectez-vous à la console Web Trellix Endpoint Security HX.
- Notez l'URL de la console dans la barre d'adresse du navigateur (format :
https://<hx-hostname>:<port>).
Créer ou valider un compte utilisateur de l'API
- Connectez-vous à la console Trellix HX avec un compte administrateur.
- Accédez à Admin > User Accounts (Administrateur > Comptes utilisateur).
- Créez un nouvel utilisateur ou sélectionnez-en un existant pour accéder à l'API.
- Assurez-vous que l'utilisateur dispose du rôle api_analyst ou api_admin.
- Notez le nom d'utilisateur et le mot de passe pour l'accès à l'API.
Vérifier l'accès à l'API
Testez vos identifiants avant de procéder à l'intégration :
HX_HOST="[https://hx-console.example.com:3000](https://hx-console.example.com:3000)" HX_USER="api_user" HX_PASS="api_password" # Authenticate and get token curl -k -X POST "$HX_HOST/hx/api/v3/token" \ -u "$HX_USER:$HX_PASS"
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 :
- Service account name (Nom du compte de service) :
fireeye-hx-collector-sa - Description du compte de service :
Service account for Cloud Run function to collect Trellix HX logs
- Service account name (Nom du compte de service) :
- Cliquez sur Créer et continuer.
- Dans la section Autoriser ce compte de service à accéder au projet, ajoutez les rôles suivants :
- Administrateur des objets Storage
- Demandeur Cloud Run
- Demandeur Cloud Functions
- Cliquez sur Continuer, puis sur OK.
Accorder des autorisations IAM sur le bucket GCS
- Accédez à Cloud Storage > Buckets.
- Cliquez sur le nom du bucket (
fireeye-hx-logs). - Accédez à l'onglet Autorisations.
- Cliquez sur Accorder l'accès.
- Ajouter des comptes principaux : saisissez l'adresse e-mail du compte de service.
- Attribuer des rôles : sélectionnez Administrateur des objets Storage.
- Cliquez sur Enregistrer.
Créer un sujet Pub/Sub
Créez un sujet auquel Cloud Scheduler publiera des messages et auquel la fonction Cloud Run s'abonnera.
- Dans la console GCP, accédez à Pub/Sub > Sujets.
- Cliquez sur Créer un sujet.
- ID du thème :
fireeye-hx-logs-trigger. - Cliquez sur Créer.
Créer une fonction Cloud Run pour collecter les journaux
- Dans la console GCP, accédez à Cloud Run.
- Cliquez sur Créer un service.
- Sélectionnez Fonction.
Dans la section Configurer, fournissez les informations suivantes :
Paramètre Valeur Nom du service fireeye-hx-collectorRégion Sélectionnez la région correspondant à votre bucket GCS. Durée d'exécution Python 3.12 ou version ultérieure Dans la section Déclencheur :
- Cliquez sur + Ajouter un déclencheur.
- Sélectionnez Cloud Pub/Sub.
- Dans Sélectionner un sujet Cloud Pub/Sub, sélectionnez
fireeye-hx-logs-trigger. - Cliquez sur Enregistrer.
Dans la section Authentification, sélectionnez Exiger l'authentification et cochez Identity and Access Management (IAM).
Faites défiler la page jusqu'à Conteneurs, mise en réseau, sécurité.
Dans l'onglet Sécurité, sélectionnez le compte de service
fireeye-hx-collector-sa.Dans l'onglet Conteneurs, cliquez sur Variables et secrets, puis ajoutez les éléments suivants :
Nom de la variable Exemple de valeur Description GCS_BUCKETfireeye-hx-logsNom du bucket GCS GCS_PREFIXhx-alertsPréfixe des fichiers journaux STATE_KEYhx-alerts/state.jsonChemin d'accès au fichier d'état HX_HOSThttps://hx-console.example.com:3000URL de la console HX HX_USERapi_userNom d'utilisateur de l'API HX_PASSapi_passwordMot de passe de l'API MAX_RECORDS1000Nombre maximal d'enregistrements par exécution PAGE_SIZE100Enregistrements par page LOOKBACK_HOURS24Période d'analyse initiale Dans Requests (Requêtes), définissez Request timeout (Délai avant expiration de la requête) sur
600secondes.Cliquez sur Créer. Une fois le service créé, l'éditeur de code intégré s'ouvre.
Ajouter un code de fonction
- Saisissez main dans le champ Point d'entrée.
Créez les fichiers suivants dans l'éditeur intégré :
- main.py:
import functions_framework from google.cloud import storage import json import os import urllib3 from datetime import datetime, timezone, timedelta import time # Disable SSL warnings for self-signed certs urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Initialize HTTP client with timeouts http = urllib3.PoolManager( timeout=urllib3.Timeout(connect=5.0, read=30.0), retries=False, cert_reqs='CERT_NONE', ) # Initialize Storage client storage_client = storage.Client() # Environment variables GCS_BUCKET = os.environ.get('GCS_BUCKET') GCS_PREFIX = os.environ.get('GCS_PREFIX', 'hx-alerts') STATE_KEY = os.environ.get('STATE_KEY', 'hx-alerts/state.json') HX_HOST = os.environ.get('HX_HOST') HX_USER = os.environ.get('HX_USER') HX_PASS = os.environ.get('HX_PASS') MAX_RECORDS = int(os.environ.get('MAX_RECORDS', '1000')) PAGE_SIZE = int(os.environ.get('PAGE_SIZE', '100')) LOOKBACK_HOURS = int(os.environ.get('LOOKBACK_HOURS', '24')) def get_api_token(host, username, password): url = f"{host}/hx/api/v3/token" auth_string = f"{username}:{password}" import base64 auth_b64 = base64.b64encode(auth_string.encode('utf-8')).decode('utf-8') headers = {'Authorization': f'Basic {auth_b64}'} response = http.request('POST', url, headers=headers) if response.status == 204: return response.headers.get('X-FeApi-Token') else: raise Exception(f"Authentication failed: HTTP {response.status}") @functions_framework.cloud_event def main(cloud_event): if not all([GCS_BUCKET, HX_HOST, HX_USER, HX_PASS]): print('Error: Missing required environment variables') return try: bucket = storage_client.bucket(GCS_BUCKET) state = load_state(bucket, STATE_KEY) now = datetime.now(timezone.utc) last_time = None if isinstance(state, dict) and state.get("last_event_time"): try: last_time = parse_datetime(state["last_event_time"]) - timedelta(minutes=2) except Exception as e: print(f"Warning: Could not parse last_event_time: {e}") if last_time is None: last_time = now - timedelta(hours=LOOKBACK_HOURS) print(f"Fetching alerts from {last_time.isoformat()} to {now.isoformat()}") token = get_api_token(HX_HOST, HX_USER, HX_PASS) alerts, newest_time = fetch_alerts(HX_HOST, token, last_time, now, PAGE_SIZE, MAX_RECORDS) hosts = fetch_hosts(HX_HOST, token) all_records = alerts + hosts if not all_records: print("No new records found.") save_state(bucket, STATE_KEY, now.isoformat()) return timestamp = now.strftime('%Y%m%d_%H%M%S') object_key = f"{GCS_PREFIX}/logs_{timestamp}.ndjson" ndjson = '\n'.join([json.dumps(record, ensure_ascii=False) for record in all_records]) + '\n' bucket.blob(object_key).upload_from_string(ndjson, content_type='application/x-ndjson') print(f"Wrote {len(all_records)} records to gs://{GCS_BUCKET}/{object_key}") save_state(bucket, STATE_KEY, newest_time if newest_time else now.isoformat()) release_token(HX_HOST, token) print(f"Successfully processed {len(all_records)} records") except Exception as e: print(f'Error processing logs: {str(e)}') raise def parse_datetime(value): if value.endswith("Z"): value = value[:-1] + "+00:00" return datetime.fromisoformat(value) def load_state(bucket, key): try: blob = bucket.blob(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, key, last_event_time_iso): try: state = {'last_event_time': last_event_time_iso} bucket.blob(key).upload_from_string(json.dumps(state, indent=2), content_type='application/json') except Exception as e: print(f"Warning: Could not save state: {e}") def fetch_alerts(host, token, start_time, end_time, page_size, max_records): endpoint = f"{host}/hx/api/v3/alerts" headers = {'X-FeApi-Token': token, 'Accept': 'application/json'} records = []; newest_time = None; offset = 0; backoff = 1.0 while True: if len(records) >= max_records: break start_iso = start_time.strftime('%Y-%m-%dT%H:%M:%S.000Z') end_iso = end_time.strftime('%Y-%m-%dT%H:%M:%S.000Z') url = f"{endpoint}?sort=reported_at+asc&min_reported_at={start_iso}&max_reported_at={end_iso}&offset={offset}&limit={min(page_size, max_records - len(records))}" try: response = http.request('GET', url, headers=headers) if response.status == 429: time.sleep(int(response.headers.get('Retry-After', str(int(backoff))))); backoff = min(backoff * 2, 30.0); continue backoff = 1.0 if response.status != 200: break data = json.loads(response.data.decode('utf-8')) page_results = data.get('data', {}).get('entries', []) if not page_results: break records.extend(page_results) for alert in page_results: event_time = alert.get('reported_at') if event_time and (newest_time is None or event_time > newest_time): newest_time = event_time offset += len(page_results) if offset >= data.get('data', {}).get('total', 0): break except Exception: break return records, newest_time def fetch_hosts(host, token): endpoint = f"{host}/hx/api/v3/hosts" headers = {'X-FeApi-Token': token, 'Accept': 'application/json'} try: response = http.request('GET', f"{endpoint}?limit=100&offset=0", headers=headers) if response.status != 200: return [] return json.loads(response.data.decode('utf-8')).get('data', {}).get('entries', []) except Exception: return [] def release_token(host, token): try: http.request('DELETE', f"{host}/hx/api/v3/token", headers={'X-FeApi-Token': token}) except Exception: pass- requirements.txt:
functions-framework==3.* google-cloud-storage==2.* urllib3>=2.0.0Cliquez sur Déployer pour enregistrer et déployer la fonction.
Créer une tâche Cloud Scheduler
- 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 fireeye-hx-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 fireeye-hx-logs-triggerCorps du message {}Cliquez sur Créer.
Tester l'intégration
- Dans Cloud Scheduler, recherchez votre job et cliquez sur Forcer l'exécution.
- Accédez à Cloud Run > Services > Journaux pour vérifier que l'opération a réussi.
- Cochez Cloud Storage pour vérifier qu'un fichier
.ndjsonexiste dans le dossierhx-alerts/.
Configurer un flux dans Google SecOps
- Accédez à Paramètres SIEM > Flux.
- Cliquez sur Ajouter un flux > Configurer un seul flux.
- Nom du flux :
Trellix HX Logs. - Type de source : Google Cloud Storage V2.
- Type de journal : FireEye HX.
- Cliquez sur Get Service Account (Obtenir un compte de service), puis copiez l'adresse e-mail (par exemple,
chronicle-12345678@...). - Cliquez sur Suivant.
- URL du bucket de stockage :
gs://fireeye-hx-logs/hx-alerts/(incluez la barre oblique de fin). - Option de suppression de la source : sélectionnez l'option de votre choix.
- Cliquez sur Suivant, vérifiez, puis cliquez sur Envoyer.
Accorder des autorisations IAM au compte de service
Le compte de service Google SecOps a besoin du rôle Lecteur des objets Storage sur votre bucket.
- Accédez à Cloud Storage > Buckets.
- Sélectionnez votre bucket, puis accédez à l'onglet Autorisations.
- Cliquez sur Accorder l'accès.
- 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.
Table de mappage UDM
| Champ du journal | Mappage UDM | Logique |
|---|---|---|
alert.event_type |
metadata.product_event_type |
Mappage direct. |
alert.reported_at |
metadata.event_timestamp |
Analysé en tant que code temporel. |
alert.source |
principal.hostname |
Mappage direct. |
alert.agent._id |
principal.asset_id |
Mappage direct. |
alert.indicator.display_name |
security_result.threat_name |
Mappage direct. |
alert.md5values |
target.file.md5 |
Mappage direct. |
| N/A | metadata.vendor_name |
Définissez-le sur Trellix. |
| N/A | metadata.product_name |
Définissez la valeur sur Endpoint Security HX. |
| N/A | metadata.log_type |
Définissez-le sur FIREEYE_HX. |
cs12 |
additional.fields |
Mappé à partir du journal des modifications |
cs9 |
target.process.file.md5 |
Mappé à partir du journal des modifications |
account_name", "UUID", "Mitre", "host_details.data.sysinfo.url", "host_details.route", "host_details.data.reported_clone", and "host_details.data.timezone |
security_result.detection_fields |
Mappé à partir du journal des modifications |
Desc |
metadata.description |
Mappé à partir du journal des modifications |
Confidence |
security_result.confidence |
Mappé à partir du journal des modifications |
alert.appliance._id |
additional.fields |
Mappé à partir du journal des modifications |
host_details.data.stats.acqs", "host_details.data.stats.alerting_conditions", "host_details.data.stats.alerts", "host_details.data.stats.exploit_alerts", "host_details.data.stats.exploit_blocks", and "host_details.data.stats.false_positive_alerts |
security_result.detection_fields |
Mappé à partir du journal des modifications |
categoryOutcome", "cs13 |
additional.fields |
Mappé à partir du journal des modifications |
cs6 |
target.process.file.sha1 |
Mappé à partir du journal des modifications |
host_details.message |
security_result.action_details |
Mappé à partir du journal des modifications |
alert.md5values", "alert.resolution", "alert.is_false_positive", and "alert.alert_type |
additional.fields |
Mappé à partir du journal des modifications |
type.threat_type |
security_result.threat_name |
Mappé à partir du journal des modifications |
ent.lms_event_id |
metadata.product_log_id |
Mappé à partir du journal des modifications |
email.smtp.mail_from |
network.email.from |
Mappé à partir du journal des modifications |
email.headers.subject |
network.email.subject |
Mappé à partir du journal des modifications |
email.headers.to |
network.email.to |
Mappé à partir du journal des modifications |
ent.type", "ent.id", "ent.name", "ent.object_source", "ent.binary", and "ent.attributes.scan_id |
security_result.detection_fields |
Mappé à partir du journal des modifications |
cs11Label |
additional_cs11Label.key |
Mappé à partir du journal des modifications |
cs11 |
additional_cs11.value |
Mappé à partir du journal des modifications |
alert.sysinfo.mac_address |
principal.mac |
Mappé à partir du journal des modifications |
host_details.data.agent_version |
metadata.product_version |
Mappé à partir du journal des modifications |
alert.url |
metadata.url_back_to_product |
Mappé à partir du journal des modifications |
description |
metadata.description |
Mappé à partir du journal des modifications |
alert.agent._id |
principal.asset.asset_id |
Mappé à partir du journal des modifications |
alert.event_id |
metadata.product_log_id |
Mappé à partir du journal des modifications |
deviceCustomDate1Label |
additional_deviceCustomDate1.key |
Mappé à partir du journal des modifications |
deviceCustomDate1 |
additional_deviceCustomDate1.value |
Mappé à partir du journal des modifications |
deviceCustomDate2 |
additional_deviceCustomDate2.value |
Mappé à partir du journal des modifications |
client |
principal.ip |
Mappé à partir du journal des modifications |
principal_ip |
principal.ip |
Mappé à partir du journal des modifications |
remoteaddress |
principal.ip |
Mappé à partir du journal des modifications |
host_ |
principal.hostname |
Mappé à partir du journal des modifications |
line |
principal.application |
Mappé à partir du journal des modifications |
username |
principal.user.userid |
Mappé à partir du journal des modifications |
client_app_type |
principal.resource.attribute.labels |
Mappé à partir du journal des modifications |
upstream |
target.url |
Mappé à partir du journal des modifications |
role |
target.user.role_name |
Mappé à partir du journal des modifications |
server |
target.resource.attribute.labels |
Mappé à partir du journal des modifications |
localusername |
target.user.user_display_name |
Mappé à partir du journal des modifications |
request |
additional.fields |
Mappé à partir du journal des modifications |
mlocked |
additional.fields |
Mappé à partir du journal des modifications |
kernel_stack |
additional.fields |
Mappé à partir du journal des modifications |
sessionID |
network.session_id |
Mappé à partir du journal des modifications |
auth_mechanism |
extensions.auth.mechanism |
Mappé à partir du journal des modifications |
authsubmethod |
extensions.auth.auth_details |
Mappé à partir du journal des modifications |
Journal des modifications
Afficher le journal des modifications pour ce parseur
Vous avez encore besoin d'aide ? Obtenez des réponses de membres de la communauté et de professionnels Google SecOps.