Collecter les journaux Qualys Virtual Scanner
Cet analyseur transforme les journaux Qualys Virtual Scanner bruts au format JSON en un format structuré conforme à l'UDM Google Security Operations. Il extrait les champs pertinents tels que les informations sur les éléments, les détails de l'analyse et les failles détectées, puis les mappe aux champs UDM correspondants pour une représentation et une analyse cohérentes.
Avant de commencer
Assurez-vous de remplir les conditions préalables suivantes :
- Instance Google Security Operations.
- Accès privilégié à Google Cloud.
- Accès privilégié à Qualys.
Activer les API requises :
- Connectez-vous à la console Google Cloud .
- Accédez à API et services > Bibliothèque.
- Recherchez les API suivantes et activez-les :
- API Cloud Functions
- API Cloud Scheduler
- Cloud Pub/Sub (requis pour que Cloud Scheduler appelle des fonctions)
Créer un bucket Google Cloud Cloud Storage
- Connectez-vous à la console Google Cloud .
Accédez à la page Buckets Cloud Storage.
Cliquez sur Créer.
Configurez le bucket :
- Nom : saisissez un nom unique qui répond aux exigences de dénomination des buckets (par exemple, qualys-vscanner-bucket).
- Choisissez où stocker vos données : sélectionnez un emplacement.
- Choisissez une classe de stockage pour vos données : sélectionnez une classe de stockage par défaut pour le bucket ou bien classe automatique pour gérer automatiquement les classes de stockage.
- Choisissez comment contrôler l'accès aux objets : sélectionnez ne pas appliquer la protection contre l'accès public, puis sélectionnez un modèle de contrôle des accès pour les objets de votre bucket.
- Classe de stockage : choisissez en fonction de vos besoins (par exemple, Standard).
Cliquez sur Créer.
Créer un compte de service Google Cloud
- Accédez à IAM et administration > Comptes de service.
- Créez un compte de service.
- Attribuez-lui un nom descriptif (par exemple, qualys-user).
- Attribuez au compte de service le rôle Administrateur des objets de l'espace de stockage sur le bucket Cloud Storage que vous avez créé à l'étape précédente.
- Attribuez au compte de service le rôle Demandeur Cloud Functions.
- Créez une clé SSH pour le compte de service.
- Téléchargez un fichier de clé JSON pour le compte de service. Conservez ce fichier de manière sécurisée.
Facultatif : Créez un utilisateur d'API dédié dans Qualys
- Connectez-vous à la console Qualys.
- Accédez à Utilisateurs.
- Cliquez sur Nouveau > Utilisateur.
- Saisissez les informations générales requises pour l'utilisateur.
- Sélectionnez l'onglet Rôle utilisateur.
- Assurez-vous que la case Accès à l'API est cochée pour le rôle.
- Cliquez sur Enregistrer.
Identifier l'URL de votre API Qualys spécifique
Option 1
Identifiez vos URL comme indiqué dans la section Identifier la plate-forme.
Option 2
- Connectez-vous à la console Qualys.
- Accédez à Aide > À propos.
- Faites défiler la page pour afficher ces informations sous "Centre des opérations de sécurité (SOC)".
- Copiez l'URL de l'API Qualys.
Configurer la fonction Cloud
- Accédez à Cloud Functions dans la console Google Cloud .
- Cliquez sur Créer une fonction.
Configurez la fonction :
- Nom : saisissez un nom pour votre fonction (par exemple, fetch-qualys-vscanner).
- Région : sélectionnez une région proche de votre bucket.
- Déclencheur : choisissez un déclencheur HTTP si nécessaire ou Cloud Pub/Sub pour une exécution planifiée.
- Authentification : sécurisez l'accès avec l'authentification.
- Écrivez le code avec un éditeur intégré :
```python from google.cloud import storage import requests import base64 import json # Google Cloud Storage Configuration BUCKET_NAME = "<bucket-name>" FILE_NAME = "qualys_virtual_scanners.json" # Qualys API Credentials QUALYS_USERNAME = "qualys-username" QUALYS_PASSWORD = "<qualys-password>" QUALYS_BASE_URL = "https://<qualys_base_url>" # for example, https://qualysapi.qualys.com def fetch_virtual_scanners(): """Fetch Virtual Scanner details from Qualys.""" auth = base64.b64encode(f"{QUALYS_USERNAME}:{QUALYS_PASSWORD}".encode()).decode() headers = { "Authorization": f"Basic {auth}", "Content-Type": "application/xml" } url = f"{QUALYS_BASE_URL}/api/2.0/fo/scanner/" payload = { "action": "list", "scanner_type": "virtual" } response = requests.post(url, headers=headers, data=payload) response.raise_for_status() return response.text # Qualys API returns XML data def upload_to_gcs(data): """Upload data to Google Cloud Storage.""" client = storage.Client() bucket = client.get_bucket(BUCKET_NAME) blob = bucket.blob(FILE_NAME) blob.upload_from_string(data, content_type="application/xml") def main(request): """Cloud Function entry point.""" try: scanners = fetch_virtual_scanners() upload_to_gcs(scanners) return "Qualys Virtual Scanners data uploaded to Cloud Storage successfully!" except Exception as e: return f"An error occurred: {e}", 500 ```Cliquez sur Déployer une fois la configuration terminée.
Configurer Cloud Scheduler
- Accédez à Cloud Scheduler dans la console Google Cloud .
- Cliquez sur Créer une tâche.
Configurez le job :
- Nom : saisissez un nom pour votre job (par exemple, trigger-fetch-qualys-vscanner).
- Fréquence : utilisez la syntaxe cron pour spécifier la planification (par exemple, "0 0 * * *" pour une exécution quotidienne à minuit).
- Fuseau horaire : définissez le fuseau horaire de votre choix.
- Type de déclencheur : sélectionnez HTTP.
- URL du déclencheur : saisissez l'URL de la fonction Cloud (disponible dans les détails de la fonction après le déploiement).
- Méthode : sélectionnez POST.
Créez le job.
Configurer des flux
Pour configurer un flux, procédez comme suit :
- Accédez à Paramètres > Gestion des données > Flux. Si vous utilisez une plate-forme SIEM uniquement, accédez à Paramètres > Flux.
- Cliquez sur Ajouter un flux d'actualités.
- Sur la page suivante, cliquez sur Configurer un seul flux.
- Dans le champ Nom du flux, saisissez un nom pour le flux, par exemple Journaux du scanner virtuel Qualys.
- Sélectionnez Google Cloud Storage V2 comme Type de source.
- Sélectionnez Qualys Virtual Scanner comme Type de journal.
- Cliquez sur Suivant.
Spécifiez les valeurs des paramètres d'entrée suivants :
- URI du bucket de stockage : URI source du bucket de stockage Google Cloud .
- Option de suppression de la source : sélectionnez l'option de suppression de votre choix.
Cliquez sur Suivant.
Vérifiez la configuration de votre nouveau flux d'actualités sur l'écran Finaliser, puis cliquez sur Envoyer.
Table de mappage UDM
| Champ du journal | Mappage UDM | Logique |
|---|---|---|
| ASSET_ID | entity.entity.asset.asset_id | Mappage direct à partir du champ ASSET_ID. |
| CLOUD_PROVIDER_TAGS.CLOUD_TAG.NAME | entity.relations.entity.resource.attribute.labels.key | Mappage direct à partir du champ CLOUD_PROVIDER_TAGS.CLOUD_TAG.NAME. |
| CLOUD_PROVIDER_TAGS.CLOUD_TAG.VALUE | entity.relations.entity.resource.attribute.labels.value | Mappage direct à partir du champ CLOUD_PROVIDER_TAGS.CLOUD_TAG.VALUE. |
| CLOUD_RESOURCE_ID | entity.relations.entity.resource.id | Mappage direct à partir du champ CLOUD_RESOURCE_ID. |
| DETECTION_LIST.DETECTION.FIRST_FOUND_DATETIME | entity.metadata.threat.first_discovered_time | Mappage direct à partir du champ DETECTION_LIST.DETECTION.FIRST_FOUND_DATETIME, converti en code temporel. |
| DETECTION_LIST.DETECTION.FIRST_REOPENED_DATETIME | entity.metadata.threat.detection_fields.value | Mappage direct à partir du champ DETECTION_LIST.DETECTION.FIRST_REOPENED_DATETIME. La clé est codée en dur en tant que "FIRST_REOPENED_DATETIME". |
| DETECTION_LIST.DETECTION.IS_DISABLED | entity.metadata.threat.detection_fields.value | Mappage direct à partir du champ DETECTION_LIST.DETECTION.IS_DISABLED. La clé est codée en dur en tant que "IS_DISABLED". |
| DETECTION_LIST.DETECTION.LAST_FIXED_DATETIME | entity.metadata.threat.detection_fields.value | Mappage direct à partir du champ DETECTION_LIST.DETECTION.LAST_FIXED_DATETIME. La clé est codée en dur en tant que "LAST_FIXED_DATETIME". |
| DETECTION_LIST.DETECTION.LAST_FOUND_DATETIME | entity.metadata.threat.detection_fields.value | Mappage direct à partir du champ DETECTION_LIST.DETECTION.LAST_FOUND_DATETIME. La clé est codée en dur en tant que "LAST_FOUND_DATETIME". |
| DETECTION_LIST.DETECTION.LAST_PROCESSED_DATETIME | entity.metadata.threat.detection_fields.value | Mappage direct à partir du champ DETECTION_LIST.DETECTION.LAST_PROCESSED_DATETIME. La clé est codée en dur en tant que "LAST_PROCESSED_DATETIME". |
| DETECTION_LIST.DETECTION.LAST_REOPENED_DATETIME | entity.metadata.threat.detection_fields.value | Mappage direct à partir du champ DETECTION_LIST.DETECTION.LAST_REOPENED_DATETIME. La clé est codée en dur en tant que "LAST_REOPENED_DATETIME". |
| DETECTION_LIST.DETECTION.LAST_TEST_DATETIME | entity.metadata.threat.detection_fields.value | Mappage direct à partir du champ DETECTION_LIST.DETECTION.LAST_TEST_DATETIME. La clé est codée en dur en tant que "LAST_TEST_DATETIME". |
| DETECTION_LIST.DETECTION.LAST_UPDATE_DATETIME | entity.metadata.threat.detection_fields.value | Mappage direct à partir du champ DETECTION_LIST.DETECTION.LAST_UPDATE_DATETIME. La clé est codée en dur en tant que "LAST_UPDATE_DATETIME". |
| DETECTION_LIST.DETECTION.PORT | entity.metadata.threat.detection_fields.value | Mappage direct à partir du champ DETECTION_LIST.DETECTION.PORT. La clé est codée en dur en tant que "PORT". |
| DETECTION_LIST.DETECTION.PROTOCOL | entity.metadata.threat.detection_fields.value | Mappage direct à partir du champ DETECTION_LIST.DETECTION.PROTOCOL. La clé est codée en dur en tant que "PROTOCOL". |
| DETECTION_LIST.DETECTION.QID | entity.metadata.threat.detection_fields.value | Mappage direct à partir du champ DETECTION_LIST.DETECTION.QID. La clé est codée en dur en tant que "QID". |
| DETECTION_LIST.DETECTION.RESULTS | entity.metadata.threat.summary | Mappage direct à partir du champ DETECTION_LIST.DETECTION.RESULTS. |
| DETECTION_LIST.DETECTION.SEVERITY | entity.metadata.threat.severity_details | Mappage direct à partir du champ DETECTION_LIST.DETECTION.SEVERITY. |
| DETECTION_LIST.DETECTION.SSL | entity.metadata.threat.detection_fields.value | Mappage direct à partir du champ DETECTION_LIST.DETECTION.SSL. La clé est codée en dur en tant que "SSL". |
| DETECTION_LIST.DETECTION.STATUS | entity.metadata.threat.detection_fields.value | Mappage direct à partir du champ DETECTION_LIST.DETECTION.STATUS. La clé est codée en dur en tant que "STATUS". |
| DETECTION_LIST.DETECTION.TIMES_FOUND | entity.metadata.threat.detection_fields.value | Mappage direct à partir du champ DETECTION_LIST.DETECTION.TIMES_FOUND. La clé est codée en dur en tant que "TIMES_FOUND". |
| DETECTION_LIST.DETECTION.TIMES_REOPENED | entity.metadata.threat.detection_fields.value | Mappage direct à partir du champ DETECTION_LIST.DETECTION.TIMES_REOPENED. La clé est codée en dur en tant que "TIMES_REOPENED". |
| DETECTION_LIST.DETECTION.TYPE | entity.metadata.threat.severity | Mappé à partir du champ DETECTION_LIST.DETECTION.TYPE. Si la valeur est "info" (non sensible à la casse), elle est mappée sur "INFORMATIONAL". Sinon, il est ajouté en tant que champ de détection avec la clé "TYPE". |
| DETECTION_LIST.DETECTION.UNIQUE_VULN_ID | entity.metadata.threat.detection_fields.value | Mappage direct à partir du champ DETECTION_LIST.DETECTION.UNIQUE_VULN_ID. La clé est codée en dur en tant que "UNIQUE_VULN_ID". |
| DNS | entity.entity.asset.hostname | Mappé à partir du champ DNS si DNS_DATA.HOSTNAME est vide. |
| DNS_DATA.HOSTNAME | entity.entity.asset.hostname | Mappage direct à partir du champ DNS_DATA.HOSTNAME. |
| EC2_INSTANCE_ID | entity.relations.entity.resource.product_object_id | Mappage direct à partir du champ EC2_INSTANCE_ID. |
| ID | entity.entity.asset.product_object_id | Mappage direct à partir du champ ID. |
| ID | entity.metadata.product_entity_id | Mappage direct à partir du champ ID. |
| IP | entity.entity.ip | Mappage direct à partir du champ IP. |
| LAST_SCAN_DATETIME | entity.metadata.interval.start_time | Mappage direct à partir du champ LAST_SCAN_DATETIME, converti en code temporel. |
| METADATA.AZURE.ATTRIBUTE.NAME | entity.relations.entity.resource.attribute.labels.key | Mappage direct à partir du champ METADATA.AZURE.ATTRIBUTE.NAME. |
| METADATA.AZURE.ATTRIBUTE.VALUE | entity.relations.entity.resource.attribute.labels.value | Mappage direct à partir du champ METADATA.AZURE.ATTRIBUTE.VALUE. |
| OS | entity.entity.asset.platform_software.platform | Mappé à partir du champ OS. Si la valeur contient "windows" (non sensible à la casse), elle est mappée à "WINDOWS". S'il contient"Linux" (non sensible à la casse), il est mappé sur "LINUX". |
| TAGS.TAG.NAME | entity.relations.entity.resource.attribute.labels.key | Mappage direct à partir du champ TAGS.TAG.NAME. |
| TAGS.TAG.TAG_ID | entity.relations.entity.resource.attribute.labels.value | Mappé à partir du champ TAGS.TAG.TAG_ID. La valeur est précédée de "TAG_ID: ". |
| entity.metadata.collected_timestamp | Code temporel de l'entrée de journal. | |
| entity.metadata.entity_type | Déterminé en fonction de la présence du champ IP. Si IP est présent, il est défini sur "IP_ADDRESS". Sinon, elle est définie sur "ASSET". |
|
| entity.metadata.interval.end_time | Codé en dur sur une valeur de code temporel très élevée (253402300799 secondes). | |
| entity.metadata.product_name | Codé en dur sur "QUALYS_VIRTUAL_SCANNER". | |
| entity.metadata.vendor_name | Codé en dur sur "QUALYS_VIRTUAL_SCANNER". | |
| entity.relations.entity.resource.resource_type | Si CLOUD_SERVICE est "VM", il est défini sur "VIRTUAL_MACHINE". |
|
| entity.relations.entity_type | Codé en dur sur "RESOURCE". | |
| entity.relations.relationship | Codé en dur sur "MEMBER". |
Journal des modifications
Afficher le journal des modifications de cet analyseur
Vous avez encore besoin d'aide ? Obtenez des réponses de membres de la communauté et de professionnels Google SecOps.