Coletar registros do Cisco AMP para Endpoints
Este documento explica como ingerir registros do Cisco AMP for Endpoints no Google Security Operations usando o Amazon S3. O analisador transforma registros brutos formatados em JSON em um formato estruturado de acordo com o UDM do Chronicle. Ele extrai campos de objetos JSON aninhados, mapeia-os para o esquema UDM, identifica categorias de eventos, atribui níveis de gravidade e gera uma saída de evento unificada, sinalizando alertas de segurança quando condições específicas são atendidas.
Antes de começar
- Uma instância do Google SecOps
- Acesso privilegiado ao console do Cisco AMP for Endpoints.
- Acesso privilegiado à AWS (S3, IAM, Lambda, EventBridge)
Coletar os pré-requisitos do Cisco AMP for Endpoints (IDs, chaves de API, IDs da organização, tokens)
- Faça login no console do Cisco AMP for Endpoints.
- Acesse Contas > Credenciais da API.
- Clique em Nova credencial de API para criar uma chave de API e um ID do cliente.
- Informe os seguintes detalhes de configuração:
- Nome do aplicativo: insira um nome (por exemplo,
Chronicle SecOps Integration). - Escopo: selecione Somente leitura para sondagem básica de eventos ou Leitura e gravação se você planeja criar fluxos de eventos.
- Nome do aplicativo: insira um nome (por exemplo,
- Clique em Criar.
- Copie e salve em um local seguro os seguintes detalhes:
- ID do cliente da API de terceiros
- Chave de API
- URL base da API: dependendo da sua região:
- EUA:
https://api.amp.cisco.com - UE:
https://api.eu.amp.cisco.com - APJC:
https://api.apjc.amp.cisco.com
- EUA:
Configurar o bucket do AWS S3 e o IAM para o Google SecOps
- Crie um bucket do Amazon S3 seguindo este guia do usuário: Como criar um bucket
- Salve o Nome e a Região do bucket para referência futura (por exemplo,
cisco-amp-logs). - Crie um usuário seguindo este guia: Como criar um usuário do IAM.
- Selecione o usuário criado.
- Selecione a guia Credenciais de segurança.
- Clique em Criar chave de acesso na seção Chaves de acesso.
- Selecione Serviço de terceiros como Caso de uso.
- Clique em Próxima.
- Opcional: adicione uma tag de descrição.
- Clique em Criar chave de acesso.
- Clique em Fazer o download do arquivo CSV para salvar a chave de acesso e a chave de acesso secreta para referência futura.
- Clique em Concluído.
- Selecione a guia Permissões.
- Clique em Adicionar permissões na seção Políticas de permissões.
- Selecione Adicionar permissões.
- Selecione Anexar políticas diretamente.
- Pesquise a política AmazonS3FullAccess.
- Selecione a política.
- Clique em Próxima.
- Clique em Adicionar permissões
Configurar a política e o papel do IAM para uploads do S3
- No console da AWS, acesse IAM > Políticas.
- Clique em Criar política > guia JSON.
Insira 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 você tiver inserido um nome de bucket diferente.
- Substitua
Clique em Próxima > Criar política.
Acesse IAM > Funções > Criar função > Serviço da AWS > Lambda.
Anexe a política recém-criada.
Nomeie a função como
cisco-amp-lambda-rolee clique em Criar função.
Criar a função Lambda
- No console da AWS, acesse Lambda > Functions > Create function.
- Clique em Criar do zero.
Informe os seguintes detalhes de configuração:
Configuração Valor Nome cisco-amp-events-collectorAmbiente de execução Python 3.13 Arquitetura x86_64 Função de execução cisco-amp-lambda-roleDepois que a função for criada, abra a guia Código, exclua o stub e insira 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)}")Acesse Configuração > Variáveis de ambiente.
Clique em Editar > Adicionar nova variável de ambiente.
Insira as variáveis de ambiente a seguir, substituindo 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 que a função for criada, permaneça na página dela ou abra Lambda > Functions > cisco-amp-events-collector.
Selecione a guia Configuração.
No painel Configuração geral, clique em Editar.
Mude Tempo limite para 5 minutos (300 segundos) e clique em Salvar.
Criar uma programação do EventBridge
- Acesse Amazon EventBridge > Scheduler > Criar programação.
- Informe os seguintes detalhes de configuração:
- Programação recorrente: Taxa (
1 hour). - Destino: sua função Lambda
cisco-amp-events-collector. - Nome:
cisco-amp-events-collector-1h.
- Programação recorrente: Taxa (
- Clique em Criar programação.
Opcional: criar um usuário e chaves do IAM somente leitura para o Google SecOps
- Acesse Console da AWS > IAM > Usuários > Adicionar usuários.
- Clique em Add users.
- Informe os seguintes detalhes de configuração:
- Usuário: insira
secops-reader. - Tipo de acesso: selecione Chave de acesso – Acesso programático.
- Usuário: insira
- Clique em Criar usuário.
- Anexe a política de leitura mínima (personalizada): Usuários > secops-reader > Permissões > Adicionar permissões > Anexar políticas diretamente > Criar política.
No editor JSON, insira 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.Acesse Criar política > pesquise/selecione > Próxima > Adicionar permissões.
Acesse Credenciais de segurança > Chaves de acesso > Criar chave de acesso.
Faça o download do CSV (esses valores são inseridos no feed).
Configurar um feed no Google SecOps para ingerir registros do Cisco AMP for Endpoints
- Acesse Configurações do SIEM > Feeds.
- Clique em + Adicionar novo feed.
- No campo Nome do feed, insira 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 registro.
- Clique em Próxima.
- Especifique valores para os seguintes parâmetros de entrada:
- URI do S3:
s3://cisco-amp-logs/cisco-amp-events/ - Opções de exclusão de fontes: selecione a opção de exclusão de acordo com sua preferência.
- Idade máxima do arquivo: inclui arquivos modificados no último número de dias. O padrão é de 180 dias.
- ID da chave de acesso: chave de acesso do usuário com acesso ao bucket do S3.
- Chave de acesso secreta: chave secreta do usuário com acesso ao bucket do S3.
- Namespace do recurso: o namespace do recurso.
- Rótulos de ingestão: o rótulo aplicado aos eventos deste feed.
- URI do S3:
- Clique em Próxima.
- Revise a nova configuração do feed na tela Finalizar e clique em Enviar.
Tabela de mapeamento do UDM
| Campo de registro | Mapeamento do 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 de date após a conversão para carimbo de data/hora |
| por IA | 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 |
| disposition | 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 |
| nome do host | read_only_udm.principal.asset.hostname | Mapeado diretamente de computer.hostname |
| nome do host | read_only_udm.target.hostname | Mapeado diretamente de computer.hostname |
| nome do host | 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 |
| usuário | read_only_udm.security_result.about.user.user_display_name | Mapeado diretamente de computer.user |
| usuário | 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 de vulnerabilities.score após a conversão para ponto flutuante |
| 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 "true" se event_type for um dos seguintes: "Ameaça detectada", "Prevenção de exploração", "Malware executado", "Possível infecção por dropper", "Vários arquivos infectados", "Aplicativo vulnerável detectado" ou se security_result.severity for "ALTA" |
|
| is_significant | Definido como "true" se event_type for um dos seguintes: "Ameaça detectada", "Prevenção de exploração", "Malware executado", "Possível infecção por dropper", "Vários arquivos infectados", "Aplicativo vulnerável detectado" ou se security_result.severity for "ALTA" |
|
| read_only_udm.metadata.event_type | Determinado com base nos valores event_type e security_result.severity. : se event_type for um dos seguintes: "Malware executado", "Ameaça detectada", "Possível infecção por dropper", "Detecção de recall na nuvem", "Detecção de atividade maliciosa", "Prevenção de exploração", "Vários arquivos infectados", "IOC na nuvem", "Proteção de processos do sistema", "Aplicativo vulnerável detectado", "Ameaça em quarentena", "Execução bloqueada", "Quarentena de recall na nuvem concluída", "Falha na restauração da quarentena de recall na nuvem", "Falha na tentativa de quarentena de recall na nuvem", "Falha na quarentena", o tipo de evento será definido como "SCAN_FILE". : se security_result.severity for "HIGH", o tipo de evento será definido como "SCAN_FILE". : se has_principal e has_target forem verdadeiros, o tipo de evento será definido como "SCAN_UNCATEGORIZED". : caso contrário, o tipo de evento será 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 detecçã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 arquivo 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 detectada", "Prevenção de exploração", "Malware executado", "Possível infecção por dropper", "Vários arquivos infectados", "Aplicativo vulnerável detectado" ou se security_result.severity for "ALTA" |
|
| read_only_udm.target.asset.ip | Mapeado diretamente de computer.network_addresses.ip |
|
| read_only_udm.target.resource.attribute.labels.key | Definido como "Disposição da matriz" para file.parent.disposition, "Nome do arquivo da matriz" para file.parent.file_name, "MD5 da matriz" para file.parent.identity.md5, "SHA1 da matriz" para file.parent.identity.sha1 e "SHA256 da matriz" para file.parent.identity.sha256 |
|
| timestamp.seconds | Mapeado diretamente de date após a conversão para carimbo de data/hora |
Precisa de mais ajuda? Receba respostas de membros da comunidade e profissionais do Google SecOps.