Naar de inhoud
Avanet

Het Sophos Fusion Data Lake doorzoeken met de Search GraphQL API

Met de Search GraphQL API v1 kan een eigen toepassing het historische Sophos Fusion Data Lake doorzoeken met QL. Het proces is asynchroon: start de zoekopdracht, bewaar de Search-URN, controleer de voltooiing en de uitvoeringsuitkomst en lees daarna alle resultaatpagina’s. COMPLETE alleen betekent niet dat alle delen van de zoekopdracht zijn geslaagd.

De API is sinds 12 oktober 2026 gepubliceerd. Ze vult bestaande API’s aan en verplicht niet tot een onmiddellijke overstap van de nog beschikbare XDR Query API. Ze vervangt ook Live Endpoint Search (LES) niet: LES bevraagt verbonden endpoints met osquery-achtige SQL. Het onderscheid tussen Classic Live Discover, Data Lake Search en LES helpt bij het kiezen van het juiste datapad.

Vóór het eerste request

Er zijn een tenant met de gezochte historische data, passende API Credentials, de unieke tenant-UUID en een HTTP-client nodig die JSON-POST-requests kan versturen en volledige antwoorden kan opslaan. Voor het voorbeeld moet de tenant procesgebeurtenissen bevatten. Zonder die data kan een technisch geslaagde zoekopdracht leeg blijven.

API-inloggegevens veilig beheren behandelt machine-identiteit, de OAuth-flow met client_credentials, tenantkoppeling en rotatie. Een partner- of organisatie-ID is geen tenant-UUID. Kies bij meerdere tenants de doeltenant via een goedgekeurde, eenduidige koppeling, niet uitsluitend op weergavenaam.

De exacte minimale rol en benodigde entitlements voor de specifieke Search-client moeten vóór productiegoedkeuring worden vastgesteld. De naam van een algemene service-principalrol bewijst geen bevestigde Search-machtiging. Ken bij een weigering daarom niet uit voorzorg Super Admin toe.

Leg vóór de start de onderzoeksvraag, periode en benodigde velden vast. Procesdata kunnen gebruikersnamen, paden en opdrachtregels met vertrouwelijke inhoud bevatten. Query’s en exports horen in een goedgekeurde omgeving met geregelde toegangs- en bewaarbevoegdheden. Tokens en Client Secrets mogen niet in requestlogs, tickets of opgeslagen voorbeeldbestanden terechtkomen. Ook volledige resultaatrijen mogen niet ongecontroleerd worden gelogd.

Gebruik de API-specifieke doelhost

Voor de volgende bewerkingen geldt hetzelfde requestcontract:

POST https://api.taegis.sophos.com/graphql
Authorization: Bearer <access-token>
X-Tenant-ID: <tenant-uuid>
X-GraphQL-Schema: default
Content-Type: application/json

Vervang in de HTTP-client <access-token> door het huidige OAuth-access-token en <tenant-uuid> door de gecontroleerde UUID. URL en headers blijven voor elke volgende JSON-body gelijk. De voorbeelden zijn requestsjablonen, geen hier uitgevoerde tenanttests of vastgelegde geslaagde uitvoer.

De regionale REST-host uit apiHosts.dataRegion is niet de doelhost van dit Search-contract. Zet omgekeerd bestaande REST-clients niet globaal over op de GraphQL-host. Deze hostnaam garandeert ook geen opslaglocatie of dataresidentie; toets zulke eisen aan de geldende tenant- en contractvoorwaarden.

Een zoekopdracht starten en eenduidig volgen

Een nieuwe uitvoering maken met createSearch

Het volgende sjabloon zoekt procesgebeurtenissen van het afgelopen uur en beperkt de geselecteerde gebeurtenisvelden. -1h is een relatief tijdvenster voor een eerste functiecontrole; leg voor een latere vergelijking met een andere client identieke expliciete tijdgrenzen vast.

{
  "operationName": "CreateSearch",
  "query": "mutation CreateSearch($input: CreateSearchInput) { createSearch(input: $input) { urn status } }",
  "variables": {
    "input": {
      "text": "from process where earliest = -1h | fields host_id, commandline, image_path"
    }
  }
}

Controleer vóór verzending tenant, periode en dataomvang. createSearch maakt en start een nieuwe zoekuitvoering, maar wijzigt geen endpointbeveiligingsconfiguratie. De uitvoering kan werk in de dienst en gevoelige resultaten genereren. Start bij een clientfout daarom niet automatisch een onbeperkte reeks nieuwe zoekopdrachten.

Beoordeel na het request eerst de HTTP-status en de GraphQL-errors-array op het hoogste niveau. Ook HTTP 200 kan GraphQL-fouten bevatten. Bewaar data.createSearch.urn pas na deze controle. Gebruik de ontvangen URN ongewijzigd voor status- en resultaatopvragingen; splits of reconstrueer het formaat niet. De beginstatus kan verschillen.

De client legt per uitvoering minimaal tenant-UUID, querytekst, tijdreferentie, Search-URN en starttijd vast. Een Search-URN identificeert de volledige uitvoering. Een Partition-URN identificeert daarentegen een deeltaak en een Event Resource Name één gebeurtenis. Deze identificatoren zijn niet uitwisselbaar.

Bestaande zoekopdrachten bewust hergebruiken

Als een passende, al lopende of afgeronde zoekopdracht gebruikt mag worden, is getOrCreateSearch een alternatief:

{
  "operationName": "GetOrCreateSearch",
  "query": "mutation GetOrCreateSearch($input: CreateSearchInput) { getOrCreateSearch(input: $input) { urn status } }",
  "variables": {
    "input": {
      "text": "from process where earliest = -1h | fields host_id, commandline, image_path"
    }
  }
}

Neem hier de URN over uit data.getOrCreateSearch.urn. De koppeling houdt rekening met de invoergegevens en vergelijkt query’s via hun canonieke gestructureerde weergave, niet alleen via identieke tekst. Hergebruik biedt geen garantie op verse resultaten en mag in de client niet als nieuwe uitvoering worden weergegeven. Gebruik bewust createSearch wanneer de taak een nieuwe uitvoering vereist.

Gaat het antwoord na createSearch door een timeout verloren, dan kan de zoekopdracht toch lopen. Blind herhalen kan nog een uitvoering aanmaken. Registreer dit als ‘aanmaak onzeker’ en beslis over hervatting op basis van de vooraf vastgelegde eisen voor hergebruik en actualiteit. getOrCreateSearch bewijst achteraf niet dat precies de verloren uitvoering is teruggevonden.

Voltooiing, gedeeltelijke fouten en vervaltijd controleren

Vraag de toestand op met de opgeslagen Search-URN. Vervang <search-urn> uitsluitend door de werkelijk ontvangen waarde:

{
  "operationName": "SearchDiagnostics",
  "query": "query SearchDiagnostics($urn: URN!) { search(urn: $urn) { urn status errors expireTime outcome { success errors { urn errors } } searchPartitions { urn schemaType status errors } } }",
  "variables": {
    "urn": "<search-urn>"
  }
}

Zolang status op QUEUED of IN_PROGRESS staat, wacht de client tussen de opvragingen. outcome.success: UNKNOWN is vóór voltooiing te verwachten. Een pollinginterval van bijvoorbeeld vijf seconden is een mogelijke clientkeuze, geen gegarandeerde dienstlimiet. Elk request heeft bovendien een timeout nodig en het volledige proces een deadline passend bij de werklast. Daarna blijft de uitvoering onopgehelderd; lokale polling stoppen annuleert de zoekopdracht op de server niet.

Beoordeel bij status: COMPLETE afzonderlijk outcome.success:

WaardeBetekenis
ALLAlle partities zijn geslaagd.
PARTIALSlechts een deel van de partities is geslaagd.
NONEGeen enkele partitie is geslaagd.

Leg voor PARTIAL vóór productiegebruik vast of en waarvoor deelresultaten toegestaan zijn. Een volledig onderzoeksrapport mag ze niet stilzwijgend als totaalbevinding overnemen. Bij NONE is er geen geslaagd zoekbereik waarop een geruststellende conclusie kan worden gebaseerd. outcome.errors koppelt meldingen aan partities; searchPartitions levert hun schema, status en fouten. Ook bij geslaagde uitvoering kan errors op zoek- of partitieniveau waarschuwingen bevatten.

Controleer met expireTime ook de planning voor latere ophaling: lees de benodigde resultaten vóór die tijd en sla ze bij langere behoefte op in een eigen goedgekeurd systeem. Een opgeslagen URN of cursor verlengt de beschikbaarheid niet. Hier wordt geen vaste TTL uit één voorbeeld afgeleid.

Alle resultaatpagina’s lezen

Vraag na voltooiing en beoordeling van de uitvoeringsuitkomst de eerste pagina aan zonder cursor in de variabelen:

{
  "operationName": "SearchResults",
  "query": "query SearchResults($urn: URN!, $limit: Int, $cursor: String) { searchResults(urn: $urn, limit: $limit, cursor: $cursor) { fields { name baseType originSchemaTypes } values totals { total { value } subtotals { schemaType value } } nextCursor } }",
  "variables": {
    "urn": "<search-urn>",
    "limit": 2
  }
}

limit: 2 maakt de paginavolgorde in de pilot eenvoudig te controleren. Het beperkt de rijen per pagina, niet het totale aantal treffers. Kies voor productie een paginagrootte die bij de verwerking past, zonder daaruit een gedocumenteerd maximum of een limiet voor het totale resultaat af te leiden.

Controleer na elke ophaling de HTTP-status, GraphQL-errors en het verwachte antwoordpad. Verwerk de pagina pas daarna. Zelfs na COMPLETE kan resultaatophaling nog tijd kosten; een leestimeout bewijst geen zoekfout. Herhaal tijdelijke leesfouten met begrensde backoff en gebruik dezelfde Search-URN en cursor. De consumer moet voorkomen dat een opnieuw gelezen pagina dubbel in de export terechtkomt.

Bevat data.searchResults.nextCursor een waarde, neem die dan ongewijzigd over in de variabelen van hetzelfde SearchResults-request:

{
  "urn": "<search-urn>",
  "limit": 2,
  "cursor": "<next-cursor>"
}

Dit is alleen het vervangende variables-gedeelte, geen volledige GraphQL-body. <next-cursor> komt uit de direct voorafgaande succesvol verwerkte pagina. Elke cursor blijft gebonden aan de Search-URN die hem heeft geleverd. Niet interpreteren, wijzigen of naar een andere uitvoering overbrengen. Ga door totdat nextCursor null is of ontbreekt. Behandel een herhaalde cursor of overschreden clientdeadline als ophaalfout, niet als geslaagde afronding.

Waarden, metadata en totalen onderscheiden

values bevat JSON-rijobjecten, geen SQL-kolommenlijst of JSON-gecodeerde additionalColumns-string zoals in het LES-resultaatformaat. Vermeldingen kunnen geneste objecten en lijsten bevatten. fields beschrijft de beschikbare veldnamen en typen; een metadatavermelding garandeert geen ingevulde waarde in elke rij. Verwerk zowel ontbrekende velden als expliciet null, zonder die automatisch gelijk te stellen aan een lege string of nul treffers.

baseType dient om waarden te interpreteren. Zo onderscheidt TIMESTAMP_SECONDS seconden van TIMESTAMP_MILLISECONDS en TIMESTAMP_MICROSECONDS; TIMESTAMP_ISO_8601 duidt een ISO-8601-string aan. Verwerk lijst- en maptypen als verzamelingen, niet als één scalar. Ook expireTime is een ISO-8601-tijdstempel. Metadata kunnen geneste velden aanduiden met puntnotatie zoals process_file_hash.md5. De parser mag daarom niet aannemen dat elke dergelijke naam een platte sleutel in het rijobject is.

De optionele waarden totals.total en totals.subtotals hebben betrekking op de volledige resultaatset respectievelijk de bijbehorende schema’s, niet op de lengte van de huidige values-lijst. Verwerk voor volledige ophaling alle pagina’s en vergelijk de verzamelde rijen met de beschikbare totalen. Ontbrekende totalen zijn geen reden om een getal te verzinnen; cursorafronding en een gedocumenteerde ophaalomvang blijven vereist. Ook volledige paginering maakt een PARTIAL-resultaat niet volledig geslaagd.

QL-projectie en enrichment behouden

In het voorbeeld beperkt | fields host_id, commandline, image_path de gebeurtenisvelden van de QL-query. De GraphQL-selectionset bepaalt daarentegen of antwoordonderdelen zoals fields, totals of nextCursor worden meegeleverd. values is een JSON-scalar: afzonderlijke rijvelden kunnen niet via een geneste GraphQL-selectionset worden geselecteerd.

Enrichment voegt afgeleide informatie toe. hostname en enrichSummary mogen niet rechtstreeks in | fields staan. Behoud host_id voor hostnaamresolutie. Zelfs dan is een oplosbare hostnaam niet gegarandeerd. De invoervelden voor enrichSummary hangen van de gebeurtenis af; een smallere projectie kan de samenvatting verkorten. Vergelijk vóór een beperking representatieve gebeurtenissen met de verrijkingen die de consumer nodig heeft.

Een projectie kan het antwoord verkleinen. Ze bewijst geen lagere scankosten of snellere uitvoering. Onnodige antwoordonderdelen weglaten mag vooral niet betekenen dat nextCursor en daarmee de mogelijkheid tot volledige ophaling verloren gaan.

Een bestaande XDR Query-client gecontroleerd vergelijken

De overstap van historische SQL naar Search-QL is geen URL-vervanging en geen mechanische SQL-vertaling. Inventariseer eerst bestaande query’s, vereiste velden en achterliggende rapporten. Het algemene onderscheid tussen XDR-API’s blijft afzonderlijk relevant voor Cases, Detections en andere workflows.

Vergelijk elke historische query in deze volgorde:

  1. Leg de inhoudelijke vraag en benodigde bronnen vast. SQL-tabellen rechtvaardigen geen directe koppeling aan gelijknamige QL-schema’s; controleer elk schema en elke veldnaam afzonderlijk.
  2. Stel identieke expliciete earliest- en latest-grenzen in voor beide zoekopdrachten en documenteer de tijdreferentie. Twee opeenvolgende ‘afgelopen uur’-query’s vormen geen zuivere gelijkheidsvergelijking.
  3. Controleer stringvergelijkingen, hoofdlettergevoeligheid en reguliere expressies. QL ondersteunt geen SQL-joins; joins en afgeleide kolommen vereisen een inhoudelijk opnieuw ontworpen proces. Schakel niet over zonder een opgehelderd equivalent.
  4. Controleer de QL-query eerst interactief onder Security Operations > Data Lake Search. Voer daarna de API-zoekopdracht uit met dezelfde inhoudelijke voorwaarden.
  5. Vergelijk representatieve records, verplichte velden, typen, tijdstempels en enrichment, niet alleen aantallen treffers. Beide clients moeten hun eigen resultaten volledig lezen.
  6. Pas de nieuwe consumer aan op values/fields, Search-URN en cursors. Koppel de oude REST-toestanden finished en succeeded niet blind aan één GraphQL-statusveld: COMPLETE en outcome.success blijven afzonderlijke controles.

Vóór de omschakeling moeten ook het beleid voor gedeeltelijke fouten, begrensde herhalingen, onzekere aanmaak, vervaltijd en exportbewaring werken. De goedgekeurde tenantpilot registreert query, tijdvenster, vereiste velden en alle pagina’s, maar geen secrets. Een lege zoekopdracht is pas inhoudelijk geduid na controle van bron, periode, filters, outcome en volledig gelezen resultaat; ze is geen algemene geruststelling.

Tot acceptatie blijft de bestaande XDR Query-client het afgesproken operationele pad. Mislukt het nieuwe proces, stop dan de omschakeling of zet de toepassing terug op die vooraf behouden client. Daarmee worden geen reeds geëxporteerde gegevens verwijderd of ontstane bewijsgaten hersteld. Een latere nieuwe zoekuitvoering kan door andere tijdreferenties of niet meer beschikbare data afwijken van de eerste.

Fouten gericht afbakenen

  • Request geweigerd: Controleer URL, X-GraphQL-Schema: default, JSON-body, geldig bearer-token en juiste tenant-UUID. Verduidelijk authenticatie en bewerkingsspecifieke toestemming afzonderlijk; zoek niet proefondervindelijk naar een regio. Houd secrets buiten diagnostische uitvoer.
  • HTTP 200, maar geen bruikbare data: Lees de errors op het hoogste niveau. Controleer query, variabeletypen en gevraagde velden voordat vervolgdata worden verwerkt.
  • COMPLETE met PARTIAL of NONE: Beoordeel outcome.errors, zoekfouten en betrokken searchPartitions. Behandel de export als onvolledig of houd hem tegen volgens de vooraf goedgekeurde deelresultaatregel; verwar dit niet met nul treffers.
  • Geen hostnaam of kortere samenvatting: Controleer projectie en gebeurtenistype. Behoud host_id voor hostnaamresolutie; vervang ontbrekende enrichment-invoer niet door hostname of enrichSummary in | fields.
  • Ophaling loopt vast of eindigt te vroeg: Controleer requesttimeout, totale procesdeadline, ongewijzigde URN, laatste succesvol verwerkte pagina en cursorkoppeling. Een kleine limit is geen limiet voor het totale resultaat.
  • Opgeslagen URN levert later geen resultaten meer: Controleer expireTime en al opgeslagen gegevens. Noch URN noch cursor is een permanent archief. Documenteer een eventueel benodigde nieuwe uitvoering als nieuw, niet als herstel van het oorspronkelijke resultaat.

De API wordt verder ontwikkeld. Beperk de client tot de gedocumenteerde bewerkingen createSearch, getOrCreateSearch, search en searchResults en de ondersteunde velden. Aanvullende velden uit introspectie betekenen geen automatische implementatiegoedkeuring.