Raccogliere i log di contesto degli asset Qualys
Questo documento spiega come importare i log di contesto degli asset Qualys in Google Security Operations utilizzando Google Cloud Storage.
Il contesto degli asset Qualys fornisce dati di inventario degli asset host (indirizzi IP, nomi DNS, sistema operativo, metadati del provider cloud e tag) dalla piattaforma Qualys. Poiché questi dati vengono estratti dall'API Qualys, una funzione Cloud Run esegue periodicamente query sull'API Qualys Host List, converte la risposta XML in JSON e la scrive in un bucket Cloud Storage, dove viene importata da Google SecOps.
Prima di iniziare
Assicurati di soddisfare i seguenti prerequisiti:
- Un'istanza Google SecOps
- Un progetto cloud Google Cloud con le API Cloud Storage, Cloud Run, Pub/Sub e Cloud Scheduler abilitate
- Autorizzazioni per creare e gestire bucket Cloud Storage, service account, funzioni Cloud Run, argomenti Pub/Sub e job Cloud Scheduler
- Un account Qualys con accesso API (un utente con il ruolo Manager o un ruolo con accesso API e visibilità degli asset che vuoi raccogliere)
Crea un bucket Cloud Storage
- Vai alla console Google Cloud.
- Seleziona il tuo progetto o creane uno nuovo.
- Vai a Cloud Storage > Bucket.
- Fai clic su Crea bucket.
- Fornisci i seguenti dettagli di configurazione:
- Assegna un nome al bucket: inserisci un nome univoco globale (ad esempio
qualys-asset-context-logs). - Tipo di località: scegli in base alle tue esigenze (regione, a due regioni o multiregionale).
- Località: seleziona la località (ad esempio,
us-central1). - Classe di archiviazione: seleziona Standard.
- Controllo dell'accesso: seleziona Uniforme.
- Assegna un nome al bucket: inserisci un nome univoco globale (ad esempio
- Fai clic su Crea.
Raccogliere le credenziali API Qualys
- Accedi all'applicazione web Qualys.
- Identifica o crea un utente API:
- Vai a Utenti > Gestione utenti.
- Utilizza un utente esistente o fai clic su Nuovo > Utente e assegna il ruolo Gestore (o un ruolo con accesso API).
- Registra il nome utente e la password dell'utente.
Identifica l'URL del server API Qualys (è specifico per la tua piattaforma Qualys, ad esempio
https://qualysapi.qg3.apps.qualys.com). Per trovarlo, consulta Identificare la piattaforma Qualys.
Crea un account di servizio per la funzione Cloud Run
- Vai a IAM e amministrazione > Service account.
- Fai clic su Crea service account.
- Fornisci i seguenti dettagli di configurazione:
- Nome service account: inserisci
qualys-asset-context-sa. - Descrizione del service account: inserisci
Service account for Cloud Run function to collect Qualys asset context logs.
- Nome service account: inserisci
- Fai clic su Crea e continua.
- Concedi i seguenti ruoli:
- Amministratore oggetti Storage: scrive i record host nel bucket.
- Cloud Run Invoker: consente a Pub/Sub di richiamare la funzione.
- Fai clic su Continua, quindi su Fine.
Concedi al account di servizio l'accesso al bucket Cloud Storage
- Vai a Cloud Storage > Bucket.
- Fai clic sul nome del bucket.
- Vai alla scheda Autorizzazioni.
- Fai clic su Concedi l'accesso.
- Fornisci i seguenti dettagli di configurazione:
- Aggiungi entità: inserisci l'email del account di servizio (
qualys-asset-context-sa@<PROJECT_ID>.iam.gserviceaccount.com). - Assegna i ruoli: seleziona Storage Object Admin.
- Aggiungi entità: inserisci l'email del account di servizio (
- Fai clic su Salva.
Crea un argomento Pub/Sub
- Vai a Pub/Sub > Argomenti.
- Fai clic su Crea argomento.
- Nel campo ID argomento, inserisci
qualys-asset-context-trigger. - Fai clic su Crea.
Crea la funzione Cloud Run per raccogliere i log
La funzione Cloud Run viene attivata dai messaggi Pub/Sub di Cloud Scheduler. Chiama l'API Qualys FO Host List, converte la risposta XML in JSON e scrive i record host nel bucket.
- Vai a Cloud Run.
- Fai clic su Crea servizio.
- Seleziona Funzione per utilizzare l'editor di codice incorporato.
- Fornisci i seguenti dettagli di configurazione:
- Nome del servizio: inserisci
qualys-asset-context-collector. - Regione: seleziona la regione corrispondente al tuo bucket (ad esempio
us-central1). - Runtime: seleziona Python 3.12 o versioni successive.
- Nome del servizio: inserisci
- Nella sezione Trigger:
- Fai clic su Aggiungi trigger.
- Seleziona Cloud Pub/Sub.
- In Seleziona un argomento Cloud Pub/Sub, seleziona
qualys-asset-context-trigger. - Fai clic su Salva.
- Nella sezione Autenticazione, seleziona Richiedi autenticazione.
- Espandi Container, networking, sicurezza e nella scheda Sicurezza imposta Service account su
qualys-asset-context-sa. Nella scheda Container > Variabili e secret, aggiungi le seguenti variabili di ambiente:
Nome variabile Valore di esempio GCS_BUCKETqualys-asset-context-logsGCS_PREFIXqualys-asset-context/QUALYS_BASE_URLhttps://qualysapi.qg3.apps.qualys.comQUALYS_USERNAMEyour-qualys-usernameQUALYS_PASSWORDyour-qualys-passwordTRUNCATION_LIMIT1000HTTP_TIMEOUT300MAX_PAGES50Imposta Timeout richiesta su
600secondi e Memoria su 512 MiB o un valore superiore.Fai clic su Crea. Una volta creato il servizio, si apre l'editor di codice incorporato.
Aggiungi il codice per la funzione
- Nel campo Entry point della funzione, inserisci
main. Nell'editor di codice incorporato, sostituisci i contenuti di
main.pycon il seguente codice:import functions_framework from google.cloud import storage import os import time import uuid import json import base64 import requests import xmltodict storage_client = storage.Client() GCS_BUCKET = os.environ.get('GCS_BUCKET') GCS_PREFIX = os.environ.get('GCS_PREFIX', 'qualys-asset-context/') QUALYS_BASE_URL = os.environ.get('QUALYS_BASE_URL') QUALYS_USERNAME = os.environ.get('QUALYS_USERNAME') QUALYS_PASSWORD = os.environ.get('QUALYS_PASSWORD') TRUNCATION_LIMIT = int(os.environ.get('TRUNCATION_LIMIT', '1000')) HTTP_TIMEOUT = int(os.environ.get('HTTP_TIMEOUT', '300')) MAX_PAGES = int(os.environ.get('MAX_PAGES', '50')) def _headers(): """Qualys FO API requires Basic auth and the X-Requested-With header.""" token = base64.b64encode(f'{QUALYS_USERNAME}:{QUALYS_PASSWORD}'.encode()).decode() return {'Authorization': f'Basic {token}', 'X-Requested-With': 'Cloud Run function'} def _extract_hosts(xml_text): """Parse the FO Host List XML into (list_of_host_dicts, next_page_url).""" doc = xmltodict.parse(xml_text) response = (doc.get('HOST_LIST_OUTPUT') or {}).get('RESPONSE') or {} host_list = (response.get('HOST_LIST') or {}).get('HOST') if host_list is None: hosts = [] elif isinstance(host_list, list): hosts = host_list else: hosts = [host_list] # When the result is truncated, RESPONSE contains <WARNING><URL>...</URL></WARNING>. warning = response.get('WARNING') next_url = warning.get('URL') if isinstance(warning, dict) else None return hosts, next_url def _write_hosts(bucket, hosts, page_num): """Write one batch of hosts to GCS as JSON, one host per line.""" ts_path = time.strftime('%Y/%m/%d', time.gmtime()) uniq = f'{int(time.time() * 1e6)}_{uuid.uuid4().hex[:8]}' key = f'{GCS_PREFIX}{ts_path}/qualys_asset_context_p{page_num:03d}_{uniq}.json' lines = [json.dumps(host, separators=(',', ':')) for host in hosts] bucket.blob(key).upload_from_string('\n'.join(lines), content_type='application/x-ndjson') return key @functions_framework.cloud_event def main(cloud_event): """Triggered by Pub/Sub to pull the Qualys host asset inventory and write it to GCS.""" if not all([GCS_BUCKET, QUALYS_BASE_URL, QUALYS_USERNAME, QUALYS_PASSWORD]): print('Error: missing required environment variables') return bucket = storage_client.bucket(GCS_BUCKET) session = requests.Session() session.headers.update(_headers()) url = f"{QUALYS_BASE_URL.rstrip('/')}/api/2.0/fo/asset/host/" params = { 'action': 'list', 'details': 'All', 'truncation_limit': TRUNCATION_LIMIT, # show_cloud_tags, host_metadata, and show_tags add the cloud provider # tags, cloud instance metadata, and asset tags that the parser maps. 'show_cloud_tags': 1, 'host_metadata': 'all', 'show_tags': 1, } pages = 0 total = 0 try: while pages < MAX_PAGES: resp = session.get(url, params=params, timeout=HTTP_TIMEOUT) resp.raise_for_status() hosts, next_url = _extract_hosts(resp.text) if hosts: _write_hosts(bucket, hosts, pages + 1) total += len(hosts) pages += 1 if not next_url: break # The pagination URL already includes every query parameter. url, params = next_url, None print(f'Wrote {total} hosts across {pages} pages') except Exception as e: print(f'Error collecting Qualys asset context: {e}') raiseCrea un file
requirements.txtcon il seguente contenuto:functions-framework==3.* google-cloud-storage==2.* requests>=2.31.0 xmltodict>=0.13.0Fai clic su Esegui il deployment e attendi il completamento del deployment.
Crea un job Cloud Scheduler
- Vai a Cloud Scheduler.
- Fai clic su Crea job.
- Fornisci i seguenti dettagli di configurazione:
- Nome: inserisci
qualys-asset-context-collector-daily. - Regione: seleziona la stessa regione della funzione Cloud Run.
- Frequenza: inserisci
0 */6 * * *(ogni sei ore). - Fuso orario: seleziona UTC.
- Tipo di target: seleziona Pub/Sub.
- Argomento: seleziona
qualys-asset-context-trigger. - Corpo del messaggio: inserisci
{}.
- Nome: inserisci
- Fai clic su Crea.
- Per verificare la configurazione, fai clic su Forza esecuzione nel job, quindi controlla i log di Cloud Run e il bucket per verificare che i record host siano stati scritti.
Configura un feed in Google SecOps per importare i log di contesto degli asset Qualys
- Vai a Impostazioni SIEM > Feed.
- Fai clic su Aggiungi nuovo feed.
- Nella pagina successiva, fai clic su Configura un singolo feed.
- Nel campo Nome feed, inserisci un nome per il feed (ad esempio,
Qualys asset context logs). - Seleziona Google Cloud Storage V2 come Tipo di origine.
- Seleziona Contesto asset Qualys come Tipo di log.
- Fai clic su Ottieni service account accanto al campo Service account Chronicle e copia l'email dell'account di servizio.
- Fai clic su Avanti.
- Specifica i valori per i seguenti parametri di input:
- URI bucket di archiviazione: inserisci
gs://qualys-asset-context-logs/qualys-asset-context/. Questo URL deve terminare con una barra finale (/). - Opzioni di eliminazione delle fonti: seleziona l'opzione di eliminazione in base alle tue preferenze.
- Età massima file: includi i file modificati nell'ultimo numero di giorni. Il valore predefinito è 180 giorni.
- URI bucket di archiviazione: inserisci
- Fai clic su Avanti.
- Controlla la nuova configurazione del feed nella schermata Finalizza e poi fai clic su Invia.
Concedi al account di servizio Google SecOps l'accesso al bucket
- Vai a Cloud Storage > Bucket.
- Fai clic sul nome del bucket.
- Vai alla scheda Autorizzazioni.
- Fai clic su Concedi l'accesso.
- Fornisci i seguenti dettagli di configurazione:
- Aggiungi entità: incolla l'email del account di servizio Google SecOps dalla configurazione del feed.
- Assegna i ruoli: seleziona Visualizzatore oggetti Storage (o Storage Object Admin se hai scelto un'opzione di eliminazione).
- Fai clic su Salva.
Tabella di mappatura UDM
| Campo log | Mappatura UDM | Logica |
|---|---|---|
ASSET_ID |
entity.asset.asset_id |
Mappato direttamente |
DNS_DATA.HOSTNAME |
entity.asset.hostname |
Mappato direttamente |
IP |
entity.asset.ip |
Unita |
OS |
entity.asset.platform_software.platform |
Mappato: (?i)windows → WINDOWS |
ID |
entity.asset.product_object_id |
Mappato direttamente |
dataset |
relations |
Unita |
| N/D | entity.asset.platform_software.platform |
Costante: WINDOWS |
| N/D | metadata.entity_type |
Costante: ASSET |
| N/D | metadata.product_name |
Costante: QUALYS ASSET CONTEXT |
| N/D | metadata.vendor_name |
Costante: QUALYS ASSET CONTEXT |
DNS_DATA.HOSTNAME |
entity.entity.asset.hostname |
Mappato dal log delle modifiche |
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.