Raccogliere i log di BeyondTrust Endpoint Privilege Management
Questo documento spiega come importare i log di BeyondTrust Endpoint Privilege Management
(EPM) in Google Security Operations utilizzando AWS S3. Il parser si concentra sulla trasformazione dei dati di log JSON non elaborati da BeyondTrust Endpoint in un formato strutturato conforme a Unified Data Model (UDM). Innanzitutto, inizializza i valori predefiniti per vari campi, quindi analizza il payload JSON, mappando successivamente campi specifici dal log non elaborato nei campi UDM corrispondenti all'interno dell'oggetto event.idm.read_only_udm
.
Prima di iniziare
Assicurati di soddisfare i seguenti prerequisiti:
- Istanza Google SecOps
- Accesso privilegiato ad AWS
- Accesso con privilegi a BeyondTrust Endpoint Privilege Management
Configurare AWS IAM per l'importazione di Google SecOps
- Crea un utente seguendo questa guida utente: Creazione di un utente IAM.
- Seleziona l'utente creato.
- Seleziona la scheda Credenziali di sicurezza.
- Fai clic su Crea chiave di accesso nella sezione Chiavi di accesso.
- Seleziona Servizio di terze parti come Caso d'uso.
- Fai clic su Avanti.
- (Facoltativo) Aggiungi un tag di descrizione.
- Fai clic su Crea chiave di accesso.
- Fai clic su Scarica file CSV per salvare la chiave di accesso e la chiave di accesso segreta per riferimento futuro.
- Fai clic su Fine.
- Seleziona la scheda Autorizzazioni.
- Fai clic su Aggiungi autorizzazioni nella sezione Norme relative alle autorizzazioni.
- Seleziona Aggiungi autorizzazioni.
- Seleziona Allega direttamente le norme.
- Cerca e seleziona il criterio AmazonS3FullAccess.
- Fai clic su Avanti.
- Fai clic su Aggiungi autorizzazioni.
Configurare BeyondTrust EPM per l'accesso API
- Accedi alla console web BeyondTrust Privilege Management come amministratore.
- Vai a System Configuration > API REST > Tokens.
- Fai clic su Aggiungi token.
- Fornisci i seguenti dettagli di configurazione:
- Nome: inserisci
Google SecOps Collector
. - Ambiti: seleziona Audit:Read e altri ambiti in base alle esigenze.
- Nome: inserisci
- Salva e copia il valore del token (che sarà il tuo BPT_API_TOKEN).
- Copia l'URL di base dell'API, che in genere è
https://<your-epm-server>/api/v3
o/api/v2
, a seconda della versione (lo utilizzerai come BPT_API_URL).
Crea un bucket AWS S3
- Accedi alla console di gestione AWS.
- Vai a AWS Console > Services > S3 > Create bucket.
- Fornisci i seguenti dettagli di configurazione:
- Nome bucket:
my-beyondtrust-logs
. - Regione: [la tua scelta] > Crea.
- Nome bucket:
Crea un ruolo IAM per EC2
- Accedi alla console di gestione AWS.
- Vai alla console AWS > Servizi > IAM > Ruoli > Crea ruolo.
- Fornisci i seguenti dettagli di configurazione:
- Entità attendibile: Servizio AWS > EC2 > Avanti.
- Allega autorizzazione: AmazonS3FullAccess (o un criterio con ambito limitato al tuo bucket) > Avanti.
- Nome ruolo:
EC2-S3-BPT-Writer
> Crea ruolo.
(Facoltativo) Avvia e configura la VM EC2 Collector
- Accedi alla console di gestione AWS.
- Vai a Servizi.
- Nella barra di ricerca, digita EC2 e seleziona la voce corrispondente.
- Nella dashboard EC2, fai clic su Istanze.
- Fai clic su Avvia istanze.
- Fornisci i seguenti dettagli di configurazione:
- Nome: inserisci
BPT-Log-Collector
- AMI: seleziona Ubuntu Server 22.04 LTS
- Tipo di istanza: t3.micro (o superiore), quindi fai clic su Avanti.
- Rete: assicurati che l'impostazione Rete sia impostata sul VPC predefinito.
- Ruolo IAM: seleziona il ruolo IAM EC2-S3-BPT-Writer dal menu.
- Assegna automaticamente IP pubblico: Attiva (o assicurati di poterlo raggiungere tramite VPN) > Avanti.
- Aggiungi spazio di archiviazione: lascia la configurazione di archiviazione predefinita (8 GiB) e fai clic su Avanti.
- Seleziona Crea un nuovo gruppo di sicurezza.
- Regola in entrata: fai clic su Aggiungi regola.
- Tipo: seleziona SSH.
- Porta: 22.
- Origine: il tuo IP
- Fai clic su Rivedi e avvia.
- Seleziona o crea una coppia di chiavi.
- Fai clic su Scarica coppia di chiavi.
- Salva il file PEM scaricato. Ti servirà questo file per connetterti all'istanza tramite SSH.
- Nome: inserisci
Connettiti alla tua macchina virtuale (VM) utilizzando SSH:
chmod 400 ~/Downloads/your-key.pem ssh -i ~/Downloads/your-key.pem ubuntu@<EC2_PUBLIC_IP>
Installa i prerequisiti del raccoglitore
Esegui questo comando:
# 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
Crea una directory e un file di stato:
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
Inizializzalo (ad esempio, a 1 ora fa):
echo "$(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ)" > /var/lib/bpt-collector/last_run.txt
Esegui il deployment dello script del raccoglitore Armis
Creare una cartella di progetto:
mkdir ~/bpt-collector && cd ~/bpt-collector
Esporta le variabili di ambiente richieste (ad esempio, in
~/.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"
Crea
collector_bpt.py
e inserisci il seguente codice:#!/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()
Rendi eseguibile il file:
chmod +x collector_bpt.py
Pianificare l'esecuzione giornaliera con Cron
Esegui questo comando:
crontab -e
Aggiungi il job giornaliero a mezzanotte UTC:
0 0 * * * cd ~/bpt-collector && source ~/bpt-venv/bin/activate && ./collector_bpt.py >> ~/bpt-collector/bpt.log 2>&1
Configurare i feed
Esistono due diversi punti di accesso per configurare i feed nella piattaforma Google SecOps:
- Impostazioni SIEM > Feed
- Hub dei contenuti > Pacchetti di contenuti
Configura i feed da Impostazioni SIEM > Feed
Per configurare un feed:
- Vai a Impostazioni SIEM > Feed.
- Fai clic su Aggiungi nuovo feed.
- Nella pagina successiva, fai clic su Configura un singolo feed.
- Nel campo Nome feed, inserisci un nome per il feed (ad esempio Log EPM di BeyondTrust).
- Seleziona Amazon S3 come Tipo di origine.
- Seleziona Beyondtrust Endpoint Privilege Management come Tipo di log.
- Fai clic su Avanti.
Specifica i valori per i seguenti parametri di input:
- Region (Regione): la regione in cui si trova il bucket Amazon S3.
- URI S3: l'URI del bucket (il formato deve essere
s3://your-log-bucket-name/
). Sostituisci quanto segue:your-log-bucket-name
: il nome del bucket.
- L'URI è una: seleziona Directory o Directory che include sottodirectory.
- Opzioni di eliminazione dell'origine: seleziona l'opzione di eliminazione in base alle tue preferenze.
- ID chiave di accesso: la chiave di accesso utente con accesso al bucket S3.
- Chiave di accesso segreta: la chiave segreta dell'utente con accesso al bucket S3.
Fai clic su Avanti.
Controlla la nuova configurazione del feed nella schermata Finalizza e poi fai clic su Invia.
Configurare i feed dall'hub dei contenuti
Specifica i valori per i seguenti campi:
Region (Regione): la regione in cui si trova il bucket Amazon S3.
- URI S3: l'URI del bucket (il formato deve essere
s3://your-log-bucket-name/
). Sostituisci quanto segue:your-log-bucket-name
: il nome del bucket.
- L'URI è una: seleziona Directory o Directory che include sottodirectory.
- Opzioni di eliminazione dell'origine: seleziona l'opzione di eliminazione in base alle tue preferenze.
- ID chiave di accesso: la chiave di accesso utente con accesso al bucket S3.
- Chiave di accesso segreta: la chiave segreta dell'utente con accesso al bucket S3.
- URI S3: l'URI del bucket (il formato deve essere
Opzioni avanzate
- Nome feed: un valore precompilato che identifica il feed.
- Tipo di origine: metodo utilizzato per raccogliere i log in Google SecOps.
- Spazio dei nomi dell'asset: lo spazio dei nomi associato al feed.
- Etichette di importazione: etichette applicate a tutti gli eventi di questo feed.
Tabella di mappatura UDM
Campo log | Mappatura UDM | Logic |
---|---|---|
agent.id | principal.asset.attribute.labels.value | Il valore viene estratto dal campo agent.id nel log non elaborato e mappato a un'etichetta con chiave agent_id all'interno dell'array principal.asset.attribute.labels in UDM. |
agent.version | principal.asset.attribute.labels.value | Il valore viene estratto dal campo agent.version nel log non elaborato e mappato a un'etichetta con chiave agent_version all'interno dell'array principal.asset.attribute.labels in UDM. |
ecs.version | principal.asset.attribute.labels.value | Il valore viene estratto dal campo ecs.version nel log non elaborato e mappato a un'etichetta con chiave ecs_version all'interno dell'array principal.asset.attribute.labels in UDM. |
event_data.reason | metadata.description | Il valore viene estratto dal campo event_data.reason nel log non elaborato e mappato al campo description all'interno dell'oggetto metadata nell'UDM. |
event_datas.ActionId | metadata.product_log_id | Il valore viene estratto dal campo event_datas.ActionId nel log non elaborato e mappato al campo product_log_id all'interno dell'oggetto metadata nell'UDM. |
file.path | principal.file.full_path | Il valore viene estratto dal campo file.path nel log non elaborato e mappato al campo full_path all'interno dell'oggetto principal.file nell'UDM. |
headers.content_length | additional.fields.value.string_value | Il valore viene estratto dal campo headers.content_length nel log non elaborato e mappato a un'etichetta con chiave content_length all'interno dell'array additional.fields in UDM. |
headers.content_type | additional.fields.value.string_value | Il valore viene estratto dal campo headers.content_type nel log non elaborato e mappato a un'etichetta con chiave content_type all'interno dell'array additional.fields in UDM. |
headers.http_host | additional.fields.value.string_value | Il valore viene estratto dal campo headers.http_host nel log non elaborato e mappato a un'etichetta con chiave http_host all'interno dell'array additional.fields in UDM. |
headers.http_version | network.application_protocol_version | Il valore viene estratto dal campo headers.http_version nel log non elaborato e mappato al campo application_protocol_version all'interno dell'oggetto network nell'UDM. |
headers.request_method | network.http.method | Il valore viene estratto dal campo headers.request_method nel log non elaborato e mappato al campo method all'interno dell'oggetto network.http nell'UDM. |
host.hostname | principal.hostname | Il valore viene estratto dal campo host.hostname nel log non elaborato e mappato al campo hostname all'interno dell'oggetto principal nell'UDM. |
host.hostname | principal.asset.hostname | Il valore viene estratto dal campo host.hostname nel log non elaborato e mappato al campo hostname all'interno dell'oggetto principal.asset nell'UDM. |
host.ip | principal.asset.ip | Il valore viene estratto dal campo host.ip nel log non elaborato e aggiunto all'array ip all'interno dell'oggetto principal.asset nell'UDM. |
host.ip | principal.ip | Il valore viene estratto dal campo host.ip nel log non elaborato e aggiunto all'array ip all'interno dell'oggetto principal nell'UDM. |
host.mac | principal.mac | Il valore viene estratto dal campo host.mac nel log non elaborato e aggiunto all'array mac all'interno dell'oggetto principal nell'UDM. |
host.os.platform | principal.platform | Il valore è impostato su MAC se il campo host.os.platform nel log non elaborato è uguale a macOS . |
host.os.version | principal.platform_version | Il valore viene estratto dal campo host.os.version nel log non elaborato e mappato al campo platform_version all'interno dell'oggetto principal nell'UDM. |
labels.related_item_id | metadata.product_log_id | Il valore viene estratto dal campo labels.related_item_id nel log non elaborato e mappato al campo product_log_id all'interno dell'oggetto metadata nell'UDM. |
process.command_line | principal.process.command_line | Il valore viene estratto dal campo process.command_line nel log non elaborato e mappato al campo command_line all'interno dell'oggetto principal.process nell'UDM. |
process.name | additional.fields.value.string_value | Il valore viene estratto dal campo process.name nel log non elaborato e mappato a un'etichetta con chiave process_name all'interno dell'array additional.fields in UDM. |
process.parent.name | additional.fields.value.string_value | Il valore viene estratto dal campo process.parent.name nel log non elaborato e mappato a un'etichetta con chiave process_parent_name all'interno dell'array additional.fields in UDM. |
process.parent.pid | principal.process.parent_process.pid | Il valore viene estratto dal campo process.parent.pid nel log non elaborato, convertito in stringa e mappato al campo pid all'interno dell'oggetto principal.process.parent_process in UDM. |
process.pid | principal.process.pid | Il valore viene estratto dal campo process.pid nel log non elaborato, convertito in stringa e mappato al campo pid all'interno dell'oggetto principal.process in UDM. |
user.id | principal.user.userid | Il valore viene estratto dal campo user.id nel log non elaborato e mappato al campo userid all'interno dell'oggetto principal.user nell'UDM. |
nome.utente | principal.user.user_display_name | Il valore viene estratto dal campo user.name nel log non elaborato e mappato al campo user_display_name all'interno dell'oggetto principal.user nell'UDM. |
N/D | metadata.event_timestamp | Il timestamp dell'evento è impostato sul timestamp della voce di log. |
N/D | metadata.event_type | Se non viene trovato alcun principal, il tipo di evento è impostato su GENERIC_EVENT , altrimenti è impostato su STATUS_UPDATE . |
N/D | network.application_protocol | Il protocollo dell'applicazione è impostato su HTTP se il campo headers.http_version nel log non elaborato contiene HTTP . |
Hai bisogno di ulteriore assistenza? Ricevi risposte dai membri della community e dai professionisti di Google SecOps.