Recoger registros de gestión de privilegios de endpoints de BeyondTrust

Disponible en:

En este documento se explica cómo ingerir registros de BeyondTrust Endpoint Privilege Management (EPM) en Google Security Operations mediante AWS S3. El analizador se centra en transformar los datos de registro JSON sin procesar de BeyondTrust Endpoint en un formato estructurado que se ajuste al modelo de datos unificado (UDM). Primero, inicializa los valores predeterminados de varios campos y, a continuación, analiza la carga útil JSON. Después, asigna campos específicos del registro sin procesar a los campos de UDM correspondientes del objeto event.idm.read_only_udm.

Antes de empezar

Asegúrate de que cumples los siguientes requisitos previos:

  • Instancia de Google SecOps
  • Acceso privilegiado a AWS
  • Acceso con privilegios a BeyondTrust Endpoint Privilege Management

Configurar la gestión de identidades y accesos de AWS para la ingestión de Google SecOps

  1. Crea un usuario siguiendo esta guía: Crear un usuario de gestión de identidades y accesos.
  2. Selecciona el usuario creado.
  3. Selecciona la pestaña Credenciales de seguridad.
  4. En la sección Claves de acceso, haz clic en Crear clave de acceso.
  5. Selecciona Servicio de terceros como Caso práctico.
  6. Haz clic en Siguiente.
  7. Opcional: añade una etiqueta de descripción.
  8. Haz clic en Crear clave de acceso.
  9. Haz clic en Descargar archivo CSV para guardar la clave de acceso y la clave de acceso secreta para futuras consultas.
  10. Haz clic en Listo.
  11. Selecciona la pestaña Permisos.
  12. En la sección Políticas de permisos, haz clic en Añadir permisos.
  13. Selecciona Añadir permisos.
  14. Seleccione Adjuntar políticas directamente.
  15. Busca y selecciona la política AmazonS3FullAccess.
  16. Haz clic en Siguiente.
  17. Haz clic en Añadir permisos.

Configurar BeyondTrust EPM para el acceso a la API

  1. Inicia sesión en la consola web BeyondTrust Privilege Management como administrador.
  2. Ve a Configuración del sistema > API REST > Tokens.
  3. Haz clic en Add Token (Añadir token).
  4. Proporcione los siguientes detalles de configuración:
    • Name (Nombre): escribe Google SecOps Collector.
    • Ámbitos: selecciona Audit:Read y otros ámbitos según sea necesario.
  5. Guarda y copia el valor del token (será tu BPT_API_TOKEN).
  6. Copia la URL base de la API. Normalmente es https://<your-epm-server>/api/v3 o /api/v2, según tu versión (la usarás como BPT_API_URL).

Crear un segmento de AWS S3

  1. Inicia sesión en la consola de administración de AWS.
  2. Ve a Consola de AWS > Servicios > S3 > Crear un bucket.
  3. Proporcione los siguientes detalles de configuración:
    • Nombre del segmento: my-beyondtrust-logs.
    • Región: [tu elección] > Crear.

Crear un rol de gestión de identidades y accesos para EC2

  1. Inicia sesión en la consola de administración de AWS.
  2. Ve a AWS Console > Services > IAM > Roles > Create role (Consola de AWS > Servicios > IAM > Roles > Crear rol).
  3. Proporcione los siguientes detalles de configuración:
    • Entidad de confianza: Servicio de AWS > EC2 > Siguiente.
    • Adjuntar permiso: AmazonS3FullAccess (o una política con ámbito para tu bucket) > Siguiente.
    • Nombre del rol: EC2-S3-BPT-Writer > Crear rol.

Opcional: Inicia y configura tu VM de EC2 Collector

  1. Inicia sesión en la consola de administración de AWS.
  2. Ve a Servicios.
  3. En la barra de búsqueda, escribe EC2 y selecciónalo.
  4. En el panel de control de EC2, haz clic en Instances (Instancias).
  5. Haz clic en Lanzar instancias.
  6. Proporcione los siguientes detalles de configuración:
    • Nombre: introduce BPT-Log-Collector.
    • AMI: selecciona Ubuntu Server 22.04 LTS.
    • Tipo de instancia: t3.micro (o un tipo más grande) y, a continuación, haz clic en Siguiente.
    • Red: comprueba que la opción Red esté configurada en tu VPC predeterminada.
    • Rol de gestión de identidades y accesos: selecciona el rol de gestión de identidades y accesos EC2-S3-BPT-Writer en el menú.
    • Asignar IP pública automáticamente: Habilitar (o asegúrate de que puedes acceder a ella mediante una VPN) > Siguiente.
    • Añadir almacenamiento: deje la configuración de almacenamiento predeterminada (8 GiB) y, a continuación, haga clic en Siguiente.
    • Selecciona Crear un grupo de seguridad.
    • Regla de entrada: haz clic en Añadir regla.
    • Tipo: selecciona SSH.
    • Puerto: 22.
    • Fuente: tu IP
    • Haga clic en Revisar y publicar.
    • Seleccione o cree un par de claves.
    • Haz clic en Descargar par de claves.
    • Guarda el archivo PEM descargado. Necesitarás este archivo para conectarte a tu instancia mediante SSH.
  7. Conéctate a tu máquina virtual (VM) mediante SSH:

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

Instalar los requisitos previos del recopilador

  1. Ejecuta el siguiente 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. Crea un directorio y un archivo 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. Inicialízalo (por ejemplo, hace 1 hora):

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

Implementar la secuencia de comandos del recopilador de Armis

  1. Crea una carpeta de proyecto:

    mkdir ~/bpt-collector && cd ~/bpt-collector
    
  2. Exporta las variables de entorno necesarias (por ejemplo, en ~/.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. Crea collector_bpt.py e introduce el siguiente 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. Haz que sea ejecutable:

    chmod +x collector_bpt.py
    

Programar diariamente con Cron

  1. Ejecuta el siguiente comando:

    crontab -e
    
  2. Añade la tarea diaria a medianoche UTC:

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

Configurar feeds

Para configurar un feed, sigue estos pasos:

  1. Ve a Configuración de SIEM > Feeds.
  2. Haz clic en Añadir feed.
  3. En la página siguiente, haga clic en Configurar un solo feed.
  4. En el campo Nombre del feed, introduzca un nombre para el feed (por ejemplo, Registros de EPM de BeyondTrust).
  5. Selecciona Amazon S3 V2 como Tipo de fuente.
  6. Seleccione Beyondtrust Endpoint Privilege Management como Tipo de registro.
  7. Haz clic en Siguiente.
  8. Especifique los valores de los siguientes parámetros de entrada:

    • URI de S3: el URI del contenedor (el formato debe ser s3://your-log-bucket-name/). Sustituye lo siguiente:
      • your-log-bucket-name: el nombre del segmento.
    • Opciones de eliminación de la fuente: selecciona la opción de eliminación que prefieras.
  9. Haz clic en Siguiente.

  10. Revise la configuración de la nueva fuente en la pantalla Finalizar y, a continuación, haga clic en Enviar.

Tabla de asignación de UDM

Campo de registro Asignación de UDM Lógica
agent.id principal.asset.attribute.labels.value El valor se toma del campo agent.id del registro sin procesar y se asigna a una etiqueta con la clave agent_id en la matriz principal.asset.attribute.labels de UDM.
agent.version principal.asset.attribute.labels.value El valor se toma del campo agent.version del registro sin procesar y se asigna a una etiqueta con la clave agent_version en la matriz principal.asset.attribute.labels de UDM.
ecs.version principal.asset.attribute.labels.value El valor se toma del campo ecs.version del registro sin procesar y se asigna a una etiqueta con la clave ecs_version en la matriz principal.asset.attribute.labels de UDM.
event_data.reason metadata.description El valor se toma del campo event_data.reason del registro sin procesar y se asigna al campo description del objeto metadata en el modelo de datos unificado.
event_datas.ActionId metadata.product_log_id El valor se toma del campo event_datas.ActionId del registro sin procesar y se asigna al campo product_log_id del objeto metadata en el modelo de datos unificado.
file.path principal.file.full_path El valor se toma del campo file.path del registro sin procesar y se asigna al campo full_path del objeto principal.file en el modelo de datos unificado.
headers.content_length additional.fields.value.string_value El valor se toma del campo headers.content_length del registro sin procesar y se asigna a una etiqueta con la clave content_length en la matriz additional.fields de UDM.
headers.content_type additional.fields.value.string_value El valor se toma del campo headers.content_type del registro sin procesar y se asigna a una etiqueta con la clave content_type en la matriz additional.fields de UDM.
headers.http_host additional.fields.value.string_value El valor se toma del campo headers.http_host del registro sin procesar y se asigna a una etiqueta con la clave http_host en la matriz additional.fields de UDM.
headers.http_version network.application_protocol_version El valor se toma del campo headers.http_version del registro sin procesar y se asigna al campo application_protocol_version del objeto network en el modelo de datos unificado.
headers.request_method network.http.method El valor se toma del campo headers.request_method del registro sin procesar y se asigna al campo method del objeto network.http en el modelo de datos unificado.
host.hostname principal.hostname El valor se toma del campo host.hostname del registro sin procesar y se asigna al campo hostname del objeto principal en el modelo de datos unificado.
host.hostname principal.asset.hostname El valor se toma del campo host.hostname del registro sin procesar y se asigna al campo hostname del objeto principal.asset en el modelo de datos unificado.
host.ip principal.asset.ip El valor se toma del campo host.ip del registro sin procesar y se añade a la matriz ip del objeto principal.asset del UDM.
host.ip principal.ip El valor se toma del campo host.ip del registro sin procesar y se añade a la matriz ip del objeto principal del UDM.
host.mac principal.mac El valor se toma del campo host.mac del registro sin procesar y se añade a la matriz mac del objeto principal del UDM.
host.os.platform principal.platform El valor es MAC si el campo host.os.platform del registro sin procesar es igual a macOS.
host.os.version principal.platform_version El valor se toma del campo host.os.version del registro sin procesar y se asigna al campo platform_version del objeto principal en el modelo de datos unificado.
labels.related_item_id metadata.product_log_id El valor se toma del campo labels.related_item_id del registro sin procesar y se asigna al campo product_log_id del objeto metadata en el modelo de datos unificado.
process.command_line principal.process.command_line El valor se toma del campo process.command_line del registro sin procesar y se asigna al campo command_line del objeto principal.process en el modelo de datos unificado.
process.name additional.fields.value.string_value El valor se toma del campo process.name del registro sin procesar y se asigna a una etiqueta con la clave process_name en la matriz additional.fields de UDM.
process.parent.name additional.fields.value.string_value El valor se toma del campo process.parent.name del registro sin procesar y se asigna a una etiqueta con la clave process_parent_name en la matriz additional.fields de UDM.
process.parent.pid principal.process.parent_process.pid El valor se toma del campo process.parent.pid del registro sin procesar, se convierte en una cadena y se asigna al campo pid del objeto principal.process.parent_process de UDM.
process.pid principal.process.pid El valor se toma del campo process.pid del registro sin procesar, se convierte en una cadena y se asigna al campo pid del objeto principal.process de UDM.
user.id principal.user.userid El valor se toma del campo user.id del registro sin procesar y se asigna al campo userid del objeto principal.user en el modelo de datos unificado.
nombre.usuario principal.user.user_display_name El valor se toma del campo user.name del registro sin procesar y se asigna al campo user_display_name del objeto principal.user en el modelo de datos unificado.
N/A metadata.event_timestamp La marca de tiempo del evento se define como la marca de tiempo de la entrada de registro.
N/A metadata.event_type El tipo de evento se define como GENERIC_EVENT si no se encuentra ningún principal. De lo contrario, se define como STATUS_UPDATE.
N/A network.application_protocol El protocolo de aplicación se define como HTTP si el campo headers.http_version del registro sin procesar contiene HTTP.

¿Necesitas más ayuda? Recibe respuestas de los miembros de la comunidad y de los profesionales de Google SecOps.