Collecter les journaux PingIDM (anciennement ForgeRock OpenIDM)

Version de l'analyseur : 4.0

Compatible avec :

Ce document explique comment ingérer des journaux PingIDM (anciennement ForgeRock OpenIDM) dans Google Security Operations à l'aide de Google Cloud Storage V2.

PingIDM est une plate-forme de gestion des identités qui fournit le provisionnement des utilisateurs, la synchronisation, la gestion des mots de passe et la gouvernance des accès. Il consigne les événements de cycle de vie des identités, les tentatives d'authentification, les opérations de rapprochement et les modifications de configuration dans des journaux d'audit accessibles via REST.

Avant de commencer

Assurez-vous de remplir les conditions préalables suivantes :

  • Une instance Google SecOps.
  • Un projet GCP avec l'API Cloud Storage activée.
  • Autorisations permettant de créer et de gérer des buckets GCS et des règles IAM.
  • Autorisations pour créer des services Cloud Run, des sujets Pub/Sub et des jobs Cloud Scheduler.
  • Accès privilégié à une instance ForgeRock OpenIDM ou PingIDM avec des identifiants d'administrateur.

Créer un bucket Google Cloud Storage

  1. Accédez à la console Google 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, forgerock-openidm-audit-logs).
    Type d'emplacement Choisissez en fonction de vos besoins (région, birégion, multirégion).
    Emplacement Sélectionnez l'emplacement (par exemple, us-central1).
    Classe de stockage Standard (recommandé pour les journaux auxquels vous accédez fréquemment)
    Access control (Contrôle des accès) Uniforme (recommandé)
    Outils de protection Facultatif : Activez la gestion des versions des objets ou la règle de conservation.
  6. Cliquez sur Créer.

Collecter les identifiants ForgeRock OpenIDM

Obtenir l'URL de base ForgeRock OpenIDM

  1. Connectez-vous à votre instance ForgeRock OpenIDM ou PingIDM.
  2. Notez votre URL de base dans la barre d'adresse du navigateur.
    • Format : https://openidm.example.com
    • N'incluez pas de barre oblique finale ni de chemin d'accès comme /admin.

Obtenir des identifiants d'administrateur

  1. Obtenez des identifiants d'administrateur pour votre instance ForgeRock OpenIDM.
  2. Vous avez alors besoin de :
    • Nom d'utilisateur : nom d'utilisateur administrateur (par exemple, openidm-admin)
    • Mot de passe : mot de passe administrateur

Vérifier les autorisations

  1. Connectez-vous à ForgeRock OpenIDM.
  2. Accédez à Configurer > Préférences système > Audit.
  3. Si vous pouvez voir la configuration et les thèmes d'audit, vous disposez des autorisations requises.
  4. Si vous ne voyez pas cette option, contactez votre administrateur pour qu'il vous accorde les autorisations de lecture des journaux d'audit.

Tester l'accès à l'API

  • Testez vos identifiants avant de procéder à l'intégration :

    # Replace with your actual credentials
    OPENIDM_BASE_URL="[https://openidm.example.com](https://openidm.example.com)"
    OPENIDM_USERNAME="openidm-admin"
    OPENIDM_PASSWORD="your-admin-password"
    
    # Test API access to authentication audit topic
    curl -v \
        -H "X-OpenIDM-Username: ${OPENIDM_USERNAME}" \
        -H "X-OpenIDM-Password: ${OPENIDM_PASSWORD}" \
        -H "Accept-API-Version: resource=1.0" \
        -H "Accept: application/json" \
        "${OPENIDM_BASE_URL}/openidm/audit/authentication?_queryFilter=true&_pageSize=1"
    

Réponse attendue : HTTP 200 avec un fichier JSON contenant les événements d'audit.

Créer un compte de service pour la fonction Cloud Run

La fonction Cloud Run a besoin d'un compte de service disposant des autorisations nécessaires pour écrire dans le bucket GCS et être appelée par Pub/Sub.

Créer un compte de service

  1. Dans la console GCP, accédez à IAM et administration > Comptes de service.
  2. Cliquez sur Créer un compte de service.
  3. Fournissez les informations de configuration suivantes :
    • Service account name (Nom du compte de service) : forgerock-openidm-collector-sa
    • Description du compte de service : Service account for Cloud Run function to collect ForgeRock OpenIDM logs
  4. Cliquez sur Créer et continuer.
  5. Dans la section Autoriser ce compte de service à accéder au projet, ajoutez les rôles suivants :
    1. Administrateur des objets Storage : pour écrire des journaux dans le bucket GCS et gérer les fichiers d'état.
    2. Demandeur Cloud Run : pour permettre à Pub/Sub d'appeler la fonction.
    3. Demandeur Cloud Functions : pour autoriser l'appel de fonctions.
  6. Cliquez sur Continuer, puis sur OK.

Accorder des autorisations IAM sur le bucket GCS

  1. Accédez à Cloud Storage > Buckets.
  2. Cliquez sur le nom de votre bucket (par exemple, forgerock-openidm-audit-logs).
  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 (par exemple, forgerock-openidm-collector-sa@PROJECT_ID.iam.gserviceaccount.com).
    • Attribuer des rôles : sélectionnez Administrateur des objets Storage.
  6. Cliquez sur Enregistrer.

Créer un sujet Pub/Sub

  1. Dans la console GCP, accédez à Pub/Sub > Sujets.
  2. Cliquez sur Créer un sujet.
  3. Fournissez les informations de configuration suivantes :
    • ID du thème : forgerock-openidm-trigger
    • Conservez les valeurs par défaut des autres paramètres.
  4. Cliquez sur Créer.

Créer une fonction Cloud Run pour collecter les journaux

  1. Dans la console GCP, accédez à Cloud Run.
  2. Cliquez sur Créer un service.
  3. Sélectionnez Fonction (utilisez un éditeur intégré pour créer une fonction).
  4. Dans la section Configurer, fournissez les informations de configuration suivantes :

    Paramètre Valeur
    Nom du service forgerock-openidm-collector
    Région Sélectionnez la région correspondant à votre bucket GCS (par exemple, us-central1).
    Durée d'exécution Sélectionnez Python 3.12 ou version ultérieure.
  5. Dans la section Déclencheur :

    1. Cliquez sur + Ajouter un déclencheur.
    2. Sélectionnez Cloud Pub/Sub.
    3. Dans Sélectionner un sujet Cloud Pub/Sub, sélectionnez forgerock-openidm-trigger.
    4. Cliquez sur Enregistrer.
  6. Dans la section Authentification :

    1. Sélectionnez Exiger l'authentification.
    2. Consultez Identity and Access Management (IAM).
  7. Faites défiler la page vers le bas, puis développez Conteneurs, mise en réseau, sécurité.

  8. Accédez à l'onglet Sécurité :

    • Compte de service : sélectionnez forgerock-openidm-collector-sa.
  9. Accédez à l'onglet Conteneurs :

    1. Cliquez sur Variables et secrets.
    2. Cliquez sur + Ajouter une variable pour chaque variable d'environnement :
    Nom de la variable Exemple de valeur Description
    GCS_BUCKET forgerock-openidm-audit-logs Nom du bucket GCS
    GCS_PREFIX openidm Préfixe des fichiers journaux
    STATE_KEY openidm/state.json Chemin d'accès au fichier d'état
    OPENIDM_BASE_URL https://openidm.example.com URL de base OpenIDM
    OPENIDM_USERNAME openidm-admin Nom d'utilisateur de l'administrateur OpenIDM
    OPENIDM_PASSWORD your-admin-password Mot de passe administrateur OpenIDM
    AUDIT_TOPICS access,activity,authentication,config,sync Thèmes séparés par une virgule
    PAGE_SIZE 100 Enregistrements par page
    MAX_PAGES 50 Nombre maximal de pages par thème
  10. Dans la section Demandes :

    • Délai avant expiration de la requête : 600 secondes.
  11. Accédez à l'onglet Paramètres :

    • Ressources : mémoire 512 Mio, 1 CPU.
  12. Cliquez sur Créer. Une fois le service créé, l'éditeur de code intégré s'ouvre.

Ajouter un code de fonction

  1. Saisissez main dans le champ Point d'entrée.
  2. Créez deux fichiers dans l'éditeur :

    • main.py:
    import functions_framework
    from google.cloud import storage
    import json
    import os
    import urllib3
    from datetime import datetime, timezone
    
    # Initialize HTTP client with timeouts
    http = urllib3.PoolManager(
        timeout=urllib3.Timeout(connect=5.0, read=30.0),
        retries=False,
    )
    
    # Initialize Storage client
    storage_client = storage.Client()
    
    # Environment variables
    GCS_BUCKET = os.environ.get('GCS_BUCKET')
    GCS_PREFIX = os.environ.get('GCS_PREFIX', 'openidm')
    STATE_KEY = os.environ.get('STATE_KEY', 'openidm/state.json')
    OPENIDM_BASE_URL = os.environ.get('OPENIDM_BASE_URL')
    OPENIDM_USERNAME = os.environ.get('OPENIDM_USERNAME')
    OPENIDM_PASSWORD = os.environ.get('OPENIDM_PASSWORD')
    AUDIT_TOPICS = os.environ.get('AUDIT_TOPICS', 'access,activity,authentication,config,sync').split(',')
    PAGE_SIZE = int(os.environ.get('PAGE_SIZE', '100'))
    MAX_PAGES = int(os.environ.get('MAX_PAGES', '50'))
    
    @functions_framework.cloud_event
    def main(cloud_event):
        """
        Cloud Run function triggered by Pub/Sub to fetch ForgeRock OpenIDM logs and write to GCS.
        """
        if not all([GCS_BUCKET, OPENIDM_BASE_URL, OPENIDM_USERNAME, OPENIDM_PASSWORD]):
            print('Error: Missing required environment variables')
            return
    
        try:
            bucket = storage_client.bucket(GCS_BUCKET)
            state = load_state(bucket, STATE_KEY)
    
            all_events = []
            for topic in AUDIT_TOPICS:
                topic = topic.strip()
                print(f"Fetching audit logs for topic: {topic}")
                events = fetch_audit_logs(topic, state.get(topic, {}))
                all_events.extend(events)
    
                if events:
                    latest_timestamp = max(e.get('timestamp', '') for e in events)
                    state[topic] = {
                        'last_timestamp': latest_timestamp,
                        'last_run': datetime.now(timezone.utc).isoformat(),
                        'events_count': len(events)
                    }
    
            if all_events:
                write_to_gcs(bucket, all_events)
                save_state(bucket, STATE_KEY, state)
                print(f"Successfully processed {len(all_events)} audit events")
            else:
                print("No new audit events to process")
    
        except Exception as e:
            print(f'Error processing logs: {str(e)}')
            raise
    
    def load_state(bucket, key):
        try:
            blob = bucket.blob(key)
            if blob.exists():
                return json.loads(blob.download_as_text())
        except Exception as e:
            print(f"Warning: Could not load state: {e}")
        return {}
    
    def save_state(bucket, key, state):
        try:
            blob = bucket.blob(key)
            blob.upload_from_string(json.dumps(state, indent=2), content_type='application/json')
        except Exception as e:
            print(f"Warning: Could not save state: {e}")
    
    def fetch_audit_logs(topic, topic_state):
        base_url = OPENIDM_BASE_URL.rstrip('/')
        all_events = []
        last_timestamp = topic_state.get('last_timestamp')
        query_filter = 'true' if not last_timestamp else f'timestamp gt "{last_timestamp}"'
        page_offset = 0
        page_count = 0
    
        while page_count < MAX_PAGES:
            try:
                url = f"{base_url}/openidm/audit/{topic}"
                params = {
                    '_queryFilter': query_filter,
                    '_pageSize': str(PAGE_SIZE),
                    '_pagedResultsOffset': str(page_offset),
                    '_sortKeys': 'timestamp'
                }
    
                headers = {
                    'X-OpenIDM-Username': OPENIDM_USERNAME,
                    'X-OpenIDM-Password': OPENIDM_PASSWORD,
                    'Accept-API-Version': 'resource=1.0',
                    'Accept': 'application/json'
                }
    
                response = http.request('GET', url, fields=params, headers=headers)
                if response.status != 200:
                    print(f"API error for topic {topic}: {response.status}")
                    break
    
                data = json.loads(response.data.decode('utf-8'))
                events = data.get('result', [])
                if not events:
                    break
    
                all_events.extend(events)
                page_offset += PAGE_SIZE
                page_count += 1
                if len(events) < PAGE_SIZE:
                    break
            except Exception as e:
                print(f"Error for topic {topic}: {str(e)}")
                break
        return all_events
    
    def write_to_gcs(bucket, events):
        timestamp = datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')
        filename = f"{GCS_PREFIX}/openidm_audit_{timestamp}.json"
        ndjson_content = '\n'.join([json.dumps(event) for event in events])
        bucket.blob(filename).upload_from_string(ndjson_content, content_type='application/x-ndjson')
    
    • requirements.txt:
    functions-framework==3.*
    google-cloud-storage==2.*
    urllib3>=2.0.0
    
  3. Cliquez sur Déployer. Le déploiement prend deux à trois minutes.

Créer une tâche Cloud Scheduler

  1. Dans la console GCP, accédez à Cloud Scheduler.
  2. Cliquez sur Créer une tâche.
  3. Fournissez les informations de configuration suivantes :

    Paramètre Valeur
    Nom forgerock-openidm-collector-hourly
    Région Sélectionnez la même région que la fonction Cloud Run.
    Fréquence 0 * * * * (toutes les heures)
    Fuseau horaire Sélectionnez un fuseau horaire (UTC recommandé).
    Type de cible Pub/Sub
    Sujet forgerock-openidm-trigger
    Corps du message {}
  4. Cliquez sur Créer.

Options de fréquence de programmation

Fréquence Expression Cron Cas d'utilisation
Toutes les 5 minutes */5 * * * * Volume élevé, faible latence
Toutes les heures 0 * * * * Standard (recommandé)
Tous les jours 0 0 * * * Collecte par lot

Tester l'intégration

  1. Dans Cloud Scheduler, cliquez sur Forcer l'exécution pour votre job.
  2. Vérifiez l'exécution dans les journaux Cloud Run. Recherchez : Successfully processed X audit events.
  3. Vérifiez qu'un fichier json a été créé dans votre bucket Cloud Storage, sous le dossier openidm/.

Récupérer le compte de service Google SecOps

Configurer un flux dans Google SecOps

  1. Accédez à Paramètres SIEM > Flux.
  2. Cliquez sur Ajouter un flux > Configurer un seul flux.
  3. Nom du flux : ForgeRock OpenIDM Audit Logs.
  4. Type de source : Google Cloud Storage V2.
  5. Type de journal : FORGEROCK_OPENIDM.
  6. Cliquez sur Obtenir un compte de service et copiez l'adresse e-mail fournie (par exemple, chronicle-12345...).
  7. Cliquez sur Suivant.
  8. URL du bucket de stockage : gs://forgerock-openidm-audit-logs/openidm/.
  9. Option de suppression des sources : sélectionnez l'option de votre choix (par exemple, Jamais).
  10. Cliquez sur Suivant, vérifiez, puis cliquez sur Envoyer.

Accorder des autorisations IAM

  1. Accédez à Cloud Storage > Buckets.
  2. Sélectionnez votre bucket, puis cliquez sur l'onglet Autorisations.
  3. Cliquez sur Accorder l'accès.
  4. Ajouter des comptes principaux : collez l'adresse e-mail du compte de service Google SecOps.
  5. Attribuer des rôles : sélectionnez Lecteur d'objets Storage.
  6. Cliquez sur Enregistrer.

Table de mappage UDM

Champ de journal Mappage UDM Logique
fluenttag_label, topic_label, context_roles_label additional.fields Paires clé-valeur pour le contexte.
Via intermediary.hostname Nom d'hôte du proxy/de l'intermédiaire.
x_forwarded_ip, caller.callerIps intermediary.ip Adresse IP de l'intermédiaire.
timestamp metadata.event_timestamp Code temporel de l'événement.
transactionId metadata.product_deployment_id ID de transaction unique.
eventName metadata.product_event_type Nom de l'événement provenant de ForgeRock.
_id metadata.product_log_id Identifiant unique du journal.
request_method network.http.method Méthode HTTP utilisée.
response.statusCode network.http.response_code Code d'état HTTP.
user_agent network.http.user_agent Chaîne user-agent complète.
client.ip, context.ipAddress principal.ip Adresse IP source de l'acteur.
userId, principalData.0 principal.user.userid ID de l'utilisateur agissant.
security_action security_result.action Décision de sécurité prise.
level security_result.severity Niveau de gravité mappé.
server.ip target.ip Adresse IP du système cible.
http.request.path target.url URL/Chemin cible.
N/A metadata.product_name Définissez-le sur ForgeRock OpenIDM.
N/A metadata.vendor_name Définissez-le sur ForgeRock.
elapsed_time" and "X-Content-Type-Options additional.fields Mappé à partir du journal des modifications
trackingIds.0 metadata.product_log_id Mappé à partir du journal des modifications
context.userRolesProperty", "context.authenticationId", and "context.authenticationIdProperty principal.user.attribute.roles Mappé à partir du journal des modifications
context.component", "context.moduleId", and "context.queryId principal.resource.attribute.labels Mappé à partir du journal des modifications
context.roles", "_normalized.fieldNames", and "_eventId additional.fields 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.