Recolha registos da gestão de privilégios de pontos finais da BeyondTrust

Compatível com:

Este documento explica como carregar registos do BeyondTrust Endpoint Privilege Management (EPM) para o Google Security Operations através do AWS S3. O analisador concentra-se na transformação de dados de registo JSON não processados do BeyondTrust Endpoint num formato estruturado em conformidade com o modelo de dados unificado (UDM). Primeiro, inicializa os valores predefinidos para vários campos e, em seguida, analisa a carga útil JSON, mapeando posteriormente campos específicos do registo não processado para os campos UDM correspondentes no objeto event.idm.read_only_udm.

Antes de começar

Certifique-se de que tem os seguintes pré-requisitos:

  • Instância do Google SecOps
  • Acesso privilegiado ao AWS
  • Acesso privilegiado à gestão de privilégios de pontos finais da BeyondTrust

Configure o AWS IAM para a carregamento do Google SecOps

  1. Crie um utilizador seguindo este guia do utilizador: criar um utilizador do IAM.
  2. Selecione o utilizador criado.
  3. Selecione o separador Credenciais de segurança.
  4. Clique em Criar chave de acesso na secção Chaves de acesso.
  5. Selecione Serviço de terceiros como Exemplo de utilização.
  6. Clicar em Seguinte.
  7. Opcional: adicione uma etiqueta de descrição.
  8. Clique em Criar chave de acesso.
  9. Clique em Transferir ficheiro CSV para guardar a chave de acesso e a chave de acesso secreta para referência futura.
  10. Clique em Concluído.
  11. Selecione o separador Autorizações.
  12. Clique em Adicionar autorizações na secção Políticas de autorizações.
  13. Selecione Adicionar autorizações.
  14. Selecione Anexar políticas diretamente.
  15. Pesquise e selecione a política AmazonS3FullAccess.
  16. Clicar em Seguinte.
  17. Clique em Adicionar autorizações.

Configure o BeyondTrust EPM para acesso à API

  1. Inicie sessão na consola Web do BeyondTrust Privilege Management como administrador.
  2. Aceda a Configuração do sistema > API REST > Tokens.
  3. Clique em Adicionar token.
  4. Indique os seguintes detalhes de configuração:
    • Nome: introduza Google SecOps Collector.
    • Âmbitos: selecione Audit:Read e outros âmbitos, conforme necessário.
  5. Guarde e copie o valor do token (este será o seu BPT_API_TOKEN).
  6. Copie o URL base da API. Normalmente, é https://<your-epm-server>/api/v3 ou /api/v2, consoante a sua versão (vai usá-lo como BPT_API_URL).

Crie um contentor do AWS S3

  1. Inicie sessão na AWS Management Console.
  2. Aceda a AWS Console > Services > S3 > Create bucket.
  3. Indique os seguintes detalhes de configuração:
    • Nome do segmento: my-beyondtrust-logs.
    • Região: [a sua escolha] > Criar.

Crie uma função do IAM para o EC2

  1. Inicie sessão na AWS Management Console.
  2. Aceda a AWS Console > Services > IAM > Roles > Create role.
  3. Indique os seguintes detalhes de configuração:
    • Entidade fidedigna: serviço AWS > EC2 > Seguinte.
    • Anexe a autorização: AmazonS3FullAccess (ou uma política com âmbito para o seu contentor) > Seguinte.
    • Nome da função: EC2-S3-BPT-Writer > Criar função.

Opcional: inicie e configure a VM do coletor do EC2

  1. Inicie sessão na AWS Management Console.
  2. Aceda a Serviços.
  3. Na barra de pesquisa, escreva EC2 e selecione-o.
  4. No painel de controlo do EC2, clique em Instances.
  5. Clique em Iniciar instâncias.
  6. Indique os seguintes detalhes de configuração:
    • Nome: introduza BPT-Log-Collector
    • AMI: selecione Ubuntu Server 22.04 LTS
    • Tipo de instância: t3.micro (ou superior) e, de seguida, clique em Seguinte.
    • Rede: certifique-se de que a definição de rede está definida para a sua VPC predefinida.
    • Função do IAM: selecione a função do IAM EC2-S3-BPT-Writer no menu.
    • Atribuir automaticamente IP público: Ativar (ou certifique-se de que consegue aceder ao mesmo através da VPN) > Seguinte.
    • Adicionar armazenamento: deixe a configuração de armazenamento predefinida (8 GiB) e, de seguida, clique em Seguinte.
    • Selecione Criar um novo grupo de segurança.
    • Regra de entrada: clique em Adicionar regra.
    • Tipo: selecione SSH.
    • Porta: 22.
    • Origem: o seu IP
    • Clique em Rever e iniciar.
    • Selecione ou crie um par de chaves.
    • Clique em Transferir par de chaves.
    • Guarde o ficheiro PEM transferido. Precisa deste ficheiro para estabelecer ligação à sua instância através de SSH.
  7. Estabeleça ligação à sua máquina virtual (VM) através do SSH:

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

Instale os pré-requisitos do coletor

  1. Execute o seguinte 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
    
  2. Crie um diretório e um ficheiro 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
    
  3. Inicialize-o (por exemplo, para há 1 hora):

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

Implemente o script do coletor da Armis

  1. Crie uma pasta de projeto:

    mkdir ~/bpt-collector && cd ~/bpt-collector
    
  2. 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"
    
  3. Crie collector_bpt.py e introduza 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()
    
  4. Torne-o executável:

    chmod +x collector_bpt.py
    

Agende diariamente com o Cron

  1. Execute o seguinte comando:

    crontab -e
    
  2. Adicione a tarefa diária à meia-noite UTC:

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

Configure feeds

Para configurar um feed, siga estes passos:

  1. Aceda a Definições do SIEM > Feeds.
  2. Clique em Adicionar novo feed.
  3. Na página seguinte, clique em Configurar um único feed.
  4. No campo Nome do feed, introduza um nome para o feed (por exemplo, Registos do BeyondTrust EPM).
  5. Selecione Amazon S3 V2 como o Tipo de origem.
  6. Selecione Beyondtrust Endpoint Privilege Management como o Tipo de registo.
  7. Clicar em Seguinte.
  8. Especifique valores para os seguintes parâmetros de entrada:

    • URI do S3: o URI do contentor (o formato deve ser: s3://your-log-bucket-name/). Substitua o seguinte:
      • your-log-bucket-name: o nome do segmento.
    • Opções de eliminação da origem: selecione a opção de eliminação de acordo com a sua preferência.
  9. Clicar em Seguinte.

  10. Reveja a nova configuração do feed no ecrã Finalizar e, de seguida, clique em Enviar.

Tabela de mapeamento do UDM

Campo de registo Mapeamento do UDM Lógica
agent.id principal.asset.attribute.labels.value O valor é retirado do campo agent.id no registo não processado e mapeado para uma etiqueta com a chave agent_id na matriz principal.asset.attribute.labels no UDM.
agent.version principal.asset.attribute.labels.value O valor é retirado do campo agent.version no registo não processado e mapeado para uma etiqueta com a chave agent_version na matriz principal.asset.attribute.labels no UDM.
ecs.version principal.asset.attribute.labels.value O valor é retirado do campo ecs.version no registo não processado e mapeado para uma etiqueta com a chave ecs_version na matriz principal.asset.attribute.labels no UDM.
event_data.reason metadata.description O valor é retirado do campo event_data.reason no registo não processado e mapeado para o campo description no objeto metadata no UDM.
event_datas.ActionId metadata.product_log_id O valor é retirado do campo event_datas.ActionId no registo não processado e mapeado para o campo product_log_id no objeto metadata no UDM.
file.path principal.file.full_path O valor é retirado do campo file.path no registo não processado e mapeado para o campo full_path no objeto principal.file no UDM.
headers.content_length additional.fields.value.string_value O valor é retirado do campo headers.content_length no registo não processado e mapeado para uma etiqueta com a chave content_length na matriz additional.fields no UDM.
headers.content_type additional.fields.value.string_value O valor é retirado do campo headers.content_type no registo não processado e mapeado para uma etiqueta com a chave content_type na matriz additional.fields no UDM.
headers.http_host additional.fields.value.string_value O valor é retirado do campo headers.http_host no registo não processado e mapeado para uma etiqueta com a chave http_host na matriz additional.fields no UDM.
headers.http_version network.application_protocol_version O valor é retirado do campo headers.http_version no registo não processado e mapeado para o campo application_protocol_version no objeto network no UDM.
headers.request_method network.http.method O valor é retirado do campo headers.request_method no registo não processado e mapeado para o campo method no objeto network.http no UDM.
host.hostname principal.hostname O valor é retirado do campo host.hostname no registo não processado e mapeado para o campo hostname no objeto principal no UDM.
host.hostname principal.asset.hostname O valor é retirado do campo host.hostname no registo não processado e mapeado para o campo hostname no objeto principal.asset no UDM.
host.ip principal.asset.ip O valor é retirado do campo host.ip no registo não processado e adicionado à matriz ip no objeto principal.asset no UDM.
host.ip principal.ip O valor é retirado do campo host.ip no registo não processado e adicionado à matriz ip no objeto principal no UDM.
host.mac principal.mac O valor é retirado do campo host.mac no registo não processado e adicionado à matriz mac no objeto principal no UDM.
host.os.platform principal.platform O valor é definido como MAC se o campo host.os.platform no registo não processado for igual a macOS.
host.os.version principal.platform_version O valor é retirado do campo host.os.version no registo não processado e mapeado para o campo platform_version no objeto principal no UDM.
labels.related_item_id metadata.product_log_id O valor é retirado do campo labels.related_item_id no registo não processado e mapeado para o campo product_log_id no objeto metadata no UDM.
process.command_line principal.process.command_line O valor é retirado do campo process.command_line no registo não processado e mapeado para o campo command_line no objeto principal.process no UDM.
process.name additional.fields.value.string_value O valor é retirado do campo process.name no registo não processado e mapeado para uma etiqueta com a chave process_name na matriz additional.fields no UDM.
process.parent.name additional.fields.value.string_value O valor é retirado do campo process.parent.name no registo não processado e mapeado para uma etiqueta com a chave process_parent_name na matriz additional.fields no UDM.
process.parent.pid principal.process.parent_process.pid O valor é retirado do campo process.parent.pid no registo não processado, convertido em string e mapeado para o campo pid no objeto principal.process.parent_process no UDM.
process.pid principal.process.pid O valor é retirado do campo process.pid no registo não processado, convertido em string e mapeado para o campo pid no objeto principal.process no UDM.
user.id principal.user.userid O valor é retirado do campo user.id no registo não processado e mapeado para o campo userid no objeto principal.user no UDM.
user.name principal.user.user_display_name O valor é retirado do campo user.name no registo não processado e mapeado para o campo user_display_name no objeto principal.user no UDM.
N/A metadata.event_timestamp A data/hora do evento está definida para a data/hora da entrada do registo.
N/A metadata.event_type O tipo de evento é definido como GENERIC_EVENT se não for encontrado nenhum principal. Caso contrário, é definido como STATUS_UPDATE.
N/A network.application_protocol O protocolo de aplicação é definido como HTTP se o campo headers.http_version no registo não processado contiver HTTP.

Precisa de mais ajuda? Receba respostas de membros da comunidade e profissionais da Google SecOps.