Collecter les journaux Oracle Cloud Infrastructure

Compatible avec :

Ce document explique comment ingérer des journaux d'audit Oracle Cloud Infrastructure (OCI) dans Google Security Operations à l'aide de l'une des méthodes suivantes :

  • Méthode 1 : Google Cloud Storage : une fonction OCI écrit les journaux dans un bucket Cloud Storage, et un flux Google SecOps les lit à partir du bucket.
  • Méthode 2 : Webhook : une fonction OCI envoie les journaux directement à un flux de webhook Google SecOps. Cette méthode n'utilise pas de bucket Cloud Storage.

Les deux méthodes utilisent OCI Connector Hub pour envoyer les journaux d'audit à la fonction, car Oracle Cloud Infrastructure ne peut pas envoyer de journaux directement à Cloud Storage ni à un point de terminaison HTTPS.

Le service Oracle Cloud Infrastructure Audit enregistre automatiquement les appels vers tous les points de terminaison d'API (interface de programmation d'application) publics OCI compatibles en tant qu'événements de journal. Les événements de journaux enregistrés par le service d'audit incluent les appels d'API effectués par la console OCI, l'interface de ligne de commande (CLI), les kits de développement logiciel (SDK), vos propres clients personnalisés ou d'autres services OCI. Les informations contenues dans les journaux incluent l'heure à laquelle l'activité de l'API s'est produite, la source et la cible de l'activité, le type d'action et le type de réponse.

Avant de commencer

Assurez-vous de remplir les conditions suivantes :

  • Une instance Google SecOps
  • Accès privilégié à la console Oracle Cloud, avec les autorisations nécessaires pour créer et gérer les éléments suivants :
    • Connecteurs Connector Hub
    • Applications et fonctions Functions
    • Stratégies IAM
  • Un sous-réseau VCN avec accès à Internet pour la fonction OCI
  • OCI Cloud Shell ou un environnement local avec la CLI Fn
  • Pour la méthode 1 : un projet Google Cloud avec l'API Cloud Storage activée, et les autorisations nécessaires pour créer des buckets Cloud Storage, des comptes de service et des stratégies IAM (Identity and Access Management) de bucket
  • Pour la méthode 2 : autorisation de créer des clés API dans le projet Google Cloud associé à votre instance Google SecOps

Méthode 1 : Cloud Storage

Créer un bucket Cloud Storage

  1. Accédez à la consoleGoogle Cloud .
  2. Sélectionnez votre projet ou créez-en un.
  3. Dans le menu de navigation, accédez à Cloud Storage > Buckets.
  4. Cliquez sur Créer un bucket.
  5. Fournissez les informations de configuration suivantes :

    Paramètre Valeur
    Attribuez un nom au bucket Saisissez un nom unique (par exemple, oci-audit-logs-gcs).
    Type d'emplacement Choisissez celle qui correspond le mieux à vos besoins (régionale, birégionale ou multirégionale).
    Emplacement Sélectionnez l'emplacement (par exemple, us-central1).
    Classe de stockage Standard (recommandé pour les journaux fréquemment consultés)
    Access control (Contrôle des accès) Uniforme (recommandé)
    Outils de protection Facultatif : Activez la gestion des versions d'objets ou la règle de conservation
  6. Cliquez sur Créer.

Configurer Oracle Cloud Infrastructure pour exporter les journaux d'audit vers Cloud Storage

Oracle Cloud Infrastructure n'est pas compatible avec l'exportation intégrée vers Cloud Storage. Vous utilisez le hub de connecteurs de service OCI avec une fonction OCI pour transférer les journaux d'audit vers Cloud Storage.

Créer une fonction Oracle Cloud Infrastructure pour transférer les journaux vers Cloud Storage

  1. Connectez-vous à la console Oracle Cloud.
  2. Ouvrez le menu de navigation, puis sélectionnez Developer Services> Functions> Applications.
  3. Sélectionnez le compartiment dans lequel vous souhaitez créer l'application de fonction.
  4. Cliquez sur Créer une application.
  5. Fournissez les informations de configuration suivantes :
    • Nom : saisissez audit-logs-to-gcs-app.
    • VCN : sélectionnez un réseau cloud virtuel.
    • Sous-réseaux : sélectionnez un sous-réseau avec accès à Internet.
  6. Cliquez sur Créer.
  7. Une fois l'application créée, cliquez sur Getting Started (Premiers pas) et suivez les instructions pour configurer votre environnement de développement local avec la CLI Fn.
  8. Créez un répertoire de fonction sur votre ordinateur local :

    mkdir oci-audit-to-gcs
    cd oci-audit-to-gcs
    
  9. Initialisez une fonction Python :

    fn init --runtime python oci-audit-to-gcs
    cd oci-audit-to-gcs
    
  10. Remplacez le contenu de func.py par le code suivant :

    import io
    import json
    import logging
    import os
    from fdk import response
    from google.cloud import storage
    from google.oauth2 import service_account
    from datetime import datetime
    
    # Configure logging
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger()
    
    # Environment variables
    GCS_BUCKET = os.environ.get('GCS_BUCKET')
    GCS_PREFIX = os.environ.get('GCS_PREFIX', 'oci-audit-logs')
    GCS_CREDENTIALS_JSON = os.environ.get('GCS_CREDENTIALS_JSON')
    
    def handler(ctx, data: io.BytesIO = None):
        """
        OCI Function to forward Audit logs to GCS.
    
        Args:
            ctx: Function context
            data: Input data containing Audit log events
        """
    
        if not all([GCS_BUCKET, GCS_CREDENTIALS_JSON]):
            logger.error('Missing required environment variables: GCS_BUCKET or GCS_CREDENTIALS_JSON')
            return response.Response(
                ctx, response_data=json.dumps({"error": "Missing configuration"}),
                headers={"Content-Type": "application/json"}
            )
    
        try:
            # Parse input data
            body = json.loads(data.getvalue())
            logger.info(f"Received event: {json.dumps(body)}")
    
            # Extract log entries
            log_entries = []
            if isinstance(body, list):
                log_entries = body
            elif isinstance(body, dict):
                # Service Connector Hub sends data in specific format
                if 'data' in body:
                    log_entries = [body['data']] if isinstance(body['data'], dict) else body['data']
                else:
                    log_entries = [body]
    
            if not log_entries:
                logger.info("No log entries to process")
                return response.Response(
                    ctx, response_data=json.dumps({"status": "no_logs"}),
                    headers={"Content-Type": "application/json"}
                )
    
            # Initialize GCS client with service account credentials
            credentials_dict = json.loads(GCS_CREDENTIALS_JSON)
            credentials = service_account.Credentials.from_service_account_info(credentials_dict)
            storage_client = storage.Client(credentials=credentials, project=credentials_dict.get('project_id'))
            bucket = storage_client.bucket(GCS_BUCKET)
    
            # Write logs to GCS as NDJSON
            timestamp = datetime.utcnow().strftime('%Y%m%d_%H%M%S_%f')
            object_key = f"{GCS_PREFIX}/logs_{timestamp}.ndjson"
            blob = bucket.blob(object_key)
    
            ndjson = '\n'.join([json.dumps(entry, ensure_ascii=False) for entry in log_entries]) + '\n'
            blob.upload_from_string(ndjson, content_type='application/x-ndjson')
    
            logger.info(f"Wrote {len(log_entries)} records to gs://{GCS_BUCKET}/{object_key}")
    
            return response.Response(
                ctx, response_data=json.dumps({"status": "success", "records": len(log_entries)}),
                headers={"Content-Type": "application/json"}
            )
    
        except Exception as e:
            logger.error(f'Error processing logs: {str(e)}')
            return response.Response(
                ctx, response_data=json.dumps({"error": str(e)}),
                headers={"Content-Type": "application/json"},
                status_code=500
            )
    

  11. Mettez à jour requirements.txt avec les dépendances suivantes :

    fdk>=0.1.0
    google-cloud-storage>=2.0.0
    google-auth>=2.0.0
    
  12. Déployez la fonction sur OCI :

    fn -v deploy --app audit-logs-to-gcs-app
    
  13. Une fois le déploiement terminé, notez l'OCID de la fonction. Vous l'utiliserez lors de la configuration du hub de connecteurs de service.

Configurer les variables d'environnement de la fonction

  1. Dans la console Oracle Cloud, accédez à Developer Services> Functions> Applications.
  2. Cliquez sur l'application (audit-logs-to-gcs-app).
  3. Cliquez sur le nom de la fonction (oci-audit-to-gcs).
  4. Cliquez sur Configuration
  5. Ajoutez les variables de configuration suivantes :

    Clé Valeur
    GCS_BUCKET Le nom de votre bucket Cloud Storage (par exemple, oci-audit-logs-gcs)
    GCS_PREFIX Préfixe des fichiers journaux (par exemple, oci-audit-logs)
    GCS_CREDENTIALS_JSON Chaîne JSON de la clé de compte de service Google Cloud
  6. Cliquez sur Enregistrer les modifications.

Créer un compte de service Google Cloud pour la fonction Oracle Cloud Infrastructure

La fonction OCI a besoin d'un compte de service Google Cloud pour écrire dans le bucket Cloud Storage.

  1. Dans la console Google Cloud, accédez à IAM et administration > Comptes de service.
  2. Cliquez sur Créer un compte de service.
  3. Fournissez les informations de configuration suivantes :
    • Nom du compte de service : saisissez oci-function-gcs-writer.
    • Description du compte de service : saisissez Service account for OCI Function to write Audit logs to GCS.
  4. Cliquez sur Créer et continuer.
  5. Dans la section Autoriser ce compte de service à accéder au projet, ajoutez le rôle suivant :
    1. Cliquez sur Sélectionner un rôle.
    2. Recherchez et sélectionnez Administrateur des objets Storage.
  6. Cliquez sur Continuer.
  7. Cliquez sur OK.
  8. Cliquez sur l'adresse e-mail du compte de service que vous venez de créer.
  9. Accédez à l'onglet Clés.
  10. Cliquez sur Ajouter une clé> Créer une clé.
  11. Sélectionnez JSON comme type de clé.
  12. Cliquez sur Créer. Le fichier de clé JSON sera téléchargé sur votre ordinateur.
  13. Ouvrez le fichier de clé JSON et copiez l'intégralité de son contenu.
  14. Revenez à la configuration de la fonction dans la console Oracle Cloud.
  15. Collez le contenu JSON dans la variable de configuration GCS_CREDENTIALS_JSON.

Accorder des autorisations IAM sur le bucket Cloud Storage

Accordez au compte de service des autorisations d'écriture sur le bucket Cloud Storage comme suit :

  1. Accédez à Cloud Storage > Buckets.
  2. Cliquez sur le nom de votre bucket (oci-audit-logs-gcs).
  3. Accédez à l'onglet Autorisations.
  4. Cliquez sur Accorder l'accès.
  5. Fournissez les informations de configuration suivantes :
    • Ajouter des comptes principaux : saisissez l'adresse e-mail du compte de service (oci-function-gcs-writer@PROJECT_ID.iam.gserviceaccount.com).
    • Attribuer des rôles : sélectionnez Administrateur des objets Storage.
  6. Cliquez sur Enregistrer.

Créer un connecteur OCI Service Connector Hub

  1. Connectez-vous à la console Oracle Cloud.
  2. Ouvrez le menu de navigation, puis sélectionnez Analytics et IA. Sous Messagerie, sélectionnez Connector Hub.
  3. Sélectionnez le compartiment dans lequel vous souhaitez créer le connecteur de service.
  4. Cliquez sur Créer un connecteur.
  5. Fournissez les informations de configuration suivantes :

    • Informations sur le connecteur :

      Paramètre Valeur
      Nom du connecteur Saisissez audit-logs-to-gcs-connector.
      Description Saisissez Forward OCI Audit logs to Cloud Storage.
      Compartiment de ressources Sélectionnez le compartiment.
    • Configurer la source :

      Paramètre Valeur
      Source Sélectionnez Journalisation.
      Compartiment Sélectionnez le compartiment contenant les journaux d'audit.
      Groupe de journaux Sélectionnez _Audit (groupe de journaux par défaut pour les journaux d'audit).
  6. Cliquez sur + Un autre journal.

  7. Sélectionnez le journal d'audit de votre compartiment (par exemple, _Audit_Include_Subcompartment).

    • Configurez la cible :

      Paramètre Valeur
      Cible Sélectionnez Fonctions.
      Compartiment de fonction Sélectionnez le compartiment contenant la fonction.
      Application de fonction Sélectionner audit-logs-to-gcs-app
      Fonction Sélectionner oci-audit-to-gcs
  8. Accédez à Configurer la tâche (facultatif) et conservez les paramètres par défaut.

  9. Si vous êtes invité à créer une règle (requise pour créer ou mettre à jour un connecteur de service), sélectionnez Créer.

  10. Cliquez sur Créer.

Créer une stratégie IAM pour Service Connector Hub

Le hub de connecteurs de service doit disposer des autorisations nécessaires pour appeler la fonction.

  1. Dans la console Oracle Cloud, accédez à Identity & Security> Policies (Identité et sécurité > Règles).
  2. Sélectionnez le compartiment dans lequel vous avez créé le connecteur Service Connector Hub.
  3. Cliquez sur Créer une règle.
  4. Fournissez les informations de configuration suivantes :
    • Nom : saisissez service-connector-functions-policy.
    • Description : saisissez Allow Service Connector Hub to invoke Functions.
    • Compartiment : sélectionnez le compartiment.
  5. Dans la section Générateur de règles, activez l'option Afficher l'éditeur manuel.
  6. Saisissez les instructions de stratégie suivantes :

    Allow any-user to use fn-function in compartment <compartment-name> where all {request.principal.type='serviceconnector'}
    Allow any-user to use fn-invocation in compartment <compartment-name> where all {request.principal.type='serviceconnector'}
    
  7. Cliquez sur Créer.

Tester l'intégration

  1. Connectez-vous à la console Oracle Cloud.
  2. Effectuez des actions qui génèrent des journaux d'audit (par exemple, créer ou modifier une ressource).
  3. Attendez deux à cinq minutes que les journaux soient traités.
  4. Accédez à Cloud Storage > Buckets dans la console Google Cloud .
  5. Cliquez sur le nom de votre bucket (oci-audit-logs-gcs).
  6. Accédez au dossier du préfixe (oci-audit-logs/).
  7. Vérifiez que de nouveaux fichiers .ndjson apparaissent dans le bucket.

Récupérer le compte de service Google SecOps

Google SecOps utilise un compte de service unique pour lire les données de votre bucket Cloud Storage. Vous devez accorder à ce compte de service l'accès à votre bucket.

Obtenir l'adresse e-mail du compte de service

  1. Accédez à Paramètres SIEM> Flux.
  2. Cliquez sur Ajouter un flux d'actualités.
  3. Cliquez sur Configurer un flux unique.
  4. Dans le champ Nom du flux, saisissez un nom pour le flux (par exemple, Oracle Cloud Audit Logs).
  5. Sélectionnez Google Cloud Storage V2 comme Type de source.
  6. Sélectionnez Journaux d'audit Oracle Cloud Infrastructure comme Type de journal.
  7. Cliquez sur Get Service Account (Obtenir un compte de service). Une adresse e-mail de compte de service unique s'affiche, par exemple :

    chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com
    
  8. Copiez cette adresse e-mail pour l'utiliser à l'étape suivante.

Accorder des autorisations IAM au compte de service Google SecOps

Le compte de service Google SecOps a besoin de deux rôles sur votre bucket Cloud Storage : un rôle "Lecteur des objets Storage" pour lire les objets de journal et un rôle au niveau du bucket pour lire les métadonnées du bucket.

  1. Accédez à Cloud Storage > Buckets.
  2. Cliquez sur le nom de votre bucket (oci-audit-logs-gcs).
  3. Accédez à l'onglet Autorisations.
  4. Cliquez sur Accorder l'accès.
  5. Fournissez les informations de configuration suivantes :
    • Ajouter des comptes principaux : collez l'adresse e-mail du compte de service Google SecOps.
    • Attribuer des rôles : sélectionnez les deux rôles suivants :
      • Lecteur des objets de l'espace de stockage : lit les objets de journal.
      • Lecteur des anciens buckets Storage : lit les métadonnées du bucket. Si vous avez sélectionné l'option de suppression Supprimer les fichiers transférés et les répertoires vides, sélectionnez plutôt Rédacteur d'ancien bucket Storage, qui accorde également l'autorisation de suppression.
  6. Cliquez sur Enregistrer.

Configurer un flux dans Google SecOps pour ingérer les journaux d'audit Oracle Cloud Infrastructure

  1. Accédez à Paramètres SIEM> Flux.
  2. Cliquez sur Ajouter un flux d'actualités.
  3. Cliquez sur Configurer un flux unique.
  4. Dans le champ Nom du flux, saisissez un nom pour le flux (par exemple, Oracle Cloud Audit Logs).
  5. Sélectionnez Google Cloud Storage V2 comme Type de source.
  6. Sélectionnez Journaux d'audit Oracle Cloud Infrastructure comme Type de journal.
  7. Cliquez sur Suivant.
  8. Spécifiez les valeurs des paramètres d'entrée suivants :

    • URL du bucket de stockage : saisissez l'URI du bucket Cloud Storage avec le chemin d'accès du préfixe :

      gs://oci-audit-logs-gcs/oci-audit-logs/
      
    • Remplacez :

      • oci-audit-logs-gcs : nom de votre bucket Cloud Storage.
      • oci-audit-logs : préfixe ou chemin d'accès facultatif où les journaux sont stockés (laissez vide pour la racine).

      Exemples :

      • Bucket racine : gs://company-logs/
      • Avec le préfixe : gs://company-logs/oci-audit-logs/
      • Avec le sous-dossier : gs://company-logs/oracle/audit/
    • Option de suppression de la source : sélectionnez l'option de suppression de votre choix :

      • Ne jamais supprimer les fichiers : ne supprime jamais les fichiers après les transferts (recommandé pour les tests).
      • Supprimer les fichiers transférés et les répertoires vides : supprime les fichiers et les répertoires vides après un transfert réussi.
    • Âge maximal du fichier (jours) : incluez les fichiers modifiés au cours des derniers jours. La valeur par défaut est de 180 jours.

    • Espace de noms de l'élément : espace de noms de l'élément.

    • Étiquettes d'ingestion : étiquette à appliquer aux événements de ce flux.

  9. Cliquez sur Suivant.

  10. Vérifiez la configuration de votre nouveau flux d'actualités sur l'écran Finaliser, puis cliquez sur Envoyer.

Méthode 2 : Webhook

Avec cette méthode, Connector Hub envoie des lots d'entrées de journal d'audit à une fonction OCI, qui les envoie à un flux de webhook Google SecOps via HTTPS. Aucun bucket Cloud Storage n'est impliqué.

Créer un flux de webhook dans Google SecOps

Créer le flux

  1. Accédez à Paramètres SIEM> Flux.
  2. Cliquez sur Ajouter un flux d'actualités.
  3. Sur la page suivante, cliquez sur Configurer un seul flux.
  4. Dans le champ Nom du flux, saisissez un nom pour le flux (par exemple, OCI Audit Logs Webhook).
  5. Sélectionnez Webhook comme type de source.
  6. Sélectionnez Journaux d'audit Oracle Cloud Infrastructure comme Type de journal.
  7. Cliquez sur Suivant.
  8. Spécifiez les valeurs des paramètres d'entrée suivants :
    • Séparateur de division : saisissez \n. La fonction envoie chaque entrée de journal sur sa propre ligne.
    • Espace de noms de l'élément : espace de noms de l'élément.
    • Étiquettes d'ingestion : étiquette à appliquer aux événements de ce flux.
  9. Cliquez sur Suivant.
  10. Vérifiez la configuration de votre nouveau flux d'actualités sur l'écran Finaliser, puis cliquez sur Envoyer.

Générer et enregistrer la clé secrète

  1. Sur la page d'informations du flux, cliquez sur Générer une clé secrète.
  2. Copiez et enregistrez la clé secrète de manière sécurisée.

Obtenir l'URL du point de terminaison du flux

  1. Accédez à l'onglet Détails du flux.
  2. Dans la section Informations sur le point de terminaison, copiez l'URL du point de terminaison du flux. L'URL est au format suivant :

    https://<REGION>-chronicle.googleapis.com/v1alpha/projects/<PROJECT_NUMBER>/locations/<REGION>/instances/<INSTANCE_ID>/feeds/<FEED_ID>:importPushLogs
    
  3. Cliquez sur OK.

Créer une clé API Google Cloud

  1. Accédez à la page Identifiants de la consoleGoogle Cloud .
  2. Sélectionnez le projet associé à votre instance Google SecOps.
  3. Cliquez sur Créer des identifiants> Clé API.
  4. Cliquez sur Modifier la clé API pour restreindre la clé.
  5. Dans le champ Nom, saisissez un nom descriptif (par exemple, oci-audit-webhook).
  6. Sous Restrictions relatives aux API, sélectionnez Restreindre la clé, puis API Chronicle dans la liste Sélectionner des API.
  7. Cliquez sur Enregistrer.
  8. Copiez la valeur de la clé API et enregistrez-la de manière sécurisée.

Créer une fonction OCI pour transférer les journaux vers le webhook

Créer l'application

  1. Connectez-vous à la console Oracle Cloud.
  2. Ouvrez le menu de navigation, puis sélectionnez Developer Services> Functions> Applications.
  3. Sélectionnez le compartiment dans lequel vous souhaitez créer l'application de fonction.
  4. Cliquez sur Créer une application.
  5. Fournissez les informations de configuration suivantes :
    • Nom : saisissez audit-logs-to-secops-app.
    • VCN : sélectionnez un réseau cloud virtuel.
    • Sous-réseaux : sélectionnez un sous-réseau avec accès à Internet : un sous-réseau public avec une passerelle Internet ou un sous-réseau privé avec une passerelle NAT. La fonction doit atteindre le point de terminaison Google SecOps via HTTPS (port 443).
  6. Cliquez sur Créer.

Créer et déployer la fonction

  1. Une fois l'application créée, cliquez sur Getting Started (Premiers pas) et suivez les instructions pour configurer OCI Cloud Shell ou votre environnement de développement local avec la CLI Fn.
  2. Initialisez une fonction Python :

    fn init --runtime python oci-audit-to-secops
    cd oci-audit-to-secops
    
  3. Remplacez le contenu de func.py par le code suivant :

    import io
    import json
    import logging
    import os
    import random
    import time
    from email.utils import parsedate_to_datetime
    
    import requests
    from fdk import response
    
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger()
    
    # The webhook accepts at most 4 MB per request and 1 MB per log line.
    # Connector Hub delivers batches of up to 6 MB, so a batch is sent as several
    # requests, each made of whole log entries.
    MAX_REQUEST_BYTES = 3 * 1024 * 1024
    MAX_LINE_BYTES = 1024 * 1024
    
    MAX_ATTEMPTS = 5
    RETRYABLE_STATUS = {429, 500, 502, 503, 504}
    # OCI stops the function at its configured timeout (300 seconds). Stop retrying
    # early enough to fail cleanly so that Connector Hub retries the whole batch.
    DEADLINE_SECONDS = 240
    
    def to_lines(body):
        """Serialize each log entry from the Connector Hub batch as one JSON line."""
        entries = body if isinstance(body, list) else [body]
        lines = []
        for entry in entries:
            line = json.dumps(entry, ensure_ascii=False, separators=(',', ':')).encode('utf-8')
            if len(line) > MAX_LINE_BYTES:
                entry_id = entry.get('id') if isinstance(entry, dict) else None
                logger.error(f'Skipping log entry {entry_id}: {len(line)} bytes exceeds the 1 MB line limit')
                continue
            lines.append(line)
        return lines
    
    def to_requests(lines):
        """Group whole lines into newline-delimited request bodies below MAX_REQUEST_BYTES."""
        chunk, size = [], 0
        for line in lines:
            if chunk and size + len(line) + 1 > MAX_REQUEST_BYTES:
                yield b'\n'.join(chunk), len(chunk)
                chunk, size = [], 0
            chunk.append(line)
            size += len(line) + 1
        if chunk:
            yield b'\n'.join(chunk), len(chunk)
    
    def retry_after_seconds(value):
        """Parse a Retry-After header given either in seconds or as an HTTP date."""
        if not value:
            return None
        try:
            return max(0.0, float(value))
        except ValueError:
            pass
        try:
            return max(0.0, parsedate_to_datetime(value).timestamp() - time.time())
        except (TypeError, ValueError, IndexError, OverflowError):
            return None
    
    def post(session, url, headers, payload, deadline):
        """Send one request, retrying throttling and server errors until the deadline."""
        status, detail = None, ''
        for attempt in range(1, MAX_ATTEMPTS + 1):
            remaining = deadline - time.monotonic()
            if remaining < 5:
                break
            wait = None
            try:
                resp = session.post(url, data=payload, headers=headers, timeout=(10, min(60, remaining)))
            except requests.RequestException as e:
                status, detail = None, str(e)
            else:
                if 200 <= resp.status_code < 300:
                    return
                status, detail = resp.status_code, resp.text[:500]
                if status not in RETRYABLE_STATUS:
                    raise RuntimeError(f'Webhook rejected the request with HTTP {status}: {detail}')
                wait = retry_after_seconds(resp.headers.get('Retry-After'))
            if wait is None:
                wait = min(30, 2 ** attempt) + random.uniform(0, 1)
            if attempt == MAX_ATTEMPTS or time.monotonic() + wait >= deadline:
                break
            logger.warning(f'Attempt {attempt} failed (HTTP {status}): {detail}. Retrying in {wait:.1f} seconds')
            time.sleep(wait)
        raise RuntimeError(f'Webhook request failed (HTTP {status}): {detail}')
    
    def handler(ctx, data: io.BytesIO = None):
        """Forward a Connector Hub batch of OCI Audit log entries to the webhook feed.
    
        Any exception fails the invocation, and Connector Hub then retries the batch.
        """
        deadline = time.monotonic() + DEADLINE_SECONDS
    
        url = os.environ.get('SECOPS_WEBHOOK_URL')
        api_key = os.environ.get('SECOPS_API_KEY')
        secret_key = os.environ.get('SECOPS_SECRET_KEY')
        if not all([url, api_key, secret_key]):
            raise RuntimeError('Missing configuration: SECOPS_WEBHOOK_URL, SECOPS_API_KEY and SECOPS_SECRET_KEY are required')
    
        raw = data.getvalue() if data else b''
        if not raw.strip():
            logger.info('Received an empty batch')
            return response.Response(
                ctx, response_data=json.dumps({'records': 0}),
                headers={'Content-Type': 'application/json'}
            )
    
        lines = to_lines(json.loads(raw))
        headers = {
            'Content-Type': 'application/json',
            'X-goog-api-key': api_key,
            'X-Webhook-Access-Key': secret_key,
        }
    
        sent = 0
        with requests.Session() as session:
            for payload, count in to_requests(lines):
                post(session, url, headers, payload, deadline)
                sent += count
    
        logger.info(f'Forwarded {sent} log entries')
        return response.Response(
            ctx, response_data=json.dumps({'records': sent}),
            headers={'Content-Type': 'application/json'}
        )
    

  4. Remplacez le contenu de requirements.txt par les dépendances suivantes :

    fdk>=0.1.0
    requests>=2.32.0
    
  5. Ouvrez func.yaml et ajoutez la ligne suivante pour augmenter le délai avant expiration de la fonction, qui passe de 30 secondes par défaut à 300 secondes au maximum :

    timeout: 300
    
  6. Déployez la fonction sur OCI :

    fn -v deploy --app audit-logs-to-secops-app
    

Configurer les variables d'environnement de la fonction

  1. Dans la console Oracle Cloud, accédez à Developer Services> Functions> Applications.
  2. Cliquez sur l'application (audit-logs-to-secops-app).
  3. Cliquez sur le nom de la fonction (oci-audit-to-secops).
  4. Cliquez sur Configuration
  5. Ajoutez les variables de configuration suivantes :

    Clé Valeur
    SECOPS_WEBHOOK_URL URL du point de terminaison du flux
    SECOPS_API_KEY La clé API Google Cloud
    SECOPS_SECRET_KEY Clé secrète du flux
  6. Cliquez sur Enregistrer les modifications.

Activer les journaux de fonction

  1. Sur la page de la liste Applications, sélectionnez audit-logs-to-secops-app.
  2. Sélectionnez l'onglet Surveillance, puis accédez à la section Journaux.
  3. Dans le menu Actions (trois points) de la catégorie Journaux d'appel de fonction, sélectionnez Activer le journal.
  4. Conservez le compartiment, le groupe de journaux et le nom de journal par défaut, ou modifiez-les si nécessaire.
  5. Sélectionnez Activer le journal.

Créer un connecteur OCI Connector Hub

  1. Ouvrez le menu de navigation, puis sélectionnez Analytics et IA. Sous Messagerie, sélectionnez Connector Hub.
  2. Sélectionnez le compartiment dans lequel vous souhaitez créer le connecteur.
  3. Cliquez sur Créer un connecteur.
  4. Fournissez les informations de configuration suivantes :

    • Informations sur le connecteur :

      Paramètre Valeur
      Nom du connecteur Saisissez audit-logs-to-secops-connector.
      Description Saisissez Forward OCI Audit logs to a webhook feed.
      Compartiment de ressources Sélectionnez le compartiment.
    • Configurer la source :

      Paramètre Valeur
      Source Sélectionnez Journalisation.
      Compartiment Sélectionnez le compartiment contenant les journaux d'audit.
      Groupe de journaux Sélectionnez _Audit (groupe de journaux par défaut pour les journaux d'audit).
  5. Cliquez sur + Un autre journal.

  6. Sélectionnez le journal d'audit de votre compartiment (par exemple, _Audit_Include_Subcompartment).

    • Configurez la cible :

      Paramètre Valeur
      Cible Sélectionnez Fonctions.
      Compartiment de fonction Sélectionnez le compartiment contenant la fonction.
      Application de fonction Sélectionner audit-logs-to-secops-app
      Fonction Sélectionner oci-audit-to-secops
  7. Accédez à Configurer la tâche (facultatif) et conservez les paramètres par défaut.

  8. Si vous êtes invité à créer une règle (requise pour créer ou mettre à jour un connecteur de service), sélectionnez Créer.

  9. Cliquez sur Créer.

Créer une stratégie IAM pour le hub de connecteurs

Connector Hub doit disposer des autorisations nécessaires pour appeler la fonction.

  1. Dans la console Oracle Cloud, accédez à Identity & Security> Policies (Identité et sécurité > Règles).
  2. Sélectionnez le compartiment dans lequel vous avez créé le connecteur.
  3. Cliquez sur Créer une règle.
  4. Fournissez les informations de configuration suivantes :
    • Nom : saisissez connector-hub-secops-function-policy.
    • Description : saisissez Allow Connector Hub to invoke the webhook forwarding function.
    • Compartiment : sélectionnez le compartiment.
  5. Dans la section Générateur de règles, activez l'option Afficher l'éditeur manuel.
  6. Saisissez les instructions de stratégie suivantes :

    Allow any-user to use fn-function in compartment <compartment-name> where all {request.principal.type='serviceconnector'}
    Allow any-user to use fn-invocation in compartment <compartment-name> where all {request.principal.type='serviceconnector'}
    
  7. Cliquez sur Créer.

Comment la fonction fournit les journaux

  • Taille de lot : Connector Hub envoie à la fonction des lots d'une taille maximale de 6 Mo, et le webhook accepte jusqu'à 4 Mo par requête. La fonction divise chaque lot en requêtes d'une taille maximale de 3 Mo. Il ne fractionne que les entrées de journal, jamais l'intérieur d'une entrée, et chaque entrée arrive dans Google SecOps sous la forme d'un événement.
  • Nouvelles tentatives : la fonction effectue de nouvelles tentatives pour les réponses HTTP 429 et 5xx avec un intervalle exponentiel entre les tentatives, et respecte l'en-tête Retry-After. Toute autre erreur, ou une requête qui échoue toujours après cinq tentatives, entraîne l'échec de l'appel. Connector Hub relance ensuite l'ensemble du lot et ne déplace pas les lots suivants tant qu'il n'a pas réussi.
  • Conservation : la source Logging de Connector Hub conserve les données non distribuées pendant 24 heures. Si la distribution continue d'échouer pendant plus longtemps, les journaux non distribués les plus anciens sont perdus. Corrigez donc rapidement les erreurs signalées dans le journal de la fonction.
  • Doublons : Connector Hub distribue chaque lot au moins une fois. Lorsqu'un lot est relancé après qu'une partie a déjà été envoyée, Google SecOps peut recevoir ces entrées deux fois.
  • Entrées surdimensionnées : une entrée de journal de plus de 1 Mo dépasse la limite de ligne du webhook. La fonction l'ignore et écrit son ID dans le journal de la fonction.

Vérifier l'intégration

Pour vérifier l'intégration, procédez comme suit :

  1. Effectuez des actions dans la console Oracle Cloud qui génèrent des journaux d'audit (par exemple, créer ou modifier une ressource).
  2. Attendez deux à cinq minutes que Connector Hub transmette les journaux.
  3. Ouvrez le journal d'appel de fonction que vous avez activé et vérifiez qu'il contient des messages Forwarded N log entries. Un message d'erreur inclut l'état HTTP renvoyé par Google SecOps.
  4. Dans Google SecOps, effectuez une recherche de journaux bruts pour le type de journal OCI_AUDIT et vérifiez que les événements d'audit arrivent.

Table de mappage UDM

Champ du journal Mappage UDM Logique
accept_encoding_field additional.fields Fusionné
accept_field additional.fields Fusionné
additional_app additional.fields Fusionné
additional_content_type additional.fields Fusionné
additional_sort_by additional.fields Fusionné
additionaldetails_data additional.fields Fusionné
allow_methods_field additional.fields Fusionné
auth_type_label additional.fields Fusionné
authorization_field additional.fields Fusionné
backend_connect_time_field additional.fields Fusionné
backend_processing_time_field additional.fields Fusionné
caller_id_label additional.fields Fusionné
caller_name_label additional.fields Fusionné
cloud_event_versiom_field additional.fields Fusionné
compartment_id_field additional.fields Fusionné
compartment_name_field additional.fields Fusionné
connection_field additional.fields Fusionné
content_length_field additional.fields Fusionné
content_type_field additional.fields Fusionné
event_grouping_id_field additional.fields Fusionné
event_name_label additional.fields Fusionné
event_resource_label additional.fields Fusionné
event_source_label additional.fields Fusionné
event_type_label additional.fields Fusionné
event_type_versiom_field additional.fields Fusionné
has_compariment_id additional.fields Mappé : true → additional_app
has_sort_by additional.fields Mappé : true → additional_sort_by
listener_name_field additional.fields Fusionné
log_group_id_field additional.fields Fusionné
log_id_field additional.fields Fusionné
message additional.fields Valeurs mappées (41 au total, par exemple \/ → tenant_id_label, \/ → auth_type_label, \/ → `ca...
opc_request_id_field additional.fields Fusionné
origin_field additional.fields Fusionné
param0_field additional.fields Fusionné
param1_field additional.fields Fusionné
referer_field additional.fields Fusionné
request_processing_time_field additional.fields Fusionné
resource_id_field additional.fields Fusionné
routing_rules_engine_errors_field additional.fields Fusionné
routing_rules_matched_rule_field additional.fields Fusionné
routing_rules_rule_hits_field additional.fields Fusionné
routing_rules_rule_misses_field additional.fields Fusionné
source_field additional.fields Fusionné
tenant_id_label additional.fields Fusionné
column3 extensions.auth.type Mappé : login successful → AUTHTYPE_UNSPECIFIED
message extensions.auth.type Mappé : \/ → AUTHTYPE_UNSPECIFIED
column3 metadata.description Mappage direct
data.message metadata.description Mappage direct
column1 metadata.event_timestamp Analysé en tant que yyyy-MM-dd HH:mm:ss
data_event_time metadata.event_timestamp Analysé en tant que yyyy-MM-ddTHH:mm:ss.SSSSSSZ
time metadata.event_timestamp Analysé en tant que ISO8601
metadata_event_type metadata.event_type Mappage direct
type metadata.product_event_type Mappage direct
data_event_id metadata.product_log_id Mappage direct
id metadata.product_log_id Mappage direct
message metadata.product_name Mappé : \/ → OCI_AUDIT
specversion metadata.product_version Mappage direct
message metadata.vendor_name Mappé : \/ → Oracle
message network.application_protocol Mapped: \/ → HTTPS, \/ → HTTP
protocol network.application_protocol Mapped: (?i)HTTPS → HTTPS, (?i)HTTP → HTTP
version network.application_protocol_version Mappage direct
data_request_action network.http.method Mappage direct
method network.http.method Mappage direct
data_identity_userAgent network.http.parsed_user_agent Renommé/Mappé
data_request_agent network.http.parsed_user_agent Renommé/Mappé
url network.http.referral_url Mappage direct
data.backendStatusCode network.http.response_code Mappage direct
data_response_status network.http.response_code Renommé/Mappé
data.userAgent network.http.user_agent Mappage direct
data_identity_userAgent network.http.user_agent Mappage direct
data_request_agent network.http.user_agent Mappage direct
data.receivedBytes network.received_bytes Mappage direct
message network.received_bytes Mappé : \/ → uinteger
data.sentBytes network.sent_bytes Mappage direct
message network.sent_bytes Mappé : \/ → uinteger
data_identity_consoleSessionId network.session_id Renommé/Mappé
data.sslCipher network.tls.cipher Mappage direct
data.sslProtocol network.tls.version Mappage direct
data.host principal.asset.hostname Mappage direct
hostname principal.asset.hostname Mappage direct
column6 principal.asset.ip Fusionné
data.forwardedForAddr principal.asset.ip Fusionné
data_identity_ipAddress principal.asset.ip Mappé : ^(?:[0-9]{1,3}[.]){3}[0-9]{1,3}$ → data_identity_ipAddress
data_request_origin principal.asset.ip Fusionné
ip1 principal.asset.ip Fusionné
ip2 principal.asset.ip Fusionné
message principal.asset.ip Valeurs mappées (7 au total, par exemple \/ → column6, \/ → data_request_origin, \/ → ip2)
src_ip principal.asset.ip Fusionné
data.host principal.hostname Mappage direct
hostname principal.hostname Mappage direct
column6 principal.ip Fusionné
data.forwardedForAddr principal.ip Fusionné
data_identity_ipAddress principal.ip Mappé : ^(?:[0-9]{1,3}[.]){3}[0-9]{1,3}$ → data_identity_ipAddress
data_request_origin principal.ip Fusionné
ip1 principal.ip Fusionné
ip2 principal.ip Fusionné
message principal.ip Valeurs mappées (7 au total, par exemple \/ → column6, \/ → data_request_origin, \/ → ip2)
src_ip principal.ip Fusionné
data_request_headers_sec-ch-ua-platform_0 principal.platform Mappé : (?i)Linux → LINUX, (?i)windows → WINDOWS, (?i)mac/ios → MAC
message principal.platform Mappé : \/ → LINUX, \/ → WINDOWS, \/ → MAC
originalConnection.sourcePort principal.port Mappage direct
src_port principal.port Mappage direct
data_request_headers_oci-original-url_0 principal.url Mappage direct
credentials_label principal.user.attribute.labels Fusionné
message principal.user.attribute.labels Mappé : \/ → credentials_label
data.identity.principalName principal.user.user_display_name Mappage direct
data.username principal.user.user_display_name Mappage direct
data.identity.principalId principal.user.userid Mappage direct
data.principalId principal.user.userid Mappage direct
column3 security_result Mappé : login successful → security_result
message security_result Mappé : \/ → security_result
allow_action security_result.action Fusionné
column3 security_result.action Mappé : login successful → allow_action
message security_result.action Mappé : \/ → allow_action
credential_type_field security_result.detection_fields Fusionné
message security_result.detection_fields Mappé : \/ → credential_type_field
data.response.message security_result.summary Mappage direct
message target.asset.ip Mapped: \/ → originalConnection.destinationIp, \/ → tar_ip
originalConnection.destinationIp target.asset.ip Fusionné
tar_ip target.asset.ip Fusionné
message target.ip Mapped: \/ → originalConnection.destinationIp, \/ → tar_ip
originalConnection.destinationIp target.ip Fusionné
tar_ip target.ip Fusionné
originalConnection.destinationPort target.port Mappage direct
tar_port target.port Mappage direct
message target.resource.attribute.labels Mappé : \/ → namespace_label
namespace_label target.resource.attribute.labels Fusionné
type target.resource.attribute.labels Mappé : listretentionrules → namespace_label
data.resourceId target.resource.name Mappage direct
data.resourceName target.resource.name Mappage direct
bucketId target.resource.product_object_id Mappage direct
data.resourceId target.resource.product_object_id Mappage direct
data_request_id target.resource.product_object_id Mappage direct
message target.resource.resource_type Mappé : \/ → STORAGE_BUCKET
type target.resource.resource_type Mappé : listretentionrules → STORAGE_BUCKET
data_request_path target.url Mappage direct
column2 target.user.email_addresses Fusionné
message target.user.email_addresses Mappé : \/ → column2
N/A extensions.auth.type Constante : AUTHTYPE_UNSPECIFIED
N/A metadata.product_name Constante : OCI_AUDIT
N/A metadata.vendor_name Constante : Oracle
N/A network.application_protocol Constante : HTTPS
N/A principal.platform Constante : LINUX
N/A target.resource.resource_type Constante : STORAGE_BUCKET

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.