Recolha registos do Cisco AMP for Endpoints

Compatível com:

Este documento explica como carregar registos do Cisco AMP for Endpoints para o Google Security Operations através do Amazon S3. O analisador transforma os registos formatados JSON não processados num formato estruturado em conformidade com o UDM do Chronicle. Extrai campos de objetos JSON aninhados, mapeia-os para o esquema do UDM, identifica categorias de eventos, atribui níveis de gravidade e, em última análise, gera um resultado de evento unificado, sinalizando alertas de segurança quando são cumpridas condições específicas.

Antes de começar

  • Uma instância do Google SecOps
  • Acesso privilegiado à consola do Cisco AMP for Endpoints
  • Acesso privilegiado à AWS (S3, IAM, Lambda, EventBridge)

Recolha os pré-requisitos do Cisco AMP for Endpoints (IDs, chaves da API, IDs da organização e tokens)

  1. Inicie sessão na consola do Cisco AMP for Endpoints.
  2. Aceda a Contas > Credenciais da API.
  3. Clique em Nova credencial da API para criar uma nova chave da API e um ID de cliente.
  4. Indique os seguintes detalhes de configuração:
    • Nome da aplicação: introduza um nome (por exemplo, Chronicle SecOps Integration).
    • Âmbito: selecione Só de leitura para sondagem de eventos básica ou Leitura e escrita se planear criar streams de eventos.
  5. Clique em Criar.
  6. Copie e guarde numa localização segura os seguintes detalhes:
    • ID de cliente da API de terceiros
    • Chave da API
    • URL base da API: consoante a sua região:
      • EUA: https://api.amp.cisco.com
      • UE: https://api.eu.amp.cisco.com
      • APJC: https://api.apjc.amp.cisco.com

Configure o contentor do AWS S3 e o IAM para o Google SecOps

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

Configure a política e a função de IAM para carregamentos do S3

  1. Na consola da AWS, aceda a IAM > Políticas.
  2. Clique em Criar política > separador JSON.
  3. Introduza a seguinte 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"
        }
      ]
    }
    
    • Substitua cisco-amp-logs se tiver introduzido um nome de contentor diferente.
  4. Clique em Seguinte > Criar política.

  5. Aceda a IAM > Funções > Criar função > Serviço AWS > Lambda.

  6. Anexe a política criada recentemente.

  7. Dê o nome cisco-amp-lambda-role à função e clique em Criar função.

Crie a função Lambda

  1. Na consola da AWS, aceda a Lambda > Functions > Create function.
  2. Clique em Criar do zero.
  3. Faculte os seguintes detalhes de configuração:

    Definição Valor
    Nome cisco-amp-events-collector
    Runtime Python 3.13
    Arquitetura x86_64
    Função de execução cisco-amp-lambda-role
  4. Depois de criar a função, abra o separador Código, elimine o fragmento de código e introduza o seguinte 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. Aceda a Configuração > Variáveis de ambiente.

  6. Clique em Editar > Adicionar nova variável de ambiente.

  7. Introduza as seguintes variáveis de ambiente fornecidas, substituindo-as pelos seus valores.

    Chave Valor de exemplo
    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 (ou o URL da sua região)
    PAGE_SIZE 500
    MAX_PAGES 10
  8. Depois de criar a função, permaneça na respetiva página (ou abra Lambda > Functions > cisco-amp-events-collector).

  9. Selecione o separador Configuração.

  10. No painel Configuração geral, clique em Editar.

  11. Altere Tempo limite para 5 minutos (300 segundos) e clique em Guardar.

Crie um horário do EventBridge

  1. Aceda a Amazon EventBridge > Scheduler > Create schedule.
  2. Indique os seguintes detalhes de configuração:
    • Agenda recorrente: Taxa (1 hour).
    • Alvo: a sua função Lambda cisco-amp-events-collector.
    • Nome: cisco-amp-events-collector-1h.
  3. Clique em Criar programação.

Opcional: crie um utilizador e chaves da IAM só de leitura para o Google SecOps

  1. Aceda a AWS Console > IAM > Users > Add users.
  2. Clique em Adicionar utilizadores.
  3. Indique os seguintes detalhes de configuração:
    • Utilizador: introduza secops-reader.
    • Tipo de acesso: selecione Chave de acesso – Acesso programático.
  4. Clique em Criar utilizador.
  5. Anexe a política de leitura mínima (personalizada): Users > secops-reader > Permissions > Add permissions > Attach policies directly > Create policy.
  6. No editor JSON, introduza a seguinte 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. Defina o nome como secops-reader-policy.

  8. Aceda a Criar política > pesquise/selecione > Seguinte > Adicionar autorizações.

  9. Aceda a Credenciais de segurança > Chaves de acesso > Criar chave de acesso.

  10. Transfira o CSV (estes valores são introduzidos no feed).

Configure um feed no Google SecOps para carregar registos do Cisco AMP for Endpoints

  1. Aceda a Definições do SIEM > Feeds.
  2. Clique em + Adicionar novo feed.
  3. No campo Nome do feed, introduza um nome para o feed (por exemplo, Cisco AMP for Endpoints logs).
  4. Selecione Amazon S3 V2 como o Tipo de origem.
  5. Selecione Cisco AMP como o Tipo de registo.
  6. Clicar em Seguinte.
  7. Especifique valores para os seguintes parâmetros de entrada:
    • URI do S3: s3://cisco-amp-logs/cisco-amp-events/
    • Opções de eliminação de origens: selecione a opção de eliminação de acordo com a sua preferência.
    • Idade máxima do ficheiro: inclua ficheiros modificados no último número de dias. A predefinição é 180 dias.
    • ID da chave de acesso: chave de acesso do utilizador com acesso ao contentor do S3.
    • Chave de acesso secreta: chave secreta do utilizador com acesso ao contentor do S3.
    • Espaço de nomes do recurso: o espaço de nomes do recurso.
    • Etiquetas de carregamento: a etiqueta aplicada aos eventos deste feed.
  8. Clicar em Seguinte.
  9. Reveja a nova configuração do feed no ecrã Finalizar e, de seguida, clique em Enviar.

Tabela de mapeamento da UDM

Campo de registo Mapeamento de UDM Lógica
ativo read_only_udm.principal.asset.active Mapeado diretamente de computer.active
connector_guid read_only_udm.principal.asset.uuid Mapeado diretamente de computer.connector_guid
data read_only_udm.metadata.event_timestamp.seconds Mapeado diretamente a partir de date após a conversão para indicação de tempo
deteção read_only_udm.security_result.threat_name Mapeado diretamente de detection
detection_id read_only_udm.security_result.detection_fields.value Mapeado diretamente de detection_id
disposição read_only_udm.security_result.description Mapeado diretamente de file.disposition
error.error_code read_only_udm.security_result.detection_fields.value Mapeado diretamente de error.error_code
error.description read_only_udm.security_result.detection_fields.value Mapeado diretamente de error.description
event_type read_only_udm.metadata.product_event_type Mapeado diretamente de event_type
event_type_id read_only_udm.metadata.product_log_id Mapeado diretamente de event_type_id
external_ip read_only_udm.principal.asset.external_ip Mapeado diretamente de computer.external_ip
file.file_name read_only_udm.target.file.names Mapeado diretamente de file.file_name
file.file_path read_only_udm.target.file.full_path Mapeado diretamente de file.file_path
file.identity.md5 read_only_udm.security_result.about.file.md5 Mapeado diretamente de file.identity.md5
file.identity.md5 read_only_udm.target.file.md5 Mapeado diretamente de file.identity.md5
file.identity.sha1 read_only_udm.security_result.about.file.sha1 Mapeado diretamente de file.identity.sha1
file.identity.sha1 read_only_udm.target.file.sha1 Mapeado diretamente de file.identity.sha1
file.identity.sha256 read_only_udm.security_result.about.file.sha256 Mapeado diretamente de file.identity.sha256
file.identity.sha256 read_only_udm.target.file.sha256 Mapeado diretamente de file.identity.sha256
file.parent.disposition read_only_udm.target.resource.attribute.labels.value Mapeado diretamente de file.parent.disposition
file.parent.file_name read_only_udm.target.resource.attribute.labels.value Mapeado diretamente de file.parent.file_name
file.parent.identity.md5 read_only_udm.target.resource.attribute.labels.value Mapeado diretamente de file.parent.identity.md5
file.parent.identity.sha1 read_only_udm.target.resource.attribute.labels.value Mapeado diretamente de file.parent.identity.sha1
file.parent.identity.sha256 read_only_udm.target.resource.attribute.labels.value Mapeado diretamente de file.parent.identity.sha256
file.parent.process_id read_only_udm.security_result.about.process.parent_process.pid Mapeado diretamente de file.parent.process_id
file.parent.process_id read_only_udm.target.process.parent_process.pid Mapeado diretamente de file.parent.process_id
hostname read_only_udm.principal.asset.hostname Mapeado diretamente de computer.hostname
hostname read_only_udm.target.hostname Mapeado diretamente de computer.hostname
hostname read_only_udm.target.asset.hostname Mapeado diretamente de computer.hostname
ip read_only_udm.principal.asset.ip Mapeado diretamente de computer.network_addresses.ip
ip read_only_udm.principal.ip Mapeado diretamente de computer.network_addresses.ip
ip read_only_udm.security_result.about.ip Mapeado diretamente de computer.network_addresses.ip
mac read_only_udm.principal.mac Mapeado diretamente de computer.network_addresses.mac
mac read_only_udm.security_result.about.mac Mapeado diretamente de computer.network_addresses.mac
gravidade read_only_udm.security_result.severity Mapeado de severity com base na seguinte lógica:
- "Medium" -> "MEDIUM"
- "High" ou "Critical" -> "HIGH"
- "Low" -> "LOW"
- Caso contrário -> "UNKNOWN_SEVERITY"
timestamp read_only_udm.metadata.event_timestamp.seconds Mapeado diretamente de timestamp
utilizador read_only_udm.security_result.about.user.user_display_name Mapeado diretamente de computer.user
utilizador read_only_udm.target.user.user_display_name Mapeado diretamente de computer.user
vulnerabilities.cve read_only_udm.extensions.vulns.vulnerabilities.cve_id Mapeado diretamente de vulnerabilities.cve
vulnerabilities.name read_only_udm.extensions.vulns.vulnerabilities.name Mapeado diretamente de vulnerabilities.name
vulnerabilities.score read_only_udm.extensions.vulns.vulnerabilities.cvss_base_score Mapeado diretamente a partir de vulnerabilities.score após a conversão para float
vulnerabilities.url read_only_udm.extensions.vulns.vulnerabilities.vendor_knowledge_base_article_id Mapeado diretamente de vulnerabilities.url
vulnerabilities.version read_only_udm.extensions.vulns.vulnerabilities.cvss_version Mapeado diretamente de vulnerabilities.version
is_alert Definido como verdadeiro se event_type for um dos seguintes: "Ameaça detetada", "Prevenção de explorações", "Software malicioso executado", "Potencial infeção por dropper", "Vários ficheiros infetados", "Aplicação vulnerável detetada" ou se security_result.severity for "ALTO"
is_significant Definido como verdadeiro se event_type for um dos seguintes: "Ameaça detetada", "Prevenção de explorações", "Software malicioso executado", "Potencial infeção por dropper", "Vários ficheiros infetados", "Aplicação vulnerável detetada" ou se security_result.severity for "ALTO"
read_only_udm.metadata.event_type Determinado com base nos valores de event_type e security_result.severity.
- Se event_type for um dos seguintes: "Executed malware", "Threat Detected", "Potential Dropper Infection", "Cloud Recall Detection", "Malicious Activity Detection", "Exploit Prevention", "Multiple Infected Files", "Cloud IOC", "System Process Protection", "Vulnerable Application Detected", "Threat Quarantined", "Execution Blocked", "Cloud Recall Quarantine Successful", "Cloud Recall Restore from Quarantine Failed", "Cloud Recall Quarantine Attempt Failed" ou "Quarantine Failure", o tipo de evento é definido como "SCAN_FILE".
- Se security_result.severity for "HIGH", o tipo de evento é definido como "SCAN_FILE".
- Se has_principal e has_target forem verdadeiros, o tipo de evento é definido como "SCAN_UNCATEGORIZED".
- Caso contrário, o tipo de evento é definido como "GENERIC_EVENT".
read_only_udm.metadata.log_type Definido como "CISCO_AMP"
read_only_udm.metadata.vendor_name Definido como "CISCO_AMP"
read_only_udm.security_result.about.file.full_path Mapeado diretamente de file.file_path
read_only_udm.security_result.about.hostname Mapeado diretamente de computer.hostname
read_only_udm.security_result.about.user.user_display_name Mapeado diretamente de computer.user
read_only_udm.security_result.detection_fields.key Definido como "ID de deteção" para detection_id, "Código de erro" para error.error_code, "Descrição do erro" para error.description, "Disposição principal" para file.parent.disposition, "Nome do ficheiro principal" para file.parent.file_name, "MD5 principal" para file.parent.identity.md5, "SHA1 principal" para file.parent.identity.sha1 e "SHA256 principal" para file.parent.identity.sha256
read_only_udm.security_result.summary Definido como event_type se event_type for um dos seguintes: "Ameaça detetada", "Prevenção de explorações", "Software malicioso executado", "Potencial infeção por instalador", "Vários ficheiros infetados", "Aplicação vulnerável detetada" ou se security_result.severity for "ALTO"
read_only_udm.target.asset.ip Mapeado diretamente de computer.network_addresses.ip
read_only_udm.target.resource.attribute.labels.key Definido como "Parent Disposition" para file.parent.disposition, "Parent File Name" para file.parent.file_name, "Parent MD5" para file.parent.identity.md5, "Parent SHA1" para file.parent.identity.sha1 e "Parent SHA256" para file.parent.identity.sha256
timestamp.seconds Mapeado diretamente a partir de date após a conversão para indicação de tempo

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