API de recherche asynchrone

Compatible avec :

La plate-forme de recherche de Google Security Operations vous permet d'utiliser des API asynchrones pour les requêtes de longue durée qui renvoient des ensembles de résultats volumineux (jusqu'à un million de résultats). Ces API vous permettent de lancer des recherches dans des sources de données, y compris des événements, des détections, des tables de données et un graphique de contexte d'entité (ECG) du modèle de données unifié (UDM), sans bloquer votre application. Lorsque vous exécutez une requête de recherche à l'aide d'une API d'opération de longue durée (LRO), vous recevez un ID d'opération. Vous pouvez utiliser cet ID pour surveiller l'état de l'opération et obtenir les résultats page par page.

Prérequis

Pour utiliser les API d'opération de longue durée, le compte principal appelant doit disposer d'autorisations IAM (Identity and Access Management) spécifiques.

Pour effectuer les actions suivantes, vous devez disposer des autorisations IAM correspondantes :

  • Lancer une recherche : chronicle.searchSessions.search
  • Résultats de la liste : chronicle.searchedResults.list sur la ressource SearchSession.

Assurez-vous que le compte principal appelant dispose d'un rôle qui accorde ces autorisations, par exemple le rôle Lecteur de l'API Chronicle, Éditeur de l'API Chronicle ou Administrateur de l'API Chronicle.

Effectuer une recherche à l'aide des API LRO

Pour effectuer une recherche à l'aide des API LRO, procédez comme suit :

  1. Lancez la recherche.
  2. Surveillez l'opération.
  3. Récupérez les résultats.

Envoyez une requête POST à la méthode personnalisée search sur l'instance Google SecOps.

  • Point de terminaison : POST /{$api_version}/projects/{project}/locations/{location}/instances/{instance}:search
  • Méthode : Search
  • Corps de la requête : SearchRequest

L'exemple suivant montre un objet SearchRequest :

{
  "parent": "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID",
  "query": "metadata.event_type = \"USER_LOGIN\"",
  "time_range": {},
  "start_time": "2026-03-16T14:40:13Z",
  "endTime": "2026-03-16T15:40:13Z",
  "dialect": "YL2"
}

La requête nécessite les paramètres clés suivants :

  • query : chaîne de la requête de recherche.
  • time_range : intervalle de temps pour la recherche.
  • dialect : spécifie le dialecte de la langue comme YL2.
    • Le dialecte SQL n'est pas compatible avec la récupération asynchrone des résultats d'une LRO à l'aide de ListSearchedResults (searchedResults.list).
    • Le dialecte RAW_LOG est en version preview et peut renvoyer une erreur 501 UNIMPLEMENTED s'il n'est pas activé pour votre instance.
  • result_limit : facultatif. Nombre maximal de lignes à matérialiser. La valeur par défaut est 10000 et la valeur maximale est 1000000.
  • simulated_data_visibility (ou simulatedDataVisibility en JSON) : facultatif. Détermine si les résultats de recherche incluent des événements simulés. Définissez cette option sur SIMULATED_DATA_INCLUDED pour inclure les événements simulés dans les résultats de recherche. Si ce paramètre n'est pas spécifié, il est défini par défaut sur SIMULATED_DATA_EXCLUDED, ce qui exclut les événements simulés.

Cet appel renvoie un objet google.longrunning.Operation.

L'exemple suivant montre une réponse d'opération réussie :

{
  "name": "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/operations/OPERATION_ID",
  "metadata": {
    "@type": "[type.googleapis.com/google.cloud.chronicle.v1main.SearchOperationMetadata](https://type.googleapis.com/google.cloud.chronicle.v1main.SearchOperationMetadata)",
    "state": "RUNNING",
    "start_time": "2026-03-13T10:00:00Z"
  }
}

Le champ state: RUNNING indique que la recherche est en cours.

Surveiller l'opération

Interrogez l'état de l'opération de longue durée à l'aide de la méthode GetOperation standard du service google.longrunning.Operations. Utilisez la valeur name de la réponse précédente.

  • Point de terminaison : GET /{$api_version}/projects/{project}/locations/{location}/instances/{instance}/operations/{operationID}

Continuez l'interrogation jusqu'à ce que le champ done de la réponse GetOperation renvoie true.

  • Si l'opération aboutit, le champ metadata.state renvoie SUCCEEDED et le champ de réponse contient la ressource SearchSession créée.
  • Si l'opération échoue, le champ done renvoie true et le champ d'erreur contient les détails de l'échec.

L'exemple suivant montre une réponse GetOperation réussie :

{
  "name": "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/operations/OPERATION_ID",
  "metadata": {
    "@type": "[type.googleapis.com/google.cloud.chronicle.v1main.SearchOperation](https://type.googleapis.com/google.cloud.chronicle.v1main.SearchOperation) Metadata",
    "state": "SUCCEEDED",
    "startTime": "2026-03-16T15:42:11.037506921Z"
  },
  "endTime": "2026-03-16T15:42:17.504730842Z",
  "expireTime": "2026-03-17T15:42:17.504731874Z",
  "progress": 100,
  "done": true,
  "response": {
    "@type": "[type.googleapis.com/google.cloud.chronicle.v1main.SearchSession](https://type.googleapis.com/google.cloud.chronicle.v1main.SearchSession)",
    "name": "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/searchSessions/SEARCH_SESSION_ID",
    "query": "metadata.event_type = \"USER_LOGIN\"",
    "timeRange": {},
    "startTime": "2026-03-16T14:40:13Z",
    "endTime": "2026-03-16T15:40:13Z",
    "dialect": "YL2",
    "metadata": {
      "operationId": "OPERATION_ID",
      "startTime": "2026-03-16T15:42:11.037506921Z",
      "endTime": "2026-03-16T15:42:17.504730842Z",
      "expireTime": "2026-03-17T15:42:17.504731874Z",
      "resultRowCount": 10000,
      "moreDataAvailable": true
    }
  }
}

Le format du nom de ressource SearchSession est projects/{project}/locations/{location}/instances/{instance}/searchSessions/{search_session}.

La réponse réussie contient les champs clés suivants :

  • done : lorsque la valeur est définie sur true, l'opération est terminée.
  • state : lorsque la valeur est définie sur SUCCEEDED, la recherche s'est terminée avec succès.
  • response.name : nom de ressource de SearchSession. Utilisez cette valeur comme propriété parente à l'étape suivante.
  • response.metadata.resultRowCount : indique le nombre total de lignes trouvées.
  • response.metadata.moreDataAvailable : indique que le nombre de résultats disponibles dépasse la limite de renvoi définie.

Répertorier les opérations de longue durée

Pour lister les opérations de longue durée, utilisez la méthode ListOperations du service google.longrunning.Operations. Utilisez la valeur name de la réponse précédente.

  • Point de terminaison : GET /{$api_version}/projects/{project}/locations/{location}/instances/{instance}

Pour lister les opérations LRO de recherche des dernières 24 heures, spécifiez le filtre name:"operations/s-lro-", y compris le trait d'union final.

L'exemple suivant montre une requête ListOperations réussie :

google.longrunning.ListOperationsRequest {
  name: "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID"
  filter: "name:\"operations/s-lro-\""
  page_size: 100
}

L'exemple suivant montre une réponse ListOperations réussie :

{
  operations {
    name: "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/operations/OPERATION_ID_1"
    metadata {
      type_url: "[type.googleapis.com/google.cloud.chronicle.v1main.SearchOperation](https://type.googleapis.com/google.cloud.chronicle.v1main.SearchOperation) Metadata"
      value: "\b\002\022\f\b\367\304\363\316\006\020\317\352\232\240\003\032\f\b\237\307\363\316\006\020\326\334\351\311\001\"\f\b\237\352\370\316\006\020\352\342\351\311\001(d"
    }
    done: true
    response {
      type_url: "[type.googleapis.com/google.cloud.chronicle.v1main.SearchSession](https://type.googleapis.com/google.cloud.chronicle.v1main.SearchSession)"
      value: "\n\213\001projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/searchSessions/OPERATION_ID_11022\bip != \"\"\032\020\n\006\b\251\255\334\316\006\022\006\b\351\345\336\316\006\0012\\\n*OPERATION_ID_1\022\f\b\367\304\363\316\006\020\317\352\232\240\003\032\f\b\237\307\363\316\006\020\326\334\351\311\001\"\f\b\237\352\370\316\006\020\352\342\351\311\001(\300\204=0\001"
    }
  }
  operations {
    name: "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/operations/OPERATION_ID_2"
    metadata {
      type_url: "[type.googleapis.com/google.cloud.chronicle.v1main.SearchOperationMetadata](https://type.googleapis.com/google.cloud.chronicle.v1main.SearchOperationMetadata)"
      value: "\b\002\022\f\b\200\305\363\316\006\020\324\262\367\225\001\032\v\b\241\307\363\316\006\020\321\261\333?\"\v\b\241\352\370\316\006\020\317\264\333?(d"
    }
    done: true
    response {
      type_url: "[type.googleapis.com/google.cloud.chronicle.v1main.SearchSession](https://type.googleapis.com/google.cloud.chronicle.v1main.SearchSession)"
      value: "\n\213\001projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/searchSessions/OPERATION_ID_2\022\bip != \"\"\0321020\n\006\b\251\255\334\316\006\022\006\b\351\345\336\316\006\0012Z\n*OPERATION_ID_2\022\f\b\200\305\363\316\006\0201324\262\367\225\001\032\v\b\241\307\363\316\006\020\321\261\333?\"\v\b\241\352\370\316\006\020\317\264\333?(\300\204=0\001"
    }
  }
}

Récupérer les résultats

Une fois que l'état de l'opération renvoie SUCCEEDED, utilisez la méthode ListSearchedResults() pour récupérer les résultats de recherche.

  • Point de terminaison : GET /{$api_version}/{parent=projects/*/locations/*/instances/*/searchSessions/*}/searchedResults
  • Méthode : ListSearchedResults
  • Paramètres de requête : ListSearchedResultsRequest

L'exemple suivant montre un ListSearchedResultsRequest qui récupère trois résultats et ignore les cinq premiers :

// GET
/v1alpha/projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/searchSessions/SEARCH_SESSION_ID/searchedResults?page_size=3&skip=5

La requête accepte les paramètres de requête suivants :

  • page_size : nombre maximal de résultats à renvoyer par page. La valeur par défaut est 100 et la valeur maximale 10 000.
  • page_token : jeton d'un ListSearchedResultsResponse précédent utilisé pour récupérer la page suivante.
  • order_by (ou orderBy en JSON) : facultatif. Champ utilisé pour trier les résultats. Lorsque vous omettez order_by, les résultats des événements UDM sont triés par udm.metadata.event_timestamp par ordre décroissant par défaut, en renvoyant d'abord les événements les plus récents. Lorsque vous spécifiez un chemin de champ dans order_by sans suffixe de direction, tel que udm.principal.hostname, les résultats sont triés par ordre croissant par défaut. N'ajoutez pas asc, car le suffixe asc n'est pas accepté et renvoie une erreur 400 INVALID_ARGUMENT. Pour trier les résultats par ordre décroissant, ajoutez le suffixe desc au chemin d'accès du champ, par exemple udm.metadata.event_timestamp desc. Le tri sur plusieurs colonnes n'est pas possible.

    • UDM events (eventRecord) : utilisez des chemins d'accès complets dans le champ udm, par exemple udm.metadata.event_timestamp desc ou udm.principal.hostname. Les noms de colonnes tels que hostname, user, process name et event type sont également acceptés.

      L'ordre de tri par défaut est udm.metadata.event_timestamp par ordre décroissant, ce qui renvoie d'abord les événements les plus récents.

    • Entities / ECG (entityContextRecord) : utilisez des chemins d'accès dans le champ entity, par exemple graph.entity.ip ou graph.entity.ip desc.

    • data tables (dataTableRecord) : utilisez le format %<table_alias>.<column_name>. Par exemple, %dt.user desc.

      La valeur par défaut est la première colonne du tableau de données.

    • Detections (DetectionRecord) : utilisez le mot clé detection suivi du chemin d'accès, par exemple detection.id.

    • Jointures : pour les événements et les entités, utilisez la variable d'espace réservé qui les définit. Pour toutes les autres sources, le format reste le même.

      Exemple :

      • ECG (jointure UDM-ECG) : entité : $e1.graph.entity.hostname
      • UDM (toutes les jointures avec UDM) : $e1.principal.ip
      • Table de données (jointure UDM-table de données) : %<table_alias>.<column_name>

      Les alias prédéfinis tels que hostname, user, process name et event type sont également acceptés. Pour ces derniers, utilisez le format $e1.hostname.at.

  • skip : facultatif. Nombre de résultats à ignorer. N'utilisez pas ce paramètre avec page_token.

    • Le tri par défaut (udm.metadata.event_timestamp) n'est pas unique pour les événements qui partagent le même code temporel. De plus, l'ordre de tri des résultats de recherche est défini lors du premier appel ListSearchedResults (searchedResults.list).
    • Lorsque vous paginez avec skip, en particulier pour des requêtes parallèles, spécifiez un champ de tri unique tel que udm.metadata.id dans le paramètre order_by. Vous pouvez également récupérer la première page avant d'envoyer des requêtes skip parallèles afin que l'ordre de tri soit déjà défini.

L'exemple suivant montre une réponse ListSearchedResultsResponse réussie :

{
"searchedResults": [
{
"name":
"projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/searchSessions/SEARCH_SESSION_ID/searchedResults/
RESULT_ID",
"resultRow": {
"eventRecord": {
"event": {
"name":
"projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/events/EVENT_ID",
"udm": {
"metadata": {
"eventTimestamp": "2026-03-16T14:45:18Z",
"eventType": "USER_LOGIN",
"vendorName": "Microsoft",
"productName": "Azure AD"
}
},
//... other UDM fields
}
//... other UDM fields
"eventLogToken":
"EVENT_LOG_TOKEN"
}
},
{ }
},
{
"name": "projects/PROJECT_NUMBER/locations/
LOCATION/instances/INSTANCE_ID</span>
/searchSessions/SEARCH_SESSION_ID/searchedResults/RESULT_ID", "resultRow": {
"eventRecord": {
//... Similar UDM event structure...
}
}
},
{
""name": "projects/PROJECT_NUMBER/locations/
LOCATION/instances/INSTANCE_ID</span>
/searchSessions/SEARCH_SESSION_ID/searchedResults/RESULT_ID", "resultRow": {
"eventRecord": {
//... Similar UDM event structure...
}
}
}
],
"totalSize": 10000,
"columnNames": [],
"columnSchema": {},
"nextPageToken": "CAKYASAB"
}

Pour récupérer la page de résultats suivante, utilisez la valeur nextPageToken renvoyée dans le paramètre de requête page_token de votre prochaine requête ListSearchedResults. Le champ resultRow contient les données réelles.

Continuez à appeler ListSearchedResults avec la valeur next_page_token de chaque réponse. Lorsque next_page_token renvoie une valeur vide, tous les résultats ont été récupérés.

Étapes suivantes

Pour en savoir plus sur les méthodes, les champs de requête et de réponse, et les types, consultez la documentation de référence de l'API suivante :

Vous avez encore besoin d'aide ? Obtenez des réponses de membres de la communauté et de professionnels Google SecOps.