Coletar registros do CloudM
Versão do analisador:6.0
Este documento explica como ingerir registros do CloudM no Google Security Operations usando o Google Cloud Storage V2.
O CloudM é uma plataforma SaaS para o Google Workspace e o Microsoft 365 que oferece automação de fluxo de trabalho para integração e desintegração de usuários, backup, arquivamento e migração de dados. O CloudM Automate gera um registro de auditoria completo de todas as ações realizadas no seu domínio, incluindo eventos de gerenciamento de usuários, etapas do fluxo de trabalho de desvinculação, mudanças de configuração e operações relacionadas à segurança. Os dados do registro de auditoria do ano passado são preservados.
Antes de começar
Verifique se você tem os pré-requisitos a seguir:
- Uma instância do Google SecOps
- Um projeto do Google Cloud com a API Storage Cloud ativada
- Permissões para criar e gerenciar buckets do Cloud Storage
- Permissões para gerenciar políticas do Identity and Access Management (IAM) em buckets do Cloud Storage
- Permissões para criar serviços do Cloud Run, tópicos do Pub/Sub e jobs do Cloud Scheduler
- Acesso de administrador à sua instância do CloudM Automate com a permissão Editar configurações globais
- URL da sua instância do CloudM Automate (por exemplo,
yourcompany.cloudm.io) - Seu ID de domínio do CloudM
Coletar credenciais do CloudM Automate
Criar uma função personalizada para acesso ao registro de API
- Faça login na sua instância do CloudM Automate.
- Acesse Configurações > Funções.
- Clique em Adicionar função para criar uma função.
- No campo Nome da função, insira um nome descritivo (por exemplo,
Google SecOps Log Reader). Na lista de permissões, ative a seguinte permissão:
- Visualizar registros: concede a capacidade de visualizar todos os registros de aplicativos.
Salve a função.
Criar uma conta de serviço e atribuir a função
- No CloudM Automate, acesse Configurações > Funções.
- Crie ou identifique uma conta de serviço para usar no acesso à API.
- Atribua o papel Leitor de registros do Google SecOps à conta de serviço.
- Verifique se o papel está atribuído com o escopo global para que a conta de serviço possa acessar registros em todo o domínio.
Obter o token de acesso da conta de serviço
- Gere um token de acesso para a conta de serviço.
- O token de acesso é usado como um token de portador no cabeçalho
Authorizationao fazer solicitações de API para a API CloudM Logs. Anote os seguintes valores:
- URL da instância do Automate: o URL da sua instância do CloudM Automate (por exemplo,
yourcompany.cloudm.io) - ID do domínio: seu identificador de domínio do CloudM.
- Token de acesso da conta de serviço: o token de portador para autenticação da API.
- URL da instância do Automate: o URL da sua instância do CloudM Automate (por exemplo,
Verifique as permissões
Para verificar se a conta tem as permissões necessárias:
- Faça login no CloudM Automate.
- Acesse Configurações > Funções.
- Verifique se a conta de serviço tem a permissão Visualizar registros atribuída com escopo global.
- Se essa opção não aparecer, entre em contato com seu administrador para conceder as permissões Editar configurações globais e Ver registros.
Testar o acesso à API
Teste suas credenciais antes de continuar com a integração:
# Replace with your actual credentials CLOUDM_INSTANCE="yourcompany.cloudm.io" DOMAIN_ID="your-domain-id" ACCESS_TOKEN="your-access-token" # Test API access curl -v -H "Authorization: Bearer ${ACCESS_TOKEN}" \ "https://${CLOUDM_INSTANCE}/_ah/api/events/v1/${DOMAIN_ID}?from=$(date -u +%Y-%m-%d)&to=$(date -u +%Y-%m-%d)"Uma resposta bem-sucedida retorna uma matriz JSON de eventos de registro de auditoria.
Permissões de API necessárias
A conta de serviço precisa da seguinte permissão:
Permissão Nível de acesso Finalidade Ver registros Global Recuperar todos os eventos de registro de auditoria do CloudM Automate
Criar Google Cloud bucket do Storage
- Acesse o Console do Google Cloud.
- Selecione um projeto ou crie um novo.
- No menu de navegação, acesse Cloud Storage > Buckets.
- Clique em Criar bucket.
Informe os seguintes detalhes de configuração:
Configuração Valor Nomeie seu bucket Insira um nome exclusivo globalmente, por exemplo, cloudm-audit-logs.Tipo de local Escolha de acordo com suas necessidades (região, birregional, multirregional) Local Selecione o local (por exemplo, us-central1).Classe de armazenamento Padrão (recomendado para registros acessados com frequência) Controle de acesso Uniforme (recomendado) Ferramentas de proteção Opcional: ativar o controle de versões de objetos ou a política de retenção Clique em Criar.
Criar uma conta de serviço para a função do Cloud Run
A função do Cloud Run precisa de uma conta de serviço com permissões para gravar no bucket do Cloud Storage e ser invocada pelo Pub/Sub.
Criar conta de serviço
- No Google Cloud Console, acesse IAM e administrador > Contas de serviço.
- Clique em Criar conta de serviço.
- Informe os seguintes detalhes de configuração:
- Nome da conta de serviço: insira
cloudm-audit-collector-sa - Descrição da conta de serviço: digite
Service account for Cloud Run function to collect CloudM audit logs
- Nome da conta de serviço: insira
- Clique em Criar e continuar.
Na seção Conceder acesso a essa conta de serviço ao projeto, adicione os seguintes papéis:
- Clique em Selecionar papel.
- Pesquise e selecione Administrador de objetos do Storage.
- Clique em + Adicionar outro papel.
- Pesquise e selecione Invocador do Cloud Run.
- Clique em + Adicionar outro papel.
- Pesquise e selecione Invocador do Cloud Functions.
Clique em Continuar.
Clique em Concluído.
Esses papéis são necessários para:
- Administrador de objetos do Storage: grava registros em um bucket do Cloud Storage e gerencia arquivos de estado.
- Invocador do Cloud Run: permite que o Pub/Sub invoque a função.
- Invocador do Cloud Functions: permite a invocação de funções
Conceder permissões do IAM no bucket do Cloud Storage
Conceda permissões de gravação à conta de serviço no bucket do Cloud Storage:
- Acesse Cloud Storage > Buckets.
- Clique no nome do bucket (
cloudm-audit-logs). - Acesse a guia Permissões.
- Clique em Conceder acesso.
Informe os seguintes detalhes de configuração:
- Adicionar principais: insira o e-mail da conta de serviço (
cloudm-audit-collector-sa@PROJECT_ID.iam.gserviceaccount.com). - Atribuir papéis: selecione Administrador de objetos do Storage.
- Adicionar principais: insira o e-mail da conta de serviço (
Clique em Salvar.
Criar tópico Pub/Sub
Crie um tópico do Pub/Sub em que o Cloud Scheduler vai publicar e a função do Cloud Run vai se inscrever.
- No Google Cloud Console, acesse Pub/Sub > Tópicos.
- Selecione Criar tópico.
Informe os seguintes detalhes de configuração:
- ID do tópico: insira
cloudm-audit-trigger - Não mude as outras configurações.
- ID do tópico: insira
Clique em Criar.
Criar uma função do Cloud Run para coletar registros
A função do Cloud Run será acionada por mensagens do Pub/Sub do Cloud Scheduler para buscar registros da API CloudM Automate Logs e gravá-los no Cloud Storage.
- No Google Cloud Console, acesse o Cloud Run.
- Clique em Criar serviço.
- Selecione Função (use um editor in-line para criar uma função).
Na seção Configurar, forneça os seguintes detalhes de configuração:
Configuração Valor Nome do serviço cloudm-audit-collectorRegião Selecione a região que corresponde ao seu bucket do Cloud Storage (por exemplo, us-central1).Ambiente de execução Selecione Python 3.12 ou uma versão mais recente. Na seção Acionador (opcional):
- Clique em + Adicionar gatilho.
- Selecione Cloud Pub/Sub.
- Em Selecionar um tópico do Cloud Pub/Sub, escolha
cloudm-audit-trigger. - Clique em Salvar.
Na seção Autenticação:
- Selecione Exigir autenticação.
- Confira o Identity and Access Management (IAM).
Role a tela para baixo e expanda Contêineres, rede, segurança.
Acesse a guia Segurança:
- Conta de serviço: selecione
cloudm-audit-collector-sa
- Conta de serviço: selecione
Acesse a guia Contêineres:
- Clique em Variáveis e secrets.
Clique em + Adicionar variável para cada variável de ambiente:
Nome da variável Valor de exemplo Descrição GCS_BUCKETcloudm-audit-logsNome do bucket do Cloud Storage GCS_PREFIXcloudm-auditPrefixo para arquivos de registro STATE_KEYcloudm-audit/state.jsonCaminho do arquivo de estado CLOUDM_INSTANCE_URLyourcompany.cloudm.ioURL da instância do CloudM Automate CLOUDM_DOMAIN_IDyour-domain-idIdentificador de domínio do CloudM CLOUDM_ACCESS_TOKENyour-access-tokenToken do portador da conta de serviço do CloudM LOOKBACK_HOURS24Período de lookback inicial
Na seção Variáveis e secrets, role a tela para baixo até Solicitações:
- Tempo limite da solicitação: insira
600segundos (10 minutos)
- Tempo limite da solicitação: insira
Acesse a guia Configurações:
Na seção Recursos:
- Memória: selecione 512 MiB ou mais.
- CPU: selecione 1
Na seção Escalonamento de revisão:
- Número mínimo de instâncias: insira
0 - Número máximo de instâncias: insira
100
- Número mínimo de instâncias: insira
Clique em Criar.
Aguarde a criação do serviço (1 a 2 minutos).
Depois que o serviço for criado, o editor de código inline será aberto automaticamente.
Adicionar código da função
- Insira main no campo Ponto de entrada.
No editor de código em linha, crie dois arquivos:
main.py:
import functions_framework from google.cloud import storage import json import os import urllib3 from datetime import datetime, timezone, timedelta http = urllib3.PoolManager( timeout=urllib3.Timeout(connect=10.0, read=60.0), retries=False, ) storage_client = storage.Client() GCS_BUCKET = os.environ.get('GCS_BUCKET') GCS_PREFIX = os.environ.get('GCS_PREFIX', 'cloudm-audit') STATE_KEY = os.environ.get('STATE_KEY', 'cloudm-audit/state.json') CLOUDM_INSTANCE_URL = os.environ.get('CLOUDM_INSTANCE_URL', '').rstrip('/') CLOUDM_DOMAIN_ID = os.environ.get('CLOUDM_DOMAIN_ID') CLOUDM_ACCESS_TOKEN = os.environ.get('CLOUDM_ACCESS_TOKEN') LOOKBACK_HOURS = int(os.environ.get('LOOKBACK_HOURS', '24')) @functions_framework.cloud_event def main(cloud_event): if not all([GCS_BUCKET, CLOUDM_INSTANCE_URL, CLOUDM_DOMAIN_ID, CLOUDM_ACCESS_TOKEN]): print('Error: Missing required environment variables') return try: bucket = storage_client.bucket(GCS_BUCKET) state = load_state(bucket) now = datetime.now(timezone.utc) if isinstance(state, dict) and state.get('last_event_date'): try: last_date = state['last_event_date'] last_time = datetime.strptime(last_date, '%Y-%m-%d').replace(tzinfo=timezone.utc) except Exception as e: print(f"Warning: Could not parse last_event_date: {e}") last_time = now - timedelta(hours=LOOKBACK_HOURS) else: last_time = now - timedelta(hours=LOOKBACK_HOURS) from_date = last_time.strftime('%Y-%m-%d') to_date = now.strftime('%Y-%m-%d') print(f"Fetching logs from {from_date} to {to_date}") records = fetch_logs(from_date, to_date) if not records: print("No new log records found.") save_state(bucket, to_date) return timestamp = now.strftime('%Y%m%d_%H%M%S') object_key = f"{GCS_PREFIX}/cloudm_audit_{timestamp}.ndjson" blob = bucket.blob(object_key) ndjson = '\n'.join( [json.dumps(record, ensure_ascii=False, default=str) for record in records] ) + '\n' blob.upload_from_string(ndjson, content_type='application/x-ndjson') print(f"Wrote {len(records)} records to gs://{GCS_BUCKET}/{object_key}") save_state(bucket, to_date) print(f"Successfully processed {len(records)} records") except Exception as e: print(f'Error processing logs: {str(e)}') raise def fetch_logs(from_date, to_date): instance = CLOUDM_INSTANCE_URL if not instance.startswith('https://'): instance = f"https://{instance}" endpoint = f"{instance}/_ah/api/events/v1/{CLOUDM_DOMAIN_ID}" headers = { 'Authorization': f'Bearer {CLOUDM_ACCESS_TOKEN}', 'Accept': 'application/json', 'User-Agent': 'GoogleSecOps-CloudMCollector/1.0' } url = f"{endpoint}?from={from_date}&to={to_date}" try: response = http.request('GET', url, headers=headers) if response.status == 429: retry_after = int(response.headers.get('Retry-After', '60')) print(f"Rate limited (429). Retry after {retry_after}s.") return [] if response.status != 200: print(f"HTTP Error: {response.status}") response_text = response.data.decode('utf-8') print(f"Response body: {response_text}") return [] data = json.loads(response.data.decode('utf-8')) if isinstance(data, list): records = data elif isinstance(data, dict): records = data.get('items', data.get('events', [data])) else: records = [] print(f"Retrieved {len(records)} events") return records except Exception as e: print(f"Error fetching logs: {e}") return [] def load_state(bucket): try: blob = bucket.blob(STATE_KEY) if blob.exists(): return json.loads(blob.download_as_text()) except Exception as e: print(f"Warning: Could not load state: {e}") return {} def save_state(bucket, last_event_date): try: state = { 'last_event_date': last_event_date, 'last_run': datetime.now(timezone.utc).isoformat() } blob = bucket.blob(STATE_KEY) blob.upload_from_string( json.dumps(state, indent=2), content_type='application/json' ) print(f"Saved state: last_event_date={last_event_date}") except Exception as e: print(f"Warning: Could not save state: {e}")requirements.txt:
functions-framework==3.* google-cloud-storage==2.* urllib3>=2.0.0
Clique em Implantar para salvar e implantar a função.
Aguarde a conclusão da implantação (2 a 3 minutos).
Criar o job do Cloud Scheduler
O Cloud Scheduler vai publicar mensagens no tópico do Pub/Sub em intervalos regulares, acionando a função do Cloud Run.
- No Google Cloud Console, acesse Cloud Scheduler.
- Clique em Criar job.
Informe os seguintes detalhes de configuração:
Configuração Valor Nome cloudm-audit-collector-hourlyRegião Selecione a mesma região da função do Cloud Run Frequência 0 * * * *(a cada hora, na hora)Fuso horário Selecione o fuso horário (UTC recomendado) Tipo de destino Pub/Sub Tópico Selecionar cloudm-audit-triggerCorpo da mensagem {}(objeto JSON vazio)Clique em Criar.
Testar a integração
- No console do Cloud Scheduler, encontre seu job (
cloudm-audit-collector-hourly). - Clique em Forçar execução para acionar o job manualmente.
- Aguarde alguns segundos.
- Acesse Cloud Run > Serviços.
- Clique em
cloudm-audit-collector. - Clique na guia Registros.
Verifique se a função foi executada com sucesso. Procure por:
Fetching logs from YYYY-MM-DD to YYYY-MM-DD Retrieved X events Wrote X records to gs://cloudm-audit-logs/cloudm-audit/cloudm_audit_YYYYMMDD_HHMMSS.ndjson Successfully processed X recordsAcesse Cloud Storage > Buckets.
Clique em
cloudm-audit-logs.Navegue até a pasta
cloudm-audit/.Verifique se um novo arquivo
.ndjsonfoi criado com o carimbo de data/hora atual.
Se você encontrar erros nos registros:
- HTTP 401: verifique se a variável de ambiente
CLOUDM_ACCESS_TOKENestá correta. - HTTP 403: verifique se a conta de serviço tem a permissão Visualizar registros com escopo global.
- HTTP 429: limitação de taxa. A função será interrompida e retomada na próxima execução programada.
- Variáveis de ambiente ausentes: verifique se todas as variáveis necessárias estão definidas na configuração da função do Cloud Run.
Recuperar a conta de serviço do Google SecOps
O Google SecOps usa uma conta de serviço exclusiva para ler dados do seu bucket do Cloud Storage. Você precisa conceder a essa conta de serviço acesso ao seu bucket.
Receber o e-mail da conta de serviço
- Acesse Configurações do SIEM > Feeds.
- Clique em Adicionar novo feed.
- Clique em Configurar um único feed.
- No campo Nome do feed, insira um nome para o feed (por exemplo,
CloudM Audit Logs). - Selecione Google Cloud Storage V2 como o Tipo de origem.
- Selecione CloudM como o Tipo de registro.
Clique em Receber conta de serviço.
Um e-mail exclusivo da conta de serviço será exibido, por exemplo:
chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.comCopie esse endereço de e-mail para usar na próxima etapa.
Clique em Próxima.
Especifique valores para os seguintes parâmetros de entrada:
URL do bucket de armazenamento: insira o URI do bucket do Cloud Storage com o caminho do prefixo:
gs://cloudm-audit-logs/cloudm-audit/Opção de exclusão da fonte: selecione a opção de exclusão de acordo com sua preferência:
- Nunca: nunca exclui arquivos após as transferências (recomendado para testes).
- Excluir arquivos transferidos: exclui os arquivos após a transferência bem-sucedida.
Excluir arquivos transferidos e diretórios vazios: exclui arquivos e diretórios vazios após a transferência bem-sucedida.
Idade máxima do arquivo: inclui arquivos modificados nos últimos dias (o padrão é 180 dias).
Namespace do recurso: o namespace do recurso.
Rótulos de ingestão: o rótulo a ser aplicado aos eventos deste feed.
Clique em Próxima.
Revise a nova configuração do feed na tela Finalizar e clique em Enviar.
Conceder permissões do IAM à conta de serviço do Google SecOps
A conta de serviço do Google SecOps precisa do papel Leitor de objetos do Storage no seu bucket do Cloud Storage.
- Acesse Cloud Storage > Buckets.
- Clique em
cloudm-audit-logs. - Acesse a guia Permissões.
- Clique em Conceder acesso.
Informe os seguintes detalhes de configuração:
- Adicionar principais: cole o e-mail da conta de serviço do Google SecOps.
- Atribuir papéis: selecione Leitor de objetos do Storage.
Clique em Salvar.
Parâmetros da API CloudM Logs
A API CloudM Logs aceita os seguintes parâmetros de consulta para filtrar eventos de registro:
| Parâmetro | Formato | Descrição |
|---|---|---|
| byUser | Endereço de e-mail | Filtre eventos pelo usuário que realizou a ação (análogo a Usuário na interface do CloudM) |
| de | yyyy-MM-dd |
Data de início do filtro de período |
| a | yyyy-MM-dd |
Data de término do filtro de período |
| contextType | String | Filtrar por tipo de contexto (por exemplo, perfil, grupo, UO) |
| contextName | String | Filtre pelo destino de uma ação (por exemplo, um usuário específico sendo desativado) |
| operação | String | Filtre por tipo de operação (por exemplo, atribuir alias, suspender usuário) |
| country | Código do país | Filtrar por código de país de geolocalização |
Tabela de mapeamento de UDM
| Campo de registro | Mapeamento do UDM | Lógica |
|---|---|---|
| sobre | sobre | Valor copiado diretamente |
| Context_Name | about.labels | Mesclados como pares de chave-valor de about_Context_Name, about_Context_Type, labels0 |
| Context_Type | about.labels | |
| Login_Type | about.labels | |
| Emissor | additional.fields | Mesclado de additional_field0, additional_field1, additional_field2 |
| SAML_code | additional.fields | |
| SAML_ACS_Url | additional.fields | |
| Operação | extensions.auth.type | Definido como SSO se a operação corresponder a SSORequest, AUTHTYPE_UNSPECIFIED se Context_Type for LoginUser |
| Context_Type | extensions.auth.type | |
| Carimbo de data/hora | metadata.event_timestamp | Data e hora e fuso horário extraídos do carimbo de data/hora, fuso horário convertido em compensação, concatenado e analisado como carimbo de data/hora |
| Operação | metadata.event_type | Definido como USER_UNCATEGORIZED se a operação corresponder a Update/Delete/SuspendUser/UnsuspendUser/Create, USER_LOGIN se a operação corresponder a SSORequest/SSORequestFail ou Context_Type for LoginUser, STATUS_UPDATE se IP não estiver vazio, caso contrário, GENERIC_EVENT |
| Context_Type | metadata.event_type | |
| User_Agent | network.http.user_agent | Valor copiado diretamente |
| participante | participante | Renomeado de principal se Context_Type != LoginUser, caso contrário, de target |
| target | participante | |
| Organization_Unit | principal.administrative_domain | Valor copiado diretamente |
| IP | principal.ip | Valor copiado diretamente |
| Cidade | principal.location.city | Valor copiado diretamente |
| País | principal.location.country_or_region | Valor copiado diretamente |
| Geolocalização | principal.location.region_latitude | Latitude extraída da geolocalização usando grok |
| Geolocalização | principal.location.region_longitude | Longitude extraída da geolocalização usando grok |
| Região | principal.location.state | Valor copiado diretamente |
| Ator | principal.user.attribute.roles | Definido como role.name se Actor não for e-mail e não estiver vazio, depois mesclado |
| Ator | principal.user.email_addresses | O valor é copiado diretamente se o ator corresponder à regex de e-mail |
| Mensagem | principal.user.userid | Nome de usuário extraído da mensagem usando grok |
| security_result | security_result | Mesclou o objeto security_result |
| SAML_code | security_result.action | Definido como ALLOW se SAML_code corresponder a Success, BLOCK se RequestDenied |
| Mensagem | security_result.description | Valor copiado diretamente |
| Gravidade | security_result.severity | Definido como maiúsculo se Error/Critical, INFORMATIONAL se Info, MEDIUM se Warning, caso contrário, UNKNOWN_SEVERITY |
| Operação | security_result.summary | Valor copiado diretamente |
| target | target | Renomeado de "target" se Context_Type != LoginUser, caso contrário, de "principal" |
| participante | target | |
| metadata.product_name | metadata.product_name | Defina como "CLOUDM" |
| metadata.vendor_name | metadata.vendor_name | Defina como "CLOUDM" |
Registro de alterações
Ver o registro de alterações deste analisador
Precisa de mais ajuda? Receba respostas de membros da comunidade e profissionais do Google SecOps.