Coletar registros do BeyondTrust Endpoint Privilege Management
Este documento explica como ingerir registros do BeyondTrust Endpoint Privilege Management (EPM) no Google Security Operations usando o AWS S3. O analisador se concentra em transformar dados de registro JSON brutos do BeyondTrust Endpoint em um formato estruturado de acordo com o Modelo de Dados Unificado (UDM). Primeiro, ele inicializa os valores padrão para vários campos e, em seguida, analisa o payload JSON, mapeando campos específicos do log bruto para os campos correspondentes da UDM no objeto event.idm.read_only_udm
.
Antes de começar
Verifique se você tem os pré-requisitos a seguir:
- Instância do Google SecOps
- Acesso privilegiado à AWS
- Acesso privilegiado ao BeyondTrust Endpoint Privilege Management
Configurar o IAM da AWS para a ingestão do Google SecOps
- Crie um usuário seguindo este guia: Como criar um usuário do IAM.
- Selecione o usuário criado.
- Selecione a guia Credenciais de segurança.
- Clique em Criar chave de acesso na seção Chaves de acesso.
- Selecione Serviço de terceiros como Caso de uso.
- Clique em Próxima.
- Opcional: adicione uma tag de descrição.
- Clique em Criar chave de acesso.
- Clique em Fazer o download do arquivo CSV para salvar a chave de acesso e a chave de acesso secreta para referência futura.
- Clique em Concluído.
- Selecione a guia Permissões.
- Clique em Adicionar permissões na seção Políticas de permissões.
- Selecione Adicionar permissões.
- Selecione Anexar políticas diretamente.
- Pesquise e selecione a política AmazonS3FullAccess.
- Clique em Próxima.
- Clique em Adicionar permissões
Configurar o BeyondTrust EPM para acesso à API
- Faça login no console da Web do BeyondTrust Privilege Management como administrador.
- Acesse Configuração do sistema > API REST > Tokens.
- Clique em Adicionar token.
- Informe os seguintes detalhes de configuração:
- Nome: insira
Google SecOps Collector
. - Escopos: selecione Audit:Read e outros escopos conforme necessário.
- Nome: insira
- Salve e copie o valor do token (esse será seu BPT_API_TOKEN).
- Copie o URL de base da API. Normalmente, ele é
https://<your-epm-server>/api/v3
ou/api/v2
, dependendo da sua versão. Use esse URL como BPT_API_URL.
Criar um bucket do AWS S3
- Faça login no Console de Gerenciamento da AWS.
- Acesse Console da AWS > Serviços > S3 > Criar bucket.
- Informe os seguintes detalhes de configuração:
- Nome do bucket:
my-beyondtrust-logs
. - Região: [sua escolha] > Criar.
- Nome do bucket:
Criar um papel do IAM para o EC2
- Faça login no Console de Gerenciamento da AWS.
- Acesse Console da AWS > Serviços > IAM > Funções > Criar função.
- Informe os seguintes detalhes de configuração:
- Entidade confiável: Serviço da AWS > EC2 > Próxima.
- Anexar permissão: AmazonS3FullAccess (ou uma política com escopo para seu bucket) > Próxima.
- Nome da função:
EC2-S3-BPT-Writer
> Criar função.
Opcional: inicie e configure a VM do coletor do EC2
- Faça login no Console de Gerenciamento da AWS.
- Acesse Serviços.
- Na barra de pesquisa, digite EC2 e selecione essa opção.
- No painel do EC2, clique em Instâncias.
- Clique em Iniciar instâncias.
- Informe os seguintes detalhes de configuração:
- Nome: insira
BPT-Log-Collector
. - AMI: selecione Ubuntu Server 22.04 LTS.
- Tipo de instância: t3.micro (ou maior) e clique em Próxima.
- Rede: verifique se a configuração de rede está definida como sua VPC padrão.
- Função do IAM: selecione a função do IAM EC2-S3-BPT-Writer no menu.
- Atribuir IP público automaticamente: Ativar (ou verifique se é possível acessar usando VPN) > Próxima.
- Adicionar armazenamento: deixe a configuração de armazenamento padrão (8 GiB) e clique em Próxima.
- Selecione Criar um novo grupo de segurança.
- Regra de entrada: clique em Adicionar regra.
- Tipo: selecione SSH.
- Porta: 22.
- Origem: seu IP
- Clique em Revisar e iniciar.
- Selecione ou crie um par de chaves.
- Clique em Fazer o download do par de chaves.
- Salve o arquivo PEM baixado. Você vai precisar desse arquivo para se conectar à instância usando SSH.
- Nome: insira
Conecte-se à sua máquina virtual (VM) usando SSH:
chmod 400 ~/Downloads/your-key.pem ssh -i ~/Downloads/your-key.pem ubuntu@<EC2_PUBLIC_IP>
Instalar os pré-requisitos do coletor
Execute este 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
Crie um diretório e um arquivo de estado:
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
Inicialize-o (por exemplo, para 1 hora atrás):
echo "$(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ)" > /var/lib/bpt-collector/last_run.txt
Implantar o script do coletor da Armis
Crie uma pasta para o projeto:
mkdir ~/bpt-collector && cd ~/bpt-collector
Exporte as variáveis de ambiente necessárias (por exemplo, em
~/.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"
Crie
collector_bpt.py
e insira o seguinte código:#!/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()
Torne-o executável:
chmod +x collector_bpt.py
Programar diariamente com o Cron
Execute este comando:
crontab -e
Adicione o job diário à meia-noite UTC:
0 0 * * * cd ~/bpt-collector && source ~/bpt-venv/bin/activate && ./collector_bpt.py >> ~/bpt-collector/bpt.log 2>&1
Configurar feeds
Há dois pontos de entrada diferentes para configurar feeds na plataforma do Google SecOps:
- Configurações do SIEM > Feeds
- Central de conteúdo > Pacotes de conteúdo
Configure feeds em "Configurações do SIEM" > "Feeds".
Para configurar um feed, siga estas etapas:
- Acesse Configurações do SIEM > Feeds.
- Clique em Adicionar novo feed.
- Na próxima página, clique em Configurar um único feed.
- No campo Nome do feed, insira um nome para o feed (por exemplo, Registros do BeyondTrust EPM).
- Selecione Amazon S3 como o Tipo de origem.
- Selecione Beyondtrust Endpoint Privilege Management como o Tipo de registro.
- Clique em Próxima.
Especifique valores para os seguintes parâmetros de entrada:
- Região: a região em que o bucket do Amazon S3 está localizado.
- URI do S3: o URI do bucket. O formato precisa ser
s3://your-log-bucket-name/
. Substitua o seguinte:your-log-bucket-name
: o nome do bucket
- O URI é um: selecione Diretório ou Diretório que inclui subdiretórios.
- Opções de exclusão de fontes: selecione a opção de exclusão de acordo com sua preferência.
- ID da chave de acesso: a chave de acesso do usuário com acesso ao bucket do S3.
- Chave de acesso secreta: a chave secreta do usuário com acesso ao bucket do S3.
Clique em Próxima.
Revise a nova configuração do feed na tela Finalizar e clique em Enviar.
Configurar feeds na Central de conteúdo
Especifique valores para os seguintes campos:
Região: a região em que o bucket do Amazon S3 está localizado.
- URI do S3: o URI do bucket. O formato precisa ser
s3://your-log-bucket-name/
. Substitua o seguinte:your-log-bucket-name
: o nome do bucket
- O URI é um: selecione Diretório ou Diretório que inclui subdiretórios.
- Opções de exclusão de fontes: selecione a opção de exclusão de acordo com sua preferência.
- ID da chave de acesso: a chave de acesso do usuário com acesso ao bucket do S3.
- Chave de acesso secreta: a chave secreta do usuário com acesso ao bucket do S3.
- URI do S3: o URI do bucket. O formato precisa ser
Opções avançadas
- Nome do feed: um valor pré-preenchido que identifica o feed.
- Tipo de origem: método usado para coletar registros no Google SecOps.
- Namespace do recurso: namespace associado ao feed.
- Rótulos de ingestão: rótulos aplicados a todos os eventos deste feed.
Tabela de mapeamento da UDM
Campo de registro | Mapeamento da UDM | Lógica |
---|---|---|
agent.id | principal.asset.attribute.labels.value | O valor é extraído do campo agent.id no registro bruto e mapeado para um rótulo com a chave agent_id na matriz principal.asset.attribute.labels na UDM. |
agent.version | principal.asset.attribute.labels.value | O valor é extraído do campo agent.version no registro bruto e mapeado para um rótulo com a chave agent_version na matriz principal.asset.attribute.labels na UDM. |
ecs.version | principal.asset.attribute.labels.value | O valor é extraído do campo ecs.version no registro bruto e mapeado para um rótulo com a chave ecs_version na matriz principal.asset.attribute.labels na UDM. |
event_data.reason | metadata.description | O valor é extraído do campo event_data.reason no registro bruto e mapeado para o campo description no objeto metadata na UDM. |
event_datas.ActionId | metadata.product_log_id | O valor é extraído do campo event_datas.ActionId no registro bruto e mapeado para o campo product_log_id no objeto metadata na UDM. |
file.path | principal.file.full_path | O valor é extraído do campo file.path no registro bruto e mapeado para o campo full_path no objeto principal.file na UDM. |
headers.content_length | additional.fields.value.string_value | O valor é extraído do campo headers.content_length no registro bruto e mapeado para um rótulo com a chave content_length na matriz additional.fields na UDM. |
headers.content_type | additional.fields.value.string_value | O valor é extraído do campo headers.content_type no registro bruto e mapeado para um rótulo com a chave content_type na matriz additional.fields na UDM. |
headers.http_host | additional.fields.value.string_value | O valor é extraído do campo headers.http_host no registro bruto e mapeado para um rótulo com a chave http_host na matriz additional.fields na UDM. |
headers.http_version | network.application_protocol_version | O valor é extraído do campo headers.http_version no registro bruto e mapeado para o campo application_protocol_version no objeto network na UDM. |
headers.request_method | network.http.method | O valor é extraído do campo headers.request_method no registro bruto e mapeado para o campo method no objeto network.http na UDM. |
host.hostname | principal.hostname | O valor é extraído do campo host.hostname no registro bruto e mapeado para o campo hostname no objeto principal na UDM. |
host.hostname | principal.asset.hostname | O valor é extraído do campo host.hostname no registro bruto e mapeado para o campo hostname no objeto principal.asset na UDM. |
host.ip | principal.asset.ip | O valor é extraído do campo host.ip no registro bruto e adicionado à matriz ip no objeto principal.asset na UDM. |
host.ip | principal.ip | O valor é extraído do campo host.ip no registro bruto e adicionado à matriz ip no objeto principal na UDM. |
host.mac | principal.mac | O valor é extraído do campo host.mac no registro bruto e adicionado à matriz mac no objeto principal na UDM. |
host.os.platform | principal.platform | O valor é definido como MAC se o campo host.os.platform no registro bruto for igual a macOS . |
host.os.version | principal.platform_version | O valor é extraído do campo host.os.version no registro bruto e mapeado para o campo platform_version no objeto principal na UDM. |
labels.related_item_id | metadata.product_log_id | O valor é extraído do campo labels.related_item_id no registro bruto e mapeado para o campo product_log_id no objeto metadata na UDM. |
process.command_line | principal.process.command_line | O valor é extraído do campo process.command_line no registro bruto e mapeado para o campo command_line no objeto principal.process na UDM. |
process.name | additional.fields.value.string_value | O valor é extraído do campo process.name no registro bruto e mapeado para um rótulo com a chave process_name na matriz additional.fields na UDM. |
process.parent.name | additional.fields.value.string_value | O valor é extraído do campo process.parent.name no registro bruto e mapeado para um rótulo com a chave process_parent_name na matriz additional.fields na UDM. |
process.parent.pid | principal.process.parent_process.pid | O valor é extraído do campo process.parent.pid no registro bruto, convertido em string e mapeado para o campo pid no objeto principal.process.parent_process na UDM. |
process.pid | principal.process.pid | O valor é extraído do campo process.pid no registro bruto, convertido em string e mapeado para o campo pid no objeto principal.process na UDM. |
user.id | principal.user.userid | O valor é extraído do campo user.id no registro bruto e mapeado para o campo userid no objeto principal.user na UDM. |
user.name | principal.user.user_display_name | O valor é extraído do campo user.name no registro bruto e mapeado para o campo user_display_name no objeto principal.user na UDM. |
N/A | metadata.event_timestamp | O carimbo de data/hora do evento é definido como o carimbo de data/hora da entrada de registro. |
N/A | metadata.event_type | O tipo de evento é definido como GENERIC_EVENT se nenhum principal for encontrado. Caso contrário, ele será definido como STATUS_UPDATE . |
N/A | network.application_protocol | O protocolo de aplicativo é definido como HTTP se o campo headers.http_version no registro bruto contiver HTTP . |
Precisa de mais ajuda? Receba respostas de membros da comunidade e profissionais do Google SecOps.