Recoger registros de Cisco AMP para endpoints

Disponible en:

En este documento se explica cómo ingerir registros de Cisco AMP for Endpoints en Google Security Operations mediante Amazon S3. El analizador transforma los registros sin procesar en formato JSON en un formato estructurado conforme al UDM de Chronicle. Extrae campos de objetos JSON anidados, los asigna al esquema de UDM, identifica categorías de eventos, asigna niveles de gravedad y, en última instancia, genera una salida de eventos unificada, marcando alertas de seguridad cuando se cumplen condiciones específicas.

Antes de empezar

  • Una instancia de Google SecOps
  • Acceso privilegiado a la consola de Cisco AMP for Endpoints
  • Acceso privilegiado a AWS (S3, IAM, Lambda y EventBridge)

Recopilar los requisitos previos de Cisco AMP para endpoints (IDs, claves de API, IDs de organización y tokens)

  1. Inicia sesión en la consola de Cisco AMP for Endpoints.
  2. Ve a Cuentas > Credenciales de API.
  3. Haz clic en Nueva credencial de API para crear una clave de API y un ID de cliente.
  4. Proporcione los siguientes detalles de configuración:
    • Nombre de la aplicación: introduce un nombre (por ejemplo, Chronicle SecOps Integration).
    • Ámbito: selecciona Solo lectura para la sondeo de eventos básico o Lectura y escritura si tienes previsto crear flujos de eventos.
  5. Haz clic en Crear.
  6. Copia y guarda en un lugar seguro los siguientes detalles:
    • ID de cliente de API de terceros
    • Clave de API
    • URL base de la API: según tu región:
      • EE. UU.: https://api.amp.cisco.com
      • UE: https://api.eu.amp.cisco.com
      • APJC: https://api.apjc.amp.cisco.com

Configurar un segmento de AWS S3 y IAM para Google SecOps

  1. Crea un segmento de Amazon S3 siguiendo esta guía de usuario: Crear un segmento.
  2. Guarda el nombre y la región del segmento para consultarlos más adelante (por ejemplo, cisco-amp-logs).
  3. Crea un usuario siguiendo esta guía: Crear un usuario de gestión de identidades y accesos.
  4. Selecciona el Usuario creado.
  5. Selecciona la pestaña Credenciales de seguridad.
  6. En la sección Claves de acceso, haz clic en Crear clave de acceso.
  7. Selecciona Servicio de terceros en Caso práctico.
  8. Haz clic en Siguiente.
  9. Opcional: añade una etiqueta de descripción.
  10. Haz clic en Crear clave de acceso.
  11. Haz clic en Descargar archivo CSV para guardar la clave de acceso y la clave de acceso secreta para futuras consultas.
  12. Haz clic en Listo.
  13. Selecciona la pestaña Permisos.
  14. En la sección Políticas de permisos, haz clic en Añadir permisos.
  15. Selecciona Añadir permisos.
  16. Seleccione Adjuntar políticas directamente.
  17. Busca la política AmazonS3FullAccess.
  18. Selecciona la política.
  19. Haz clic en Siguiente.
  20. Haz clic en Añadir permisos.

Configurar la política y el rol de gestión de identidades y accesos para las subidas de S3

  1. En la consola de AWS, ve a IAM > Políticas.
  2. Haz clic en Crear política > pestaña JSON.
  3. Introduce la siguiente política:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowPutObjects",
          "Effect": "Allow",
          "Action": "s3:PutObject",
          "Resource": "arn:aws:s3:::cisco-amp-logs/*"
        },
        {
          "Sid": "AllowGetStateObject",
          "Effect": "Allow",
          "Action": "s3:GetObject",
          "Resource": "arn:aws:s3:::cisco-amp-logs/cisco-amp-events/state.json"
        }
      ]
    }
    
    • Sustituye cisco-amp-logs si has introducido otro nombre de segmento.
  4. Haz clic en Siguiente > Crear política.

  5. Ve a IAM > Roles > Crear rol > Servicio de AWS > Lambda.

  6. Adjunte la política que acaba de crear.

  7. Dale el nombre cisco-amp-lambda-role al rol y haz clic en Crear rol.

Crear la función Lambda

  1. En la consola de AWS, ve a Lambda > Funciones > Crear función.
  2. Haz clic en Crear desde cero.
  3. Proporciona los siguientes detalles de configuración:

    Ajuste Valor
    Nombre cisco-amp-events-collector
    Tiempo de ejecución Python 3.13
    Arquitectura x86_64
    Rol de ejecución cisco-amp-lambda-role
  4. Una vez creada la función, abra la pestaña Código, elimine el stub e introduzca el siguiente código (cisco-amp-events-collector.py):

    import json
    import boto3
    import urllib3
    import base64
    from datetime import datetime, timedelta
    import os
    import logging
    
    # Configure logging
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    
    # AWS S3 client and HTTP pool manager
    s3_client = boto3.client('s3')
    http = urllib3.PoolManager()
    
    def lambda_handler(event, context):
        """
        AWS Lambda handler to fetch Cisco AMP events and store them in S3
        """
    
        try:
            # Get environment variables
            s3_bucket = os.environ['S3_BUCKET']
            s3_prefix = os.environ['S3_PREFIX']
            state_key = os.environ['STATE_KEY']
            api_client_id = os.environ['AMP_CLIENT_ID']
            api_key = os.environ['AMP_API_KEY']
            api_base = os.environ['API_BASE']
    
            # Optional parameters
            page_size = int(os.environ.get('PAGE_SIZE', '500'))
            max_pages = int(os.environ.get('MAX_PAGES', '10'))
    
            logger.info(f"Starting Cisco AMP events collection for bucket: {s3_bucket}")
    
            # Get last run timestamp from state file
            last_timestamp = get_last_timestamp(s3_bucket, state_key)
            if not last_timestamp:
                last_timestamp = (datetime.utcnow() - timedelta(days=1)).isoformat() + 'Z'
    
            # Create Basic Auth header
            auth_header = base64.b64encode(f"{api_client_id}:{api_key}".encode()).decode()
            headers = {
                'Authorization': f'Basic {auth_header}',
                'Accept': 'application/json'
            }
    
            # Build initial API URL
            base_url = f"{api_base}/v1/events"
            next_url = f"{base_url}?limit={page_size}&start_date={last_timestamp}"
    
            all_events = []
            page_count = 0
    
            while next_url and page_count < max_pages:
                logger.info(f"Fetching page {page_count + 1} from: {next_url}")
    
                # Make API request using urllib3
                response = http.request('GET', next_url, headers=headers, timeout=60)
    
                if response.status != 200:
                    raise RuntimeError(f"API request failed: {response.status} {response.data[:256]!r}")
    
                data = json.loads(response.data.decode('utf-8'))
    
                # Extract events from response
                events = data.get('data', [])
                if events:
                    all_events.extend(events)
                    logger.info(f"Collected {len(events)} events from page {page_count + 1}")
    
                    # Check for next page
                    next_url = data.get('metadata', {}).get('links', {}).get('next')
                    page_count += 1
                else:
                    logger.info("No events found on current page")
                    break
    
            logger.info(f"Total events collected: {len(all_events)}")
    
            # Store events in S3 if any were collected
            if all_events:
                timestamp_str = datetime.utcnow().strftime('%Y%m%d_%H%M%S')
                s3_key = f"{s3_prefix}cisco_amp_events_{timestamp_str}.ndjson"
    
                # Convert events to NDJSON format (one JSON object per line)
                ndjson_content = 'n'.join(json.dumps(event) for event in all_events)
    
                # Upload to S3
                s3_client.put_object(
                    Bucket=s3_bucket,
                    Key=s3_key,
                    Body=ndjson_content.encode('utf-8'),
                    ContentType='application/x-ndjson'
                )
    
                logger.info(f"Uploaded {len(all_events)} events to s3://{s3_bucket}/{s3_key}")
    
            # Update state file with current timestamp
            current_timestamp = datetime.utcnow().isoformat() + 'Z'
            update_state(s3_bucket, state_key, current_timestamp)
    
            return {
                'statusCode': 200,
                'body': json.dumps({
                    'message': 'Success',
                    'events_collected': len(all_events),
                    'pages_processed': page_count
                })
            }
    
        except Exception as e:
            logger.error(f"Error in lambda_handler: {str(e)}")
            return {
                'statusCode': 500,
                'body': json.dumps({
                    'error': str(e)
                })
            }
    
    def get_last_timestamp(bucket, state_key):
        """
        Get the last run timestamp from S3 state file
        """
        try:
            response = s3_client.get_object(Bucket=bucket, Key=state_key)
            state_data = json.loads(response['Body'].read().decode('utf-8'))
            return state_data.get('last_timestamp')
        except s3_client.exceptions.NoSuchKey:
            logger.info("No state file found, starting from 24 hours ago")
            return None
        except Exception as e:
            logger.warning(f"Error reading state file: {str(e)}")
            return None
    
    def update_state(bucket, state_key, timestamp):
        """
        Update the state file with the current timestamp
        """
        try:
            state_data = {
                'last_timestamp': timestamp,
                'updated_at': datetime.utcnow().isoformat() + 'Z'
            }
    
            s3_client.put_object(
                Bucket=bucket,
                Key=state_key,
                Body=json.dumps(state_data).encode('utf-8'),
                ContentType='application/json'
            )
    
            logger.info(f"Updated state file with timestamp: {timestamp}")
    
        except Exception as e:
            logger.error(f"Error updating state file: {str(e)}")
    
  5. Vaya a Configuración > Variables de entorno.

  6. Haz clic en Editar > Añadir nueva variable de entorno.

  7. Introduce las siguientes variables de entorno, sustituyendo los valores por los tuyos.

    Clave Valor de ejemplo
    S3_BUCKET cisco-amp-logs
    S3_PREFIX cisco-amp-events/
    STATE_KEY cisco-amp-events/state.json
    AMP_CLIENT_ID <your-client-id>
    AMP_API_KEY <your-api-key>
    API_BASE https://api.amp.cisco.com (o la URL de tu región)
    PAGE_SIZE 500
    MAX_PAGES 10
  8. Una vez creada la función, permanece en su página (o abre Lambda > Funciones > cisco-amp-events-collector).

  9. Seleccione la pestaña Configuración.

  10. En el panel Configuración general, haz clic en Editar.

  11. Cambia Tiempo de espera a 5 minutos (300 segundos) y haz clic en Guardar.

Crear una programación de EventBridge

  1. Ve a Amazon EventBridge > Scheduler > Create schedule (Amazon EventBridge > Programador > Crear programación).
  2. Proporcione los siguientes detalles de configuración:
    • Programación periódica: Precio (1 hour).
    • Destino: tu función Lambda cisco-amp-events-collector.
    • Nombre: cisco-amp-events-collector-1h.
  3. Haz clic en Crear programación.

Opcional: Crear un usuario y claves de gestión de identidades y accesos de solo lectura para Google SecOps

  1. Ve a Consola de AWS > IAM > Usuarios > Añadir usuarios.
  2. Haz clic en Add users (Añadir usuarios).
  3. Proporcione los siguientes detalles de configuración:
    • Usuario: introduce secops-reader.
    • Tipo de acceso: selecciona Clave de acceso – Acceso programático.
  4. Haz clic en Crear usuario.
  5. Asigna una política de lectura mínima (personalizada): Usuarios > secops-reader > Permisos > Añadir permisos > Asignar políticas directamente > Crear política.
  6. En el editor de JSON, introduce la siguiente política:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": ["s3:GetObject"],
          "Resource": "arn:aws:s3:::cisco-amp-logs/*"
        },
        {
          "Effect": "Allow",
          "Action": ["s3:ListBucket"],
          "Resource": "arn:aws:s3:::cisco-amp-logs"
        }
      ]
    }
    
  7. Asigna el nombre secops-reader-policy.

  8. Ve a Crear política > busca o selecciona > Siguiente > Añadir permisos.

  9. Ve a Credenciales de seguridad > Claves de acceso > Crear clave de acceso.

  10. Descarga el archivo CSV (estos valores se introducen en el feed).

Configurar un feed en Google SecOps para ingerir registros de Cisco AMP for Endpoints

  1. Ve a Configuración de SIEM > Feeds.
  2. Haz clic en + Añadir nuevo feed.
  3. En el campo Nombre del feed, introduce un nombre para el feed (por ejemplo, Cisco AMP for Endpoints logs).
  4. Selecciona Amazon S3 V2 como Tipo de fuente.
  5. Selecciona Cisco AMP como Tipo de registro.
  6. Haz clic en Siguiente.
  7. Especifique los valores de los siguientes parámetros de entrada:
    • URI de S3: s3://cisco-amp-logs/cisco-amp-events/
    • Opciones de eliminación de la fuente: selecciona la opción de eliminación que prefieras.
    • Antigüedad máxima del archivo: incluye los archivos modificados en los últimos días. El valor predeterminado es 180 días.
    • ID de clave de acceso: clave de acceso de usuario con acceso al bucket de S3.
    • Clave de acceso secreta: clave secreta del usuario con acceso al bucket de S3.
    • Espacio de nombres de recursos: el espacio de nombres de recursos.
    • Etiquetas de ingestión: la etiqueta aplicada a los eventos de este feed.
  8. Haz clic en Siguiente.
  9. 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
activa read_only_udm.principal.asset.active Asignado directamente desde computer.active
connector_guid read_only_udm.principal.asset.uuid Asignado directamente desde computer.connector_guid
fecha read_only_udm.metadata.event_timestamp.seconds Se asigna directamente desde date después de convertirlo en una marca de tiempo.
detección read_only_udm.security_result.threat_name Asignado directamente desde detection
detection_id read_only_udm.security_result.detection_fields.value Asignado directamente desde detection_id
disposition read_only_udm.security_result.description Asignado directamente desde file.disposition
error.error_code read_only_udm.security_result.detection_fields.value Asignado directamente desde error.error_code
error.description read_only_udm.security_result.detection_fields.value Asignado directamente desde error.description
event_type read_only_udm.metadata.product_event_type Asignado directamente desde event_type
event_type_id read_only_udm.metadata.product_log_id Asignado directamente desde event_type_id
external_ip read_only_udm.principal.asset.external_ip Asignado directamente desde computer.external_ip
file.file_name read_only_udm.target.file.names Asignado directamente desde file.file_name
file.file_path read_only_udm.target.file.full_path Asignado directamente desde file.file_path
file.identity.md5 read_only_udm.security_result.about.file.md5 Asignado directamente desde file.identity.md5
file.identity.md5 read_only_udm.target.file.md5 Asignado directamente desde file.identity.md5
file.identity.sha1 read_only_udm.security_result.about.file.sha1 Asignado directamente desde file.identity.sha1
file.identity.sha1 read_only_udm.target.file.sha1 Asignado directamente desde file.identity.sha1
file.identity.sha256 read_only_udm.security_result.about.file.sha256 Asignado directamente desde file.identity.sha256
file.identity.sha256 read_only_udm.target.file.sha256 Asignado directamente desde file.identity.sha256
file.parent.disposition read_only_udm.target.resource.attribute.labels.value Asignado directamente desde file.parent.disposition
file.parent.file_name read_only_udm.target.resource.attribute.labels.value Asignado directamente desde file.parent.file_name
file.parent.identity.md5 read_only_udm.target.resource.attribute.labels.value Asignado directamente desde file.parent.identity.md5
file.parent.identity.sha1 read_only_udm.target.resource.attribute.labels.value Asignado directamente desde file.parent.identity.sha1
file.parent.identity.sha256 read_only_udm.target.resource.attribute.labels.value Asignado directamente desde file.parent.identity.sha256
file.parent.process_id read_only_udm.security_result.about.process.parent_process.pid Asignado directamente desde file.parent.process_id
file.parent.process_id read_only_udm.target.process.parent_process.pid Asignado directamente desde file.parent.process_id
nombre de host read_only_udm.principal.asset.hostname Asignado directamente desde computer.hostname
nombre de host read_only_udm.target.hostname Asignado directamente desde computer.hostname
nombre de host read_only_udm.target.asset.hostname Asignado directamente desde computer.hostname
ip read_only_udm.principal.asset.ip Asignado directamente desde computer.network_addresses.ip
ip read_only_udm.principal.ip Asignado directamente desde computer.network_addresses.ip
ip read_only_udm.security_result.about.ip Asignado directamente desde computer.network_addresses.ip
mac read_only_udm.principal.mac Asignado directamente desde computer.network_addresses.mac
mac read_only_udm.security_result.about.mac Asignado directamente desde computer.network_addresses.mac
gravedad read_only_udm.security_result.severity Se ha asignado desde severity según la siguiente lógica:
- "Medium" (Media) -> "MEDIUM" (MEDIA)
- "High" (Alta) o "Critical" (Crítica) -> "HIGH" (ALTA)
- "Low" (Baja) -> "LOW" (BAJA)
- En otros casos -> "UNKNOWN_SEVERITY" (GRAVEDAD_DESCONOCIDA)
timestamp read_only_udm.metadata.event_timestamp.seconds Asignado directamente desde timestamp
usuario read_only_udm.security_result.about.user.user_display_name Asignado directamente desde computer.user
usuario read_only_udm.target.user.user_display_name Asignado directamente desde computer.user
vulnerabilities.cve read_only_udm.extensions.vulns.vulnerabilities.cve_id Asignado directamente desde vulnerabilities.cve
vulnerabilities.name read_only_udm.extensions.vulns.vulnerabilities.name Asignado directamente desde vulnerabilities.name
vulnerabilities.score read_only_udm.extensions.vulns.vulnerabilities.cvss_base_score Se asigna directamente desde vulnerabilities.score después de convertirlo en un valor flotante.
vulnerabilities.url read_only_udm.extensions.vulns.vulnerabilities.vendor_knowledge_base_article_id Asignado directamente desde vulnerabilities.url
vulnerabilities.version read_only_udm.extensions.vulns.vulnerabilities.cvss_version Asignado directamente desde vulnerabilities.version
is_alert Se define como true si event_type es uno de los siguientes valores: "Threat Detected" (Amenaza detectada), "Exploit Prevention" (Prevención de exploits), "Executed malware" (Malware ejecutado), "Potential Dropper Infection" (Posible infección de dropper), "Multiple Infected Files" (Varios archivos infectados) o "Vulnerable Application Detected" (Aplicación vulnerable detectada). También se define como true si security_result.severity es "HIGH" (ALTO).
is_significant Se define como true si event_type es uno de los siguientes valores: "Threat Detected" (Amenaza detectada), "Exploit Prevention" (Prevención de exploits), "Executed malware" (Malware ejecutado), "Potential Dropper Infection" (Posible infección de dropper), "Multiple Infected Files" (Varios archivos infectados) o "Vulnerable Application Detected" (Aplicación vulnerable detectada). También se define como true si security_result.severity es "HIGH" (ALTO).
read_only_udm.metadata.event_type Se determina en función de los valores de event_type y security_result.severity.
: si event_type es uno de los siguientes valores: "Executed malware" (Malware ejecutado), "Threat Detected" (Amenaza detectada), "Potential Dropper Infection" (Posible infección por dropper), "Cloud Recall Detection" (Detección de Cloud Recall), "Malicious Activity Detection" (Detección de actividad maliciosa), "Exploit Prevention" (Prevención de exploits), "Multiple Infected Files" (Varios archivos infectados), "Cloud IOC" (IOC en la nube), "System Process Protection" (Protección de procesos del sistema), "Vulnerable Application Detected" (Aplicación vulnerable detectada), "Threat Quarantined" (Amenaza puesta en cuarentena), "Execution Blocked" (Ejecución bloqueada), "Cloud Recall Quarantine Successful" (Cuarentena de Cloud Recall completada), "Cloud Recall Restore from Quarantine Failed" (No se ha podido restaurar Cloud Recall desde la cuarentena), "Cloud Recall Quarantine Attempt Failed" (No se ha podido poner en cuarentena Cloud Recall) o "Quarantine Failure" (Fallo de cuarentena), el tipo de evento se define como "SCAN_FILE".
: si security_result.severity es "HIGH", el tipo de evento se define como "SCAN_FILE".
: si tanto has_principal como has_target son verdaderos, el tipo de evento se define como "SCAN_UNCATEGORIZED".
: en caso contrario, el tipo de evento se define como "GENERIC_EVENT".
read_only_udm.metadata.log_type Se ha definido como "CISCO_AMP"
read_only_udm.metadata.vendor_name Se ha definido como "CISCO_AMP"
read_only_udm.security_result.about.file.full_path Asignado directamente desde file.file_path
read_only_udm.security_result.about.hostname Asignado directamente desde computer.hostname
read_only_udm.security_result.about.user.user_display_name Asignado directamente desde computer.user
read_only_udm.security_result.detection_fields.key Asigna el valor "Detection ID" a detection_id, "Error Code" a error.error_code, "Error Description" a error.description, "Parent Disposition" a file.parent.disposition, "Parent File Name" a file.parent.file_name, "Parent MD5" a file.parent.identity.md5, "Parent SHA1" a file.parent.identity.sha1 y "Parent SHA256" a file.parent.identity.sha256.
read_only_udm.security_result.summary Se define como event_type si event_type es uno de los siguientes valores: "Threat Detected" (Amenaza detectada), "Exploit Prevention" (Prevención de exploits), "Executed malware" (Malware ejecutado), "Potential Dropper Infection" (Posible infección por dropper), "Multiple Infected Files" (Varios archivos infectados) o "Vulnerable Application Detected" (Aplicación vulnerable detectada), o si security_result.severity es "HIGH" (ALTO).
read_only_udm.target.asset.ip Asignado directamente desde computer.network_addresses.ip
read_only_udm.target.resource.attribute.labels.key Asigna el valor "Parent Disposition" a file.parent.disposition, "Parent File Name" a file.parent.file_name, "Parent MD5" a file.parent.identity.md5, "Parent SHA1" a file.parent.identity.sha1 y "Parent SHA256" a file.parent.identity.sha256.
timestamp.seconds Se asigna directamente desde date después de convertirlo en una marca de tiempo.

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