Recopila registros de BeyondTrust Endpoint Privilege Management

Compatible con:

En este documento, se explica cómo transferir registros de BeyondTrust Endpoint Privilege Management (EPM) a Google Security Operations con AWS S3. El analizador se enfoca 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 para varios campos y, luego, analiza la carga útil JSON, y, posteriormente, asigna campos específicos del registro sin procesar a los campos de UDM correspondientes dentro del objeto event.idm.read_only_udm.

Antes de comenzar

Asegúrate de cumplir con los siguientes requisitos previos:

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

Configura AWS IAM para la transferencia de datos de Google SecOps

  1. Crea un usuario siguiendo esta guía del usuario: Cómo crear un usuario de IAM.
  2. Selecciona el usuario creado.
  3. Selecciona la pestaña Credenciales de seguridad.
  4. Haz clic en Crear clave de acceso en la sección Claves de acceso.
  5. Selecciona Servicio de terceros como Caso de uso.
  6. Haz clic en Siguiente.
  7. Opcional: Agrega 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 consultarlas en el futuro.
  10. Haz clic en Listo.
  11. Selecciona la pestaña Permisos.
  12. Haz clic en Agregar permisos en la sección Políticas de permisos.
  13. Selecciona Agregar permisos.
  14. Selecciona Adjuntar políticas directamente.
  15. Busca y selecciona la política AmazonS3FullAccess.
  16. Haz clic en Siguiente.
  17. Haz clic en Agregar permisos.

Configura BeyondTrust EPM para el acceso a la API

  1. Accede a la consola web de BeyondTrust Privilege Management como administrador.
  2. Ve a Configuración del sistema > API de REST > Tokens.
  3. Haz clic en Agregar token.
  4. Proporciona los siguientes detalles de configuración:
    • Nombre: Ingresa Google SecOps Collector.
    • Permisos: Selecciona Audit:Read y otros permisos según sea necesario.
  5. Guarda y copia el valor del token (este será tu BPT_API_TOKEN).
  6. Copia tu URL base de la API, que suele ser https://<your-epm-server>/api/v3 o /api/v2, según tu versión (la usarás como BPT_API_URL).

Crea un bucket de AWS S3

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

Crea un rol de IAM para EC2

  1. Accede a la consola de administración de AWS.
  2. Ve a Consola de AWS > Servicios > IAM > Roles > Crear rol.
  3. Proporciona los siguientes detalles de configuración:
    • Entidad de confianza: Servicio de AWS > EC2 > Siguiente.
    • Adjuntar permiso: AmazonS3FullAccess (o una política con alcance para tu bucket) > Siguiente.
    • Nombre del rol: EC2-S3-BPT-Writer > Crear rol

Opcional: Inicia y configura tu VM del recopilador de EC2

  1. Accede a 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 EC2, haz clic en Instances.
  5. Haz clic en Launch instances.
  6. Proporciona los siguientes detalles de configuración:
    • Nombre: Ingresa BPT-Log-Collector.
    • AMI: Selecciona Ubuntu Server 22.04 LTS.
    • Tipo de instancia: t3.micro (o más grande) y, luego, haz clic en Siguiente.
    • Red: Asegúrate de que el parámetro de configuración de red esté establecido en tu VPC predeterminada.
    • Rol de IAM: Selecciona el rol de IAM EC2-S3-BPT-Writer en el menú.
    • Asignar IP pública automáticamente: Habilita esta opción (o asegúrate de poder acceder a ella con una VPN) > Siguiente.
    • Add Storage: Deja la configuración de almacenamiento predeterminada (8 GiB) y, luego, haz clic en Next.
    • Selecciona Crear un grupo de seguridad nuevo.
    • Regla de entrada: Haz clic en Agregar regla.
    • Tipo: Selecciona SSH.
    • Puerto: 22
    • Origen: Tu IP
    • Haz clic en Revisar y lanzar.
    • Selecciona o crea un par de claves.
    • Haz clic en Descargar par de claves.
    • Guarda el archivo PEM descargado. Necesitarás este archivo para conectarte a la instancia con SSH.
  7. Conéctate a tu máquina virtual (VM) con SSH:

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

Instala 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
    

Implementa el script 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 y, luego, ingresa 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
    

Cómo programar tareas diarias con Cron

  1. Ejecuta el siguiente comando:

    crontab -e
    
  2. Agrega el trabajo diario a la medianoche (UTC):

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

Configura feeds

Existen dos puntos de entrada diferentes para configurar feeds en la plataforma de Google SecOps:

  • Configuración de SIEM > Feeds
  • Centro de contenido > Paquetes de contenido

Configura feeds en Configuración del SIEM > Feeds

Para configurar un feed, sigue estos pasos:

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

    • Región: Es la región en la que se encuentra el bucket de Amazon S3.
    • URI de S3: Es el URI del bucket (el formato debe ser s3://your-log-bucket-name/). Reemplaza lo siguiente:
      • your-log-bucket-name: el nombre del bucket.
    • El URI es un: Selecciona Directorio o Directorio que incluye subdirectorios.
    • Opciones de borrado de la fuente: Selecciona la opción de borrado según tu preferencia.
    • ID de clave de acceso: Es la clave de acceso del usuario con acceso al bucket de S3.
    • Clave de acceso secreta: Es la clave secreta del usuario con acceso al bucket de S3.
  9. Haz clic en Siguiente.

  10. Revisa la nueva configuración del feed en la pantalla Finalizar y, luego, haz clic en Enviar.

Configura feeds desde el Centro de contenido

Especifica valores para los siguientes campos:

  • Región: Es la región en la que se encuentra el bucket de Amazon S3.

    • URI de S3: Es el URI del bucket (el formato debe ser s3://your-log-bucket-name/). Reemplaza lo siguiente:
      • your-log-bucket-name: el nombre del bucket.
    • El URI es un: Selecciona Directorio o Directorio que incluye subdirectorios.
    • Opciones de borrado de la fuente: Selecciona la opción de borrado según tu preferencia.
    • ID de clave de acceso: Es la clave de acceso del usuario con acceso al bucket de S3.
    • Clave de acceso secreta: Es la clave secreta del usuario con acceso al bucket de S3.

Opciones avanzadas

  • Nombre del feed: Es un valor completado previamente que identifica el feed.
  • Tipo de fuente: Es el método que se usa para recopilar registros en Google SecOps.
  • Espacio de nombres del activo: Es el espacio de nombres asociado con el feed.
  • Etiquetas de transferencia: Son las etiquetas que se aplican a todos los eventos de este feed.

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 en el registro sin procesar y se asigna a una etiqueta con la clave agent_id dentro del array principal.asset.attribute.labels en el UDM.
agent.version principal.asset.attribute.labels.value El valor se toma del campo agent.version en el registro sin procesar y se asigna a una etiqueta con la clave agent_version dentro del array principal.asset.attribute.labels en el UDM.
ecs.version principal.asset.attribute.labels.value El valor se toma del campo ecs.version en el registro sin procesar y se asigna a una etiqueta con la clave ecs_version dentro del array principal.asset.attribute.labels en el UDM.
event_data.reason metadata.description El valor se toma del campo event_data.reason en el registro sin procesar y se asigna al campo description dentro del objeto metadata en el UDM.
event_datas.ActionId metadata.product_log_id El valor se toma del campo event_datas.ActionId en el registro sin procesar y se asigna al campo product_log_id dentro del objeto metadata en el UDM.
file.path principal.file.full_path El valor se toma del campo file.path en el registro sin procesar y se asigna al campo full_path dentro del objeto principal.file en el UDM.
headers.content_length additional.fields.value.string_value El valor se toma del campo headers.content_length en el registro sin procesar y se asigna a una etiqueta con la clave content_length dentro del array additional.fields en el UDM.
headers.content_type additional.fields.value.string_value El valor se toma del campo headers.content_type en el registro sin procesar y se asigna a una etiqueta con la clave content_type dentro del array additional.fields en el UDM.
headers.http_host additional.fields.value.string_value El valor se toma del campo headers.http_host en el registro sin procesar y se asigna a una etiqueta con la clave http_host dentro del array additional.fields en el UDM.
headers.http_version network.application_protocol_version El valor se toma del campo headers.http_version en el registro sin procesar y se asigna al campo application_protocol_version dentro del objeto network en el UDM.
headers.request_method network.http.method El valor se toma del campo headers.request_method en el registro sin procesar y se asigna al campo method dentro del objeto network.http en el UDM.
host.hostname principal.hostname El valor se toma del campo host.hostname en el registro sin procesar y se asigna al campo hostname dentro del objeto principal en el UDM.
host.hostname principal.asset.hostname El valor se toma del campo host.hostname en el registro sin procesar y se asigna al campo hostname dentro del objeto principal.asset en el UDM.
host.ip principal.asset.ip El valor se toma del campo host.ip en el registro sin procesar y se agrega al array ip dentro del objeto principal.asset en el UDM.
host.ip principal.ip El valor se toma del campo host.ip en el registro sin procesar y se agrega al array ip dentro del objeto principal en el UDM.
host.mac principal.mac El valor se toma del campo host.mac en el registro sin procesar y se agrega al array mac dentro del objeto principal en el UDM.
host.os.platform principal.platform El valor se establece en MAC si el campo host.os.platform en el registro sin procesar es igual a macOS.
host.os.version principal.platform_version El valor se toma del campo host.os.version en el registro sin procesar y se asigna al campo platform_version dentro del objeto principal en el UDM.
labels.related_item_id metadata.product_log_id El valor se toma del campo labels.related_item_id en el registro sin procesar y se asigna al campo product_log_id dentro del objeto metadata en el UDM.
process.command_line principal.process.command_line El valor se toma del campo process.command_line en el registro sin procesar y se asigna al campo command_line dentro del objeto principal.process en el UDM.
process.name additional.fields.value.string_value El valor se toma del campo process.name en el registro sin procesar y se asigna a una etiqueta con la clave process_name dentro del array additional.fields en el UDM.
process.parent.name additional.fields.value.string_value El valor se toma del campo process.parent.name en el registro sin procesar y se asigna a una etiqueta con la clave process_parent_name dentro del array additional.fields en el UDM.
process.parent.pid principal.process.parent_process.pid El valor se toma del campo process.parent.pid en el registro sin procesar, se convierte en una cadena y se asigna al campo pid dentro del objeto principal.process.parent_process en el UDM.
process.pid principal.process.pid El valor se toma del campo process.pid en el registro sin procesar, se convierte en una cadena y se asigna al campo pid dentro del objeto principal.process en el UDM.
user.id principal.user.userid El valor se toma del campo user.id en el registro sin procesar y se asigna al campo userid dentro del objeto principal.user en el UDM.
user.name principal.user.user_display_name El valor se toma del campo user.name en el registro sin procesar y se asigna al campo user_display_name dentro del objeto principal.user en el UDM.
N/A metadata.event_timestamp La marca de tiempo del evento se establece en la marca de tiempo de la entrada de registro.
N/A metadata.event_type El tipo de evento se establece en GENERIC_EVENT si no se encuentra ninguna entidad principal; de lo contrario, se establece en STATUS_UPDATE.
N/A network.application_protocol El protocolo de la aplicación se establece en HTTP si el campo headers.http_version en el registro sin procesar contiene HTTP.

¿Necesitas más ayuda? Obtén respuestas de miembros de la comunidad y profesionales de Google SecOps.