Coletar registros do Snipe-IT

Compatível com:

Este documento explica como ingerir registros do Snipe-IT no Google Security Operations usando o Google Cloud Storage. O Snipe-IT é um sistema de gerenciamento de recursos de TI de código aberto que rastreia hardware, licenças de software, acessórios, consumíveis e outros recursos de TI ao longo do ciclo de vida deles.

Antes de começar

Verifique se você atende os seguintes pré-requisitos:

  • Uma instância do Google SecOps
  • Um projeto do GCP com a API Storage do Cloud ativada
  • Permissões para criar e gerenciar intervalos do GCS
  • Permissões para gerenciar políticas do IAM em buckets do GCS
  • Permissões para criar funções do Cloud Run, tópicos do Pub/Sub e jobs do Cloud Scheduler
  • Acesso privilegiado ao locatário do Snipe-IT

Coletar os pré-requisitos do Snipe-IT (token de API e URL base)

  1. Faça login no Snipe-IT.
  2. Abra o menu do usuário (avatar no canto superior direito) e clique em Gerenciar chaves de API.
  3. Clique em Criar novo token:
    • Nome/Rótulo: insira um rótulo descritivo (por exemplo, Google SecOps export).
  4. Clique em Gerar.
  5. Copie o token da API. Ele só será mostrado uma vez. Armazene com segurança.
  6. Determine o URL base da API, normalmente: https://<your-domain>/api/v1
    • Exemplo: https://snipeit.example.com/api/v1

Criar um bucket do Google Cloud Storage

  1. Acesse o Console do Google Cloud.
  2. Selecione ou crie um projeto.
  3. No menu de navegação, acesse Cloud Storage > Buckets.
  4. Clique em Criar bucket.
  5. Informe os seguintes detalhes de configuração:

    Configuração Valor
    Nomeie seu bucket Insira um nome globalmente exclusivo, por exemplo, snipe-it-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
  6. 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 GCS.

Criar conta de serviço

  1. No console do GCP, acesse IAM e administrador > Contas de serviço.
  2. Clique em Criar conta de serviço.
  3. Informe os seguintes detalhes de configuração:
    • Nome da conta de serviço: insira snipeit-assets-to-gcs-sa.
    • Descrição da conta de serviço: insira Service account for Cloud Run function to collect Snipe-IT logs.
  4. Clique em Criar e continuar.
  5. Na seção Conceder a essa conta de serviço acesso ao projeto:
    1. Clique em Selecionar papel.
    2. Pesquise e selecione Administrador de objetos do Storage.
    3. Clique em + Adicionar outro papel.
    4. Pesquise e selecione Invocador do Cloud Run.
    5. Clique em + Adicionar outro papel.
    6. Pesquise e selecione Invocador de funções do Cloud.
  6. Clique em Continuar.
  7. Clique em Concluído.

Essas funções são necessárias para:

  • Administrador de objetos do Storage: grava registros no bucket do GCS 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 GCS

Conceda permissões de gravação à conta de serviço no bucket do GCS:

  1. Acesse Cloud Storage > Buckets.
  2. Clique no nome do bucket.
  3. Acesse a guia Permissões.
  4. Clique em Conceder acesso.
  5. Informe os seguintes detalhes de configuração:
    • Adicionar principais: insira o e-mail da conta de serviço (por exemplo, snipeit-assets-to-gcs-sa@PROJECT_ID.iam.gserviceaccount.com).
    • Atribuir papéis: selecione Administrador de objetos do Storage.
  6. 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.

  1. No Console do GCP, acesse Pub/Sub > Tópicos.
  2. Selecione Criar tópico.
  3. Informe os seguintes detalhes de configuração:
    • ID do tópico: insira snipeit-assets-trigger.
    • Não mude as outras configurações.
  4. Clique em Criar.

Criar uma função do Cloud Run para coletar registros

A função do Cloud Run é acionada por mensagens do Pub/Sub do Cloud Scheduler para buscar recursos de hardware da API Snipe-IT e gravar no GCS.

  1. No console do GCP, acesse o Cloud Run.
  2. Clique em Criar serviço.
  3. Selecione Função (use um editor in-line para criar uma função).
  4. Na seção Configurar, forneça os seguintes detalhes de configuração:

    Configuração Valor
    Nome do serviço snipeit-assets-to-gcs
    Região Selecione a região correspondente ao seu bucket do GCS (por exemplo, us-central1).
    Ambiente de execução Selecione Python 3.12 ou uma versão mais recente.
  5. Na seção Gatilho (opcional):

    1. Clique em + Adicionar gatilho.
    2. Selecione Cloud Pub/Sub.
    3. Em Selecionar um tópico do Cloud Pub/Sub, escolha o tópico (snipeit-assets-trigger).
    4. Clique em Salvar.
  6. Na seção Autenticação:

    1. Selecione Exigir autenticação.
    2. Confira o Identity and Access Management (IAM).
  7. Role a tela para baixo e abra Contêineres, rede, segurança.

  8. Acesse a guia Segurança:

    • Conta de serviço: selecione a conta de serviço (snipeit-assets-to-gcs-sa).
  9. Acesse a guia Contêineres:

    1. Clique em Variáveis e secrets.
    2. Clique em + Adicionar variável para cada variável de ambiente:
    Nome da variável Valor de exemplo
    GCS_BUCKET snipe-it-logs
    GCS_PREFIX snipeit/assets
    SNIPE_BASE_URL https://snipeit.example.com/api/v1
    SNIPE_API_TOKEN your-api-token
    PAGE_SIZE 500
    MAX_PAGES 200
  10. Role a tela para baixo na guia Variáveis e secrets até Solicitações:

    • Tempo limite da solicitação: insira 600 segundos (10 minutos).
  11. Acesse a guia Configurações em Contêineres:

    • Na seção Recursos:
      • Memória: selecione 512 MiB ou mais.
      • CPU: selecione 1.
    • Clique em Concluído.
  12. Role até Ambiente de execução:

    • Selecione Padrão (recomendado).
  13. 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 ou ajuste com base na carga esperada.
  14. Clique em Criar.

  15. Aguarde a criação do serviço (1 a 2 minutos).

  16. Depois que o serviço é criado, o editor de código inline é aberto automaticamente.

Adicionar código da função

  1. Insira main em Ponto de entrada da função
  2. No editor de código inline, crie dois arquivos:

    • Primeiro arquivo: main.py::

          import functions_framework
          from google.cloud import storage
          import json
          import os
          import urllib3
          from datetime import datetime, timezone
          import urllib.parse
      
          # Initialize HTTP client
          http = urllib3.PoolManager()
      
          # Initialize Storage client
          storage_client = storage.Client()
      
          @functions_framework.cloud_event
          def main(cloud_event):
              """
              Cloud Run function triggered by Pub/Sub to fetch hardware assets from Snipe-IT API and write to GCS.
      
              Args:
                  cloud_event: CloudEvent object containing Pub/Sub message
              """
      
              # Get environment variables
              bucket_name = os.environ.get('GCS_BUCKET')
              prefix = os.environ.get('GCS_PREFIX', 'snipeit/assets')
              base_url = os.environ.get('SNIPE_BASE_URL', '').rstrip('/')
              token = os.environ.get('SNIPE_API_TOKEN')
              page_size = int(os.environ.get('PAGE_SIZE', '500'))
              max_pages = int(os.environ.get('MAX_PAGES', '200'))
      
              if not all([bucket_name, base_url, token]):
                  print('Error: Missing required environment variables')
                  return
      
              try:
                  # Get GCS bucket
                  bucket = storage_client.bucket(bucket_name)
      
                  # Fetch and write pages
                  ts = datetime.now(timezone.utc)
                  offset = 0
                  page = 0
                  total = 0
      
                  headers = {
                      'Authorization': f'Bearer {token}',
                      'Accept': 'application/json',
                      'Content-Type': 'application/json'
                  }
      
                  while page < max_pages:
                      # Fetch page from Snipe-IT API
                      params = {
                          'limit': page_size,
                          'offset': offset,
                          'sort': 'id',
                          'order': 'asc'
                      }
                      qs = urllib.parse.urlencode(params)
                      url = f"{base_url}/hardware?{qs}"
      
                      print(f'Fetching page {page} from {url}')
      
                      response = http.request('GET', url, headers=headers, timeout=60.0)
      
                      if response.status != 200:
                          print(f'Error: API returned status {response.status}')
                          break
      
                      data = json.loads(response.data.decode('utf-8'))
      
                      # Get rows from response (Snipe-IT uses 'rows' field)
                      rows = data.get('rows', [])
                      total_available = data.get('total', 0)
      
                      # Write page to GCS
                      blob_name = f"{prefix}/{ts.strftime('%Y/%m/%d')}/snipeit-hardware-{page:05d}.json"
                      blob = bucket.blob(blob_name)
                      body = json.dumps(data, separators=(',', ':')).encode('utf-8')
                      blob.upload_from_string(body, content_type='application/json')
      
                      print(f'Wrote page {page} with {len(rows)} rows to {blob_name}')
      
                      total += len(rows)
      
                      # Check if we've reached the end
                      # Snipe-IT returns empty rows array when no more data
                      if len(rows) == 0:
                          print(f'No more results (empty rows array)')
                          break
      
                      # Also check if we've fetched all available records
                      if offset + len(rows) >= total_available:
                          print(f'Reached end of data (offset {offset + len(rows)} >= total {total_available})')
                          break
      
                      page += 1
                      offset += page_size
      
                  print(f'Successfully processed {page + 1} pages with {total} total objects')
      
              except Exception as e:
                  print(f'Error processing logs: {str(e)}')
                  raise
          ```
      
    • Segundo arquivo: requirements.txt:

      functions-framework==3.*
      google-cloud-storage==2.*
      urllib3>=2.0.0
      
  3. Clique em Implantar para salvar e implantar a função.

  4. Aguarde a conclusão da implantação (2 a 3 minutos).

Criar o job do Cloud Scheduler

O Cloud Scheduler publica mensagens no tópico do Pub/Sub em intervalos regulares, acionando a função do Cloud Run.

  1. No console do GCP, acesse o Cloud Scheduler.
  2. Clique em Criar job.
  3. Informe os seguintes detalhes de configuração:

    Configuração Valor
    Nome snipeit-assets-to-gcs-hourly
    Região Selecione a mesma região da função do Cloud Run
    Frequência 0 * * * * (de hora em hora)
    Fuso horário Selecionar fuso horário (UTC recomendado)
    Tipo de destino Pub/Sub
    Tópico Selecione o assunto (snipeit-assets-trigger)
    Corpo da mensagem {} (objeto JSON vazio)
  4. Clique em Criar.

Opções de frequência de programação

  • Escolha a frequência com base no volume de registros e nos requisitos de latência:

    Frequência Expressão Cron Caso de uso
    A cada 5 minutos */5 * * * * Alto volume e baixa latência
    A cada 15 minutos */15 * * * * Volume médio
    A cada hora 0 * * * * Padrão (recomendado)
    A cada 6 horas 0 */6 * * * Baixo volume, processamento em lote
    Diário 0 0 * * * Coleta de dados históricos

Testar o job do programador

  1. No console do Cloud Scheduler, encontre seu job.
  2. Clique em Forçar execução para acionar manualmente.
  3. Aguarde alguns segundos e acesse Cloud Run > Serviços > snipeit-assets-to-gcs > Registros.
  4. Verifique se a função foi executada com sucesso.
  5. Verifique o bucket do GCS para confirmar se os registros foram gravados.

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 GCS. Você precisa conceder a essa conta de serviço acesso ao seu bucket.

Receber o e-mail da conta de serviço

  1. Acesse Configurações do SIEM > Feeds.
  2. Clique em Adicionar novo feed.
  3. Clique em Configurar um único feed.
  4. No campo Nome do feed, insira um nome para o feed (por exemplo, Snipe-IT logs).
  5. Selecione Google Cloud Storage V2 como o Tipo de origem.
  6. Selecione Snipe-IT como o Tipo de registro.
  7. Clique em Receber conta de serviço. Um e-mail exclusivo da conta de serviço é exibido, por exemplo:

    chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com
    
  8. Copie esse endereço de e-mail para usar na próxima etapa.

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 GCS.

  1. Acesse Cloud Storage > Buckets.
  2. Clique no nome do bucket.
  3. Acesse a guia Permissões.
  4. Clique em Conceder acesso.
  5. Informe os seguintes detalhes de configuração:
    • Adicionar participantes: cole o e-mail da conta de serviço do Google SecOps.
    • Atribuir papéis: selecione Leitor de objetos do Storage.
  6. Clique em Salvar.

Configurar um feed no Google SecOps para ingerir registros do Snipe-IT

  1. Acesse Configurações do SIEM > Feeds.
  2. Clique em Adicionar novo feed.
  3. Clique em Configurar um único feed.
  4. No campo Nome do feed, insira um nome para o feed (por exemplo, Snipe-IT logs).
  5. Selecione Google Cloud Storage V2 como o Tipo de origem.
  6. Selecione Snipe-IT como o Tipo de registro.
  7. Clique em Próxima.
  8. Especifique valores para os seguintes parâmetros de entrada:

    • URL do bucket de armazenamento: insira o URI do bucket do GCS com o caminho do prefixo:

      gs://snipe-it-logs/snipeit/assets/
      
      • Substitua:

        • snipe-it-logs: o nome do bucket do GCS.
        • snipeit/assets: prefixo/caminho da pasta onde os registros são armazenados.
    • 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.
      • Excluir arquivos transferidos e diretórios vazios: exclui arquivos e diretórios vazios após a transferência.

    • Idade máxima do arquivo: inclui arquivos modificados nos últimos dias. O padrão é de 180 dias.

    • Namespace do recurso: o namespace do recurso.

    • Rótulos de ingestão: o rótulo a ser aplicado aos eventos deste feed.

  9. Clique em Próxima.

  10. Revise a nova configuração do feed na tela Finalizar e clique em Enviar.

Tabela de mapeamento de UDM

Campo de registro Mapeamento de UDM Lógica
created_at.datetime entity.asset.attribute.creation_time Analisado como UNIX_MS
age entity.asset.attribute.labels.value Mapeado diretamente
alt_barcode entity.asset.attribute.labels.value Mapeado diretamente
asset_eol_date entity.asset.attribute.labels.value Mapeado diretamente
asset_tag entity.asset.attribute.labels.value Mapeado diretamente
asset_type_value entity.asset.attribute.labels.value Mapeado diretamente
assets_classification_value entity.asset.attribute.labels.value Mapeado diretamente
category.id entity.asset.attribute.labels.value Mapeado diretamente
custom_fields.RAM.value entity.asset.attribute.labels.value Mapeado diretamente
custom_fields.SSD.value entity.asset.attribute.labels.value Mapeado diretamente
last_update_time.formatted entity.asset.attribute.labels.value Mapeado diretamente
manufacturer.id entity.asset.attribute.labels.value Mapeado diretamente
model_id entity.asset.attribute.labels.value Mapeado diretamente
model_number entity.asset.attribute.labels.value Mapeado diretamente
updated_at.datetime entity.asset.attribute.last_update_time Analisado como UNIX_MS
category.name entity.asset.category Mapeado diretamente
custom_fields.Processor.value entity.asset.hardware.cpu_model Mapeado diretamente
manufacturer.name entity.asset.hardware.manufacturer Mapeado diretamente
model.name entity.asset.hardware.model Mapeado diretamente
serial entity.asset.hardware.serial_number Mapeado diretamente
name entity.asset.hostname Mapeado diretamente
location.name entity.asset.location.name Mapeado diretamente
id entity.asset.product_object_id Mapeado diretamente
custom_fields.Owner.value entity.labels.value Mapeado diretamente
deleted_at entity.labels.value Mapeado diretamente
eol entity.labels.value Mapeado diretamente
expected_checkin entity.labels.value Mapeado diretamente
image entity.labels.value Mapeado diretamente
last_audit_date entity.labels.value Mapeado diretamente
next_audit_date.date entity.labels.value Mapeado diretamente
notes entity.labels.value Mapeado diretamente
order_number entity.labels.value Mapeado diretamente
purchase_cost entity.labels.value Mapeado diretamente
purchase_date.date entity.labels.value Mapeado diretamente
purchase_date.formatted entity.labels.value Mapeado diretamente
qr entity.labels.value Mapeado diretamente
requestable entity.labels.value Mapeado diretamente
requests_counter entity.labels.value Mapeado diretamente
rtd_location.id entity.labels.value Mapeado diretamente
status_label.id entity.labels.value Mapeado diretamente
status_label.status_meta entity.labels.value Mapeado diretamente
status_label.status_type entity.labels.value Mapeado diretamente
supplier.id entity.labels.value Mapeado diretamente
supplier.name entity.labels.value Mapeado diretamente
updated_at.formatted entity.labels.value Mapeado diretamente
warranty_expires.date entity.labels.value Mapeado diretamente
warranty_expires.formatted entity.labels.value Mapeado diretamente
warranty_months entity.labels.value Mapeado diretamente
assigned_to.username entity.user.attribute.labels.value Mapeado diretamente
available_actions.checkin entity.user.attribute.labels.value Mapeado diretamente
available_actions.checkout entity.user.attribute.labels.value Mapeado diretamente
available_actions.clone entity.user.attribute.labels.value Mapeado diretamente
available_actions.delete entity.user.attribute.labels.value Mapeado diretamente
available_actions.restore entity.user.attribute.labels.value Mapeado diretamente
available_actions.update entity.user.attribute.labels.value Mapeado diretamente
checkin_counter entity.user.attribute.labels.value Mapeado diretamente
checkout_counter entity.user.attribute.labels.value Mapeado diretamente
company.id entity.user.attribute.labels.value Mapeado diretamente
created_by.id entity.user.attribute.labels.value Mapeado diretamente
created_by.name entity.user.attribute.labels.value Mapeado diretamente
last_checkin.datetime entity.user.attribute.labels.value Mapeado diretamente
last_checkin.formatted entity.user.attribute.labels.value Mapeado diretamente
last_checkout.formatted entity.user.attribute.labels.value Mapeado diretamente
assigned_to.type entity.user.attribute.roles.name Mapeado diretamente
company.name entity.user.company_name Mapeado diretamente
assigned_to_email entity.user.email_addresses Mesclado
assigned_to.employee_number entity.user.employee_id Mapeado diretamente
assigned_to.first_name entity.user.first_name Mapeado diretamente
last_checkout.datetime entity.user.last_login_time Analisado como UNIX_MS
assigned_to.last_name entity.user.last_name Mapeado diretamente
assigned_to.name entity.user.user_display_name Mapeado diretamente
assigned_to.id entity.user.userid Mapeado diretamente
has_asset metadata.entity_type Mapeado: true → ASSET
has_user metadata.entity_type Mapeado: true → USER
has_asset metadata.product_name Mapeado: true → CMDB
has_user metadata.product_name Mapeado: true → CMDB
has_asset metadata.vendor_name Mapeado: true → Snipe-IT
has_user metadata.vendor_name Mapeado: true → Snipe-IT
N/A entity.asset.attribute.labels.key Constante: model_id
N/A entity.asset.platform_software.platform Constante: WINDOWS
N/A entity.labels.key Constante: purchase_date
N/A entity.user.attribute.labels.key Constante: checkout
N/A metadata.entity_type Constante: ASSET
N/A metadata.product_name Constante: CMDB
N/A metadata.vendor_name Constante: Snipe-IT

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.