Recolha registos do Cisco AMP for Endpoints
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)
- Inicie sessão na consola do Cisco AMP for Endpoints.
- Aceda a Contas > Credenciais da API.
- Clique em Nova credencial da API para criar uma nova chave da API e um ID de cliente.
- 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.
- Nome da aplicação: introduza um nome (por exemplo,
- Clique em Criar.
- 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
- EUA:
Configure o contentor do AWS S3 e o IAM para o Google SecOps
- Crie um contentor do Amazon S3 seguindo este guia do utilizador: Criar um contentor
- Guarde o nome e a região do contentor para referência futura (por exemplo,
cisco-amp-logs). - Crie um utilizador seguindo este guia do utilizador: criar um utilizador do IAM.
- Selecione o utilizador criado.
- Selecione o separador Credenciais de segurança.
- Clique em Criar chave de acesso na secção Chaves de acesso.
- Selecione Serviço de terceiros como Exemplo de utilização.
- Clicar em Seguinte.
- Opcional: adicione uma etiqueta de descrição.
- Clique em Criar chave de acesso.
- Clique em Transferir ficheiro CSV para guardar a chave de acesso e a chave de acesso secreta para referência futura.
- Clique em Concluído.
- Selecione o separador Autorizações.
- Clique em Adicionar autorizações na secção Políticas de autorizações.
- Selecione Adicionar autorizações.
- Selecione Anexar políticas diretamente.
- Pesquise a política AmazonS3FullAccess.
- Selecione a política.
- Clicar em Seguinte.
- Clique em Adicionar autorizações.
Configure a política e a função de IAM para carregamentos do S3
- Na consola da AWS, aceda a IAM > Políticas.
- Clique em Criar política > separador JSON.
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-logsse tiver introduzido um nome de contentor diferente.
- Substitua
Clique em Seguinte > Criar política.
Aceda a IAM > Funções > Criar função > Serviço AWS > Lambda.
Anexe a política criada recentemente.
Dê o nome
cisco-amp-lambda-roleà função e clique em Criar função.
Crie a função Lambda
- Na consola da AWS, aceda a Lambda > Functions > Create function.
- Clique em Criar do zero.
Faculte os seguintes detalhes de configuração:
Definição Valor Nome cisco-amp-events-collectorRuntime Python 3.13 Arquitetura x86_64 Função de execução cisco-amp-lambda-roleDepois 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)}")Aceda a Configuração > Variáveis de ambiente.
Clique em Editar > Adicionar nova variável de ambiente.
Introduza as seguintes variáveis de ambiente fornecidas, substituindo-as pelos seus valores.
Chave Valor de exemplo S3_BUCKETcisco-amp-logsS3_PREFIXcisco-amp-events/STATE_KEYcisco-amp-events/state.jsonAMP_CLIENT_ID<your-client-id>AMP_API_KEY<your-api-key>API_BASEhttps://api.amp.cisco.com(ou o URL da sua região)PAGE_SIZE500MAX_PAGES10Depois de criar a função, permaneça na respetiva página (ou abra Lambda > Functions > cisco-amp-events-collector).
Selecione o separador Configuração.
No painel Configuração geral, clique em Editar.
Altere Tempo limite para 5 minutos (300 segundos) e clique em Guardar.
Crie um horário do EventBridge
- Aceda a Amazon EventBridge > Scheduler > Create schedule.
- 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.
- Agenda recorrente: Taxa (
- Clique em Criar programação.
Opcional: crie um utilizador e chaves da IAM só de leitura para o Google SecOps
- Aceda a AWS Console > IAM > Users > Add users.
- Clique em Adicionar utilizadores.
- Indique os seguintes detalhes de configuração:
- Utilizador: introduza
secops-reader. - Tipo de acesso: selecione Chave de acesso – Acesso programático.
- Utilizador: introduza
- Clique em Criar utilizador.
- Anexe a política de leitura mínima (personalizada): Users > secops-reader > Permissions > Add permissions > Attach policies directly > Create policy.
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" } ] }Defina o nome como
secops-reader-policy.Aceda a Criar política > pesquise/selecione > Seguinte > Adicionar autorizações.
Aceda a Credenciais de segurança > Chaves de acesso > Criar chave de acesso.
Transfira o CSV (estes valores são introduzidos no feed).
Configure um feed no Google SecOps para carregar registos do Cisco AMP for Endpoints
- Aceda a Definições do SIEM > Feeds.
- Clique em + Adicionar novo feed.
- No campo Nome do feed, introduza um nome para o feed (por exemplo,
Cisco AMP for Endpoints logs). - Selecione Amazon S3 V2 como o Tipo de origem.
- Selecione Cisco AMP como o Tipo de registo.
- Clicar em Seguinte.
- 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.
- URI do S3:
- Clicar em Seguinte.
- 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.