Collecter les journaux de contexte des composants Qualys
Ce document explique comment ingérer des journaux de contexte d'assets Qualys dans Google Security Operations à l'aide de Google Cloud Storage.
Le contexte des composants Qualys fournit des données d'inventaire des composants hôtes (adresses IP, noms DNS, système d'exploitation, métadonnées du fournisseur de services cloud et tags) à partir de la plate-forme Qualys. Étant donné que ces données sont extraites de l'API Qualys, une fonction Cloud Run interroge régulièrement l'API Qualys Host List, convertit la réponse XML en JSON et l'écrit dans un bucket Cloud Storage, où Google SecOps l'ingère.
Avant de commencer
Assurez-vous de remplir les conditions suivantes :
- Une instance Google SecOps
- Un projet Google Cloud 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 Cloud Storage, des comptes de service, des fonctions Cloud Run, des sujets Pub/Sub et des jobs Cloud Scheduler
- Un compte Qualys avec accès à l'API (un utilisateur avec le rôle Manager ou un rôle qui a accès à l'API et qui peut voir les composants que vous souhaitez collecter)
Créer un bucket Cloud Storage
- Accédez à Google Cloud Console.
- Sélectionnez votre projet ou créez-en un.
- Accédez à Cloud Storage > Buckets.
- Cliquez sur Créer un bucket.
- Fournissez les informations de configuration suivantes :
- Attribuer un nom au bucket : saisissez un nom unique (par exemple,
qualys-asset-context-logs). - Type d'emplacement : choisissez en fonction de vos besoins (régional, birégional ou multirégional).
- Emplacement : sélectionnez l'emplacement (par exemple,
us-central1). - Classe de stockage : sélectionnez Standard.
- Contrôle des accès : sélectionnez Uniforme.
- Attribuer un nom au bucket : saisissez un nom unique (par exemple,
- Cliquez sur Créer.
Collecter les identifiants de l'API Qualys
- Connectez-vous à l'application Web Qualys.
- Identifiez ou créez un utilisateur de l'API :
- Accédez à Utilisateurs > Gestion des utilisateurs.
- Utilisez un utilisateur existant ou cliquez sur Nouveau > Utilisateur, puis attribuez le rôle Administrateur (ou un rôle avec accès à l'API).
- Notez le nom d'utilisateur et le mot de passe de l'utilisateur.
Identifiez l'URL de votre serveur d'API Qualys (elle est spécifique à votre plate-forme Qualys, par exemple
https://qualysapi.qg3.apps.qualys.com). Pour la trouver, consultez Identifier votre plate-forme Qualys.
Créer un compte de service pour la fonction Cloud Run
- 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
qualys-asset-context-sa. - Description du compte de service : saisissez
Service account for Cloud Run function to collect Qualys asset context logs.
- Nom du compte de service : saisissez
- Cliquez sur Créer et continuer.
- Attribuez les rôles suivants :
- Administrateur des objets Storage : écrire des enregistrements d'hôte dans le bucket.
- Demandeur Cloud Run : permet à Pub/Sub d'appeler la fonction.
- Cliquez sur Continue (Continuer), puis sur Done (OK).
Accorder au compte de service l'accès au bucket Cloud Storage
- Accédez à Cloud Storage > Buckets.
- Cliquez sur le nom de votre bucket.
- 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 (
qualys-asset-context-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
- Accédez à Pub/Sub > Sujets.
- Cliquez sur Create topic (Créer un sujet).
- Dans le champ ID du thème, saisissez
qualys-asset-context-trigger. - Cliquez sur Créer.
Créer la fonction Cloud Run pour collecter les journaux
La fonction Cloud Run est déclenchée par des messages Pub/Sub provenant de Cloud Scheduler. Il appelle l'API Qualys FO Host List, convertit la réponse XML en JSON et écrit les enregistrements d'hôte dans le bucket.
- Accédez à Cloud Run.
- Cliquez sur Créer un service.
- Sélectionnez Fonction pour utiliser l'éditeur de code intégré.
- Fournissez les informations de configuration suivantes :
- Nom du service : saisissez
qualys-asset-context-collector. - Région : sélectionnez la région correspondant à votre bucket (par exemple,
us-central1). - Environnement d'exécution : sélectionnez Python 3.12 ou version ultérieure.
- Nom du service : saisissez
- 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
qualys-asset-context-trigger. - Cliquez sur Enregistrer.
- Dans la section Authentification, sélectionnez Exiger l'authentification.
- Développez Conteneurs, mise en réseau, sécurité, puis dans l'onglet Sécurité, définissez Compte de service sur
qualys-asset-context-sa. Dans l'onglet Conteneurs> Variables et secrets, ajoutez les variables d'environnement suivantes :
Nom de la variable Exemple de valeur GCS_BUCKETqualys-asset-context-logsGCS_PREFIXqualys-asset-context/QUALYS_BASE_URLhttps://qualysapi.qg3.apps.qualys.comQUALYS_USERNAMEyour-qualys-usernameQUALYS_PASSWORDyour-qualys-passwordTRUNCATION_LIMIT1000HTTP_TIMEOUT300MAX_PAGES50Définissez Délai avant expiration de la requête sur
600secondes et Mémoire sur 512 Mio ou plus.Cliquez sur Créer. Une fois le service créé, l'éditeur de code intégré s'ouvre.
Ajouter le code de la fonction
- Dans le champ Point d'entrée de la fonction, saisissez
main. Dans l'éditeur de code intégré, remplacez le contenu de
main.pypar le code suivant :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}') raiseCréez un fichier
requirements.txtavec le contenu suivant :functions-framework==3.* google-cloud-storage==2.* requests>=2.31.0 xmltodict>=0.13.0Cliquez sur Déployer et attendez la fin du déploiement.
Créer une tâche Cloud Scheduler
- Accédez à Cloud Scheduler.
- Cliquez sur Créer une tâche.
- Fournissez les informations de configuration suivantes :
- Nom : saisissez
qualys-asset-context-collector-daily. - Région : sélectionnez la même région que la fonction Cloud Run.
- Fréquence : saisissez
0 */6 * * *(toutes les six heures). - Fuseau horaire : sélectionnez UTC.
- Type de cible : sélectionnez Pub/Sub.
- Sujet : sélectionnez
qualys-asset-context-trigger. - Corps du message : saisissez
{}.
- Nom : saisissez
- Cliquez sur Créer.
- Pour vérifier la configuration, cliquez sur Exécuter de force sur le job, puis consultez les journaux Cloud Run et le bucket pour confirmer que les enregistrements d'hôte ont été écrits.
Configurer un flux dans Google SecOps pour ingérer les journaux de contexte des composants Qualys
- Accédez à Paramètres SIEM> Flux.
- Cliquez sur Add New Feed (Ajouter un flux).
- Sur la page suivante, cliquez sur Configurer un seul flux.
- Dans le champ Nom du flux, saisissez un nom pour le flux (par exemple,
Qualys asset context logs). - Sélectionnez Google Cloud Storage V2 comme Type de source.
- Sélectionnez Contexte des assets Qualys comme Type de journal.
- Cliquez sur Obtenir le compte de service à côté du champ Compte de service Chronicle, puis copiez l'adresse e-mail du compte de service.
- Cliquez sur Suivant.
- Spécifiez les valeurs des paramètres d'entrée suivants :
- URI du bucket de stockage : saisissez
gs://qualys-asset-context-logs/qualys-asset-context/. Cette URL doit se terminer par une barre oblique (/). - Options de suppression de la source : sélectionnez l'option de suppression de votre choix.
- Âge maximal des fichiers : incluez les fichiers modifiés au cours des derniers jours. La valeur par défaut est de 180 jours.
- URI du bucket de stockage : saisissez
- Cliquez sur Suivant.
- Vérifiez la configuration de votre nouveau flux sur l'écran Finaliser, puis cliquez sur Envoyer.
Accorder au compte de service Google SecOps l'accès au bucket
- Accédez à Cloud Storage > Buckets.
- Cliquez sur le nom de votre bucket.
- 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 à partir de la configuration du flux.
- Attribuer des rôles : sélectionnez Lecteur d'objets Storage (ou Administrateur des objets Storage si vous avez choisi une option de suppression).
- Cliquez sur Enregistrer.
Table de mappage UDM
| Champ de journal | Mappage UDM | Logique |
|---|---|---|
ASSET_ID |
entity.asset.asset_id |
Mappé directement |
DNS_DATA.HOSTNAME |
entity.asset.hostname |
Mappé directement |
IP |
entity.asset.ip |
Fusionné |
OS |
entity.asset.platform_software.platform |
Mappé : (?i)windows → WINDOWS |
ID |
entity.asset.product_object_id |
Mappé directement |
dataset |
relations |
Fusionné |
| N/A | entity.asset.platform_software.platform |
Constante : WINDOWS |
| N/A | metadata.entity_type |
Constante : ASSET |
| N/A | metadata.product_name |
Constante : QUALYS ASSET CONTEXT |
| N/A | metadata.vendor_name |
Constante : QUALYS ASSET CONTEXT |
DNS_DATA.HOSTNAME |
entity.entity.asset.hostname |
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.