Collecter les journaux BeyondTrust Endpoint Privilege Management

Compatible avec :

Ce document explique comment ingérer des journaux BeyondTrust Endpoint Privilege Management (EPM) dans Google Security Operations à l'aide d'AWS S3. L'analyseur se concentre sur la transformation des données de journaux JSON brutes de BeyondTrust Endpoint en un format structuré conforme à l'Unified Data Model (UDM). Il initialise d'abord les valeurs par défaut de différents champs, puis analyse la charge utile JSON et mappe ensuite des champs spécifiques du journal brut dans les champs UDM correspondants de l'objet event.idm.read_only_udm.

Avant de commencer

Assurez-vous de remplir les conditions suivantes :

  • Instance Google SecOps
  • Accès privilégié à AWS
  • Accès privilégié à BeyondTrust Endpoint Privilege Management

Configurer AWS IAM pour l'ingestion Google SecOps

  1. Créez un utilisateur en suivant ce guide de l'utilisateur : Créer un utilisateur IAM.
  2. Sélectionnez l'utilisateur créé.
  3. Sélectionnez l'onglet Identifiants de sécurité.
  4. Cliquez sur Créer une clé d'accès dans la section Clés d'accès.
  5. Sélectionnez Service tiers comme Cas d'utilisation.
  6. Cliquez sur Suivant.
  7. Facultatif : Ajoutez un tag de description.
  8. Cliquez sur Créer une clé d'accès.
  9. Cliquez sur Télécharger le fichier CSV pour enregistrer la clé d'accès et la clé d'accès secrète pour référence ultérieure.
  10. Cliquez sur OK.
  11. Sélectionnez l'onglet Autorisations.
  12. Cliquez sur Ajouter des autorisations dans la section Règles d'autorisation.
  13. Sélectionnez Ajouter des autorisations.
  14. Sélectionnez Joindre directement des règles.
  15. Recherchez et sélectionnez la règle AmazonS3FullAccess.
  16. Cliquez sur Suivant.
  17. Cliquez sur Ajouter des autorisations.

Configurer BeyondTrust EPM pour l'accès à l'API

  1. Connectez-vous à la console Web BeyondTrust Privilege Management en tant qu'administrateur.
  2. Accédez à Configuration du système > API REST > Jetons.
  3. Cliquez sur Ajouter un jeton.
  4. Fournissez les informations de configuration suivantes :
    • Nom : saisissez Google SecOps Collector.
    • Niveaux d'accès : sélectionnez Audit:Read et d'autres niveaux d'accès selon vos besoins.
  5. Enregistrez et copiez la valeur du jeton (il s'agit de votre BPT_API_TOKEN).
  6. Copiez votre URL de base de l'API. Elle est généralement https://<your-epm-server>/api/v3 ou /api/v2, selon votre version (vous l'utiliserez comme BPT_API_URL).

Créer un bucket AWS S3

  1. Connectez-vous à l'AWS Management Console.
  2. Accédez à la console AWS> Services > S3 > Créer un bucket.
  3. Fournissez les informations de configuration suivantes :
    • Nom du bucket : my-beyondtrust-logs.
    • Région : [votre choix] > Créer.

Créer un rôle IAM pour EC2

  1. Connectez-vous à l'AWS Management Console.
  2. Accédez à la console AWS> Services > IAM > Rôles > Créer un rôle.
  3. Fournissez les informations de configuration suivantes :
    • Entité approuvée : Service AWS > EC2 > Suivant.
    • Associez l'autorisation AmazonS3FullAccess (ou une règle limitée à votre bucket) > Suivant.
    • Nom du rôle : EC2-S3-BPT-Writer > Créer un rôle.

Facultatif : Lancez et configurez votre VM de collecte EC2

  1. Connectez-vous à l'AWS Management Console.
  2. Accédez à Services.
  3. Dans la barre de recherche, saisissez "EC2" et sélectionnez-le.
  4. Dans le tableau de bord EC2, cliquez sur Instances.
  5. Cliquez sur Lancer des instances.
  6. Fournissez les informations de configuration suivantes :
    • Nom : saisissez BPT-Log-Collector.
    • AMI : sélectionnez Ubuntu Server 22.04 LTS.
    • Type d'instance : t3.micro (ou plus grand), puis cliquez sur Suivant.
    • Réseau : assurez-vous que le paramètre "Réseau" est défini sur votre VPC par défaut.
    • Rôle IAM : sélectionnez le rôle IAM EC2-S3-BPT-Writer dans le menu.
    • Attribuer automatiquement une adresse IP publique : Activer (ou assurez-vous de pouvoir y accéder à l'aide d'un VPN) > Suivant.
    • Ajouter du stockage : conservez la configuration de stockage par défaut (8 Gio), puis cliquez sur Suivant.
    • Sélectionnez Créer un groupe de sécurité.
    • Règle entrante : cliquez sur Ajouter une règle.
    • Type : sélectionnez SSH.
    • Port : 22
    • Source : votre adresse IP
    • Cliquez sur Vérifier et lancer.
    • Sélectionnez ou créez une paire de clés.
    • Cliquez sur Download Key Pair (Télécharger la paire de clés).
    • Enregistrez le fichier PEM téléchargé. Vous aurez besoin de ce fichier pour vous connecter à votre instance à l'aide de SSH.
  7. Connectez-vous à votre machine virtuelle (VM) à l'aide de SSH :

    chmod 400 ~/Downloads/your-key.pem
    ssh -i ~/Downloads/your-key.pem ubuntu@<EC2_PUBLIC_IP>
    

Installer les prérequis du collecteur

  1. Exécutez la commande suivante :

    # Update OS
    sudo apt update && sudo apt upgrade -y
    
    # Install Python, Git
    sudo apt install -y python3 python3-venv python3-pip git
    
    # Create & activate virtualenv
    python3 -m venv ~/bpt-venv
    source ~/bpt-venv/bin/activate
    
    # Install libraries
    pip install requests boto3
    
  2. Créez un répertoire et un fichier d'état :

    sudo mkdir -p /var/lib/bpt-collector
    sudo touch /var/lib/bpt-collector/last_run.txt
    sudo chown ubuntu:ubuntu /var/lib/bpt-collector/last_run.txt
    
  3. Initialisez-le (par exemple, sur "il y a une heure") :

    echo "$(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ)" > /var/lib/bpt-collector/last_run.txt
    

Déployer le script du collecteur Armis

  1. Créez un dossier pour le projet :

    mkdir ~/bpt-collector && cd ~/bpt-collector
    
  2. Exportez les variables d'environnement requises (par exemple, dans ~/.bashrc) :

    export BPT_API_URL="https://<your-subdomain>-services.pm.beyondtrustcloud.com"
    export BPT_CLIENT_ID="your-client-id"
    export BPT_CLIENT_SECRET="your-client-secret"
    export S3_BUCKET="my-bpt-logs"
    export S3_PREFIX="bpt/"
    export STATE_FILE="/var/lib/bpt-collector/last_run.txt"
    export PAGE_SIZE="100"
    
  3. Créez collector_bpt.py et saisissez le code suivant :

    #!/usr/bin/env python3
    import os, sys, json, boto3, requests
    from datetime import datetime, timezone, timedelta
    
    # ── UTILS ─────────────────────────────────────────────────────────────────
    def must_env(var):
        val = os.getenv(var)
        if not val:
            print(f"ERROR: environment variable {var} is required", file=sys.stderr)
            sys.exit(1)
        return val
    
    def ensure_state_file(path):
        d = os.path.dirname(path)
        if not os.path.isdir(d):
            os.makedirs(d, exist_ok=True)
        if not os.path.isfile(path):
            ts = (datetime.now(timezone.utc) - timedelta(hours=1))\
                .strftime("%Y-%m-%dT%H:%M:%SZ")
            with open(path, "w") as f:
                f.write(ts)
    
    # ── CONFIG ─────────────────────────────────────────────────────────────────
    BPT_API_URL    = must_env("BPT_API_URL")       # for example, https://subdomain-services.pm.beyondtrustcloud.com
    CLIENT_ID      = must_env("BPT_CLIENT_ID")
    CLIENT_SECRET  = must_env("BPT_CLIENT_SECRET")
    S3_BUCKET      = must_env("S3_BUCKET")
    S3_PREFIX      = os.getenv("S3_PREFIX", "")    # for example, "bpt/"
    STATE_FILE     = os.getenv("STATE_FILE", "/var/lib/bpt-collector/last_run.txt")
    PAGE_SIZE      = int(os.getenv("PAGE_SIZE", "100"))
    # ── END CONFIG ─────────────────────────────────────────────────────────────
    
    ensure_state_file(STATE_FILE)
    
    def read_last_run():
        with open(STATE_FILE, "r") as f:
            ts = f.read().strip()
        return datetime.fromisoformat(ts.replace("Z", "+00:00"))
    
    def write_last_run(dt):
        with open(STATE_FILE, "w") as f:
            f.write(dt.strftime("%Y-%m-%dT%H:%M:%SZ"))
    
    def get_oauth_token():
        resp = requests.post(
            f"{BPT_API_URL}/oauth/connect/token",
            headers={"Content-Type": "application/x-www-form-urlencoded"},
            data={
                "grant_type":    "client_credentials",
                "client_id":     CLIENT_ID,
                "client_secret": CLIENT_SECRET
            }
        )
        resp.raise_for_status()
        return resp.json()["access_token"]
    
    def fetch_events(token, start, end):
        headers = {"Authorization": f"Bearer {token}"}
        offset = 0
        while True:
            params = {
                "startTime": start,
                "endTime":   end,
                "limit":     PAGE_SIZE,
                "offset":    offset
            }
            resp = requests.get(
                f"{BPT_API_URL}/management-api/v1/Audit/Events",
                headers=headers, params=params
            )
            resp.raise_for_status()
            events = resp.json().get("events", [])
            if not events:
                break
            for e in events:
                yield e
            offset += PAGE_SIZE
    
    def upload_to_s3(obj, key):
        boto3.client("s3").put_object(
            Bucket=S3_BUCKET, Key=key,
            Body=json.dumps(obj).encode("utf-8")
        )
    
    def main():
        # 1) determine window
        start_dt = read_last_run()
        end_dt   = datetime.now(timezone.utc)
        START = start_dt.strftime("%Y-%m-%dT%H:%M:%SZ")
        END   = end_dt.strftime("%Y-%m-%dT%H:%M:%SZ")
        print(f"Fetching events from {START} to {END}")
    
        # 2) authenticate and fetch
        token = get_oauth_token()
        count = 0
        for idx, evt in enumerate(fetch_events(token, START, END), start=1):
            key = f"{S3_PREFIX}{end_dt.strftime('%Y/%m/%d')}/evt_{int(end_dt.timestamp())}_{idx}.json"
            upload_to_s3(evt, key)
            count += 1
        print(f"Uploaded {count} events")
    
        # 3) persist state
        write_last_run(end_dt)
    
    if __name__ == "__main__":
        main()
    
  4. Rendez-le exécutable :

    chmod +x collector_bpt.py
    

Planifier une exécution quotidienne avec Cron

  1. Exécutez la commande suivante :

    crontab -e
    
  2. Ajoutez le job quotidien à minuit UTC :

    0 0 * * * cd ~/bpt-collector && source ~/bpt-venv/bin/activate && ./collector_bpt.py >> ~/bpt-collector/bpt.log 2>&1
    

Configurer des flux

Il existe deux points d'entrée différents pour configurer les flux dans la plate-forme Google SecOps :

  • Paramètres SIEM> Flux
  • Plate-forme de contenu > Packs de contenu

Configurer des flux à partir de Paramètres SIEM > Flux

Pour configurer un flux, procédez comme suit :

  1. Accédez à Paramètres SIEM > Flux.
  2. Cliquez sur Add New Feed (Ajouter un flux).
  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, Journaux BeyondTrust EPM).
  5. Sélectionnez Amazon S3 comme Type de source.
  6. Sélectionnez Beyondtrust Endpoint Privilege Management comme type de journal.
  7. Cliquez sur Suivant.
  8. Spécifiez les valeurs des paramètres d'entrée suivants :

    • Région : région dans laquelle se trouve le bucket Amazon S3.
    • URI S3 : URI du bucket (au format s3://your-log-bucket-name/). Remplacez les éléments suivants :
      • your-log-bucket-name : nom du bucket.
    • L'URI est : sélectionnez Répertoire ou Répertoire incluant des sous-répertoires.
    • Options de suppression de la source : sélectionnez l'option de suppression de votre choix.
    • ID de clé d'accès : clé d'accès utilisateur ayant accès au bucket S3.
    • Clé d'accès secrète : clé secrète de l'utilisateur ayant accès au bucket S3.
  9. Cliquez sur Suivant.

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

Configurer des flux depuis le Hub de contenu

Indiquez les valeurs des champs suivants :

  • Région : région dans laquelle se trouve le bucket Amazon S3.

    • URI S3 : URI du bucket (au format s3://your-log-bucket-name/). Remplacez les éléments suivants :
      • your-log-bucket-name : nom du bucket.
    • L'URI est : sélectionnez Répertoire ou Répertoire incluant des sous-répertoires.
    • Options de suppression de la source : sélectionnez l'option de suppression de votre choix.
    • ID de clé d'accès : clé d'accès utilisateur ayant accès au bucket S3.
    • Clé d'accès secrète : clé secrète de l'utilisateur ayant accès au bucket S3.

Options avancées

  • Nom du flux : valeur préremplie qui identifie le flux.
  • Type de source : méthode utilisée pour collecter les journaux dans Google SecOps.
  • Espace de noms de l'élément : espace de noms associé au flux.
  • Libellés d'ingestion : libellés appliqués à tous les événements de ce flux.

Table de mappage UDM

Champ du journal Mappage UDM Logique
agent.id principal.asset.attribute.labels.value La valeur est extraite du champ agent.id du journal brut et mappée à un libellé avec la clé agent_id dans le tableau principal.asset.attribute.labels de l'UDM.
agent.version principal.asset.attribute.labels.value La valeur est extraite du champ agent.version du journal brut et mappée à un libellé avec la clé agent_version dans le tableau principal.asset.attribute.labels de l'UDM.
ecs.version principal.asset.attribute.labels.value La valeur est extraite du champ ecs.version du journal brut et mappée à un libellé avec la clé ecs_version dans le tableau principal.asset.attribute.labels de l'UDM.
event_data.reason metadata.description La valeur est extraite du champ event_data.reason du journal brut et mappée au champ description de l'objet metadata dans l'UDM.
event_datas.ActionId metadata.product_log_id La valeur est extraite du champ event_datas.ActionId du journal brut et mappée au champ product_log_id de l'objet metadata dans l'UDM.
file.path principal.file.full_path La valeur est extraite du champ file.path du journal brut et mappée au champ full_path de l'objet principal.file dans l'UDM.
headers.content_length additional.fields.value.string_value La valeur est extraite du champ headers.content_length du journal brut et mappée à un libellé avec la clé content_length dans le tableau additional.fields de l'UDM.
headers.content_type additional.fields.value.string_value La valeur est extraite du champ headers.content_type du journal brut et mappée à un libellé avec la clé content_type dans le tableau additional.fields de l'UDM.
headers.http_host additional.fields.value.string_value La valeur est extraite du champ headers.http_host du journal brut et mappée à un libellé avec la clé http_host dans le tableau additional.fields de l'UDM.
headers.http_version network.application_protocol_version La valeur est extraite du champ headers.http_version du journal brut et mappée au champ application_protocol_version de l'objet network dans l'UDM.
headers.request_method network.http.method La valeur est extraite du champ headers.request_method du journal brut et mappée au champ method de l'objet network.http dans l'UDM.
host.hostname principal.hostname La valeur est extraite du champ host.hostname du journal brut et mappée au champ hostname de l'objet principal dans l'UDM.
host.hostname principal.asset.hostname La valeur est extraite du champ host.hostname du journal brut et mappée au champ hostname de l'objet principal.asset dans l'UDM.
host.ip principal.asset.ip La valeur est extraite du champ host.ip du journal brut et ajoutée au tableau ip dans l'objet principal.asset de l'UDM.
host.ip principal.ip La valeur est extraite du champ host.ip du journal brut et ajoutée au tableau ip dans l'objet principal de l'UDM.
host.mac principal.mac La valeur est extraite du champ host.mac du journal brut et ajoutée au tableau mac dans l'objet principal de l'UDM.
host.os.platform principal.platform La valeur est définie sur MAC si le champ host.os.platform du journal brut est égal à macOS.
host.os.version principal.platform_version La valeur est extraite du champ host.os.version du journal brut et mappée au champ platform_version de l'objet principal dans l'UDM.
labels.related_item_id metadata.product_log_id La valeur est extraite du champ labels.related_item_id du journal brut et mappée au champ product_log_id de l'objet metadata dans l'UDM.
process.command_line principal.process.command_line La valeur est extraite du champ process.command_line du journal brut et mappée au champ command_line de l'objet principal.process dans l'UDM.
process.name additional.fields.value.string_value La valeur est extraite du champ process.name du journal brut et mappée à un libellé avec la clé process_name dans le tableau additional.fields de l'UDM.
process.parent.name additional.fields.value.string_value La valeur est extraite du champ process.parent.name du journal brut et mappée à un libellé avec la clé process_parent_name dans le tableau additional.fields de l'UDM.
process.parent.pid principal.process.parent_process.pid La valeur est extraite du champ process.parent.pid du journal brut, convertie en chaîne et mappée au champ pid de l'objet principal.process.parent_process dans l'UDM.
process.pid principal.process.pid La valeur est extraite du champ process.pid du journal brut, convertie en chaîne et mappée au champ pid de l'objet principal.process dans l'UDM.
user.id principal.user.userid La valeur est extraite du champ user.id du journal brut et mappée au champ userid de l'objet principal.user dans l'UDM.
nom.utilisateur principal.user.user_display_name La valeur est extraite du champ user.name du journal brut et mappée au champ user_display_name de l'objet principal.user dans l'UDM.
N/A metadata.event_timestamp Le code temporel de l'événement est défini sur celui de l'entrée de journal.
N/A metadata.event_type Le type d'événement est défini sur GENERIC_EVENT si aucun principal n'est trouvé, sinon il est défini sur STATUS_UPDATE.
N/A network.application_protocol Le protocole d'application est défini sur HTTP si le champ headers.http_version du journal brut contient HTTP.

Vous avez encore besoin d'aide ? Obtenez des réponses de membres de la communauté et de professionnels Google SecOps.