Recolha conjuntos de dados principais do Code42 Incydr

Compatível com:

Este documento explica como carregar conjuntos de dados principais do Code42 Incydr (utilizadores, sessões, auditoria, registos e, opcionalmente, eventos de ficheiros) para o Google Security Operations através do Amazon S3.

Antes de começar

  • Instância do Google SecOps
  • Acesso privilegiado ao Code42 Incydr
  • Acesso privilegiado à AWS (S3, IAM, Lambda, EventBridge)

Recolha os pré-requisitos de origem (IDs, chaves da API, IDs da organização, tokens)

  1. Inicie sessão na IU Web do Code42 Incydr.
  2. Aceda a Administração > Integrações > Clientes da API.
  3. Crie um novo cliente.
  4. Copie e guarde os seguintes detalhes numa localização segura:
    1. ID de cliente.
    2. Segredo do cliente.
    3. URL de base: (por exemplo, https://api.us.code42.com, https://api.us2.code42.com, https://api.ie.code42.com, https://api.gov.code42.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 utilização posterior.
  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 o 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 utilização posterior.
  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 e selecione a política AmazonS3FullAccess.
  18. Clicar em Seguinte.
  19. Clique em Adicionar autorizações.

Configure o AWS Lambda para sondar o Code42 Incydr (sem transformação)

  1. Na consola da AWS, aceda a Lambda > Functions > Create function.
  2. Clique em Criar do zero.
  3. Indique os seguintes detalhes de configuração:
    • Nome: introduza um nome exclusivo e significativo (por exemplo, code42-incydr-pull)
    • Tempo de execução: selecione Python 3.13.
    • Autorizações: selecione uma função com s3:PutObject e Cloudwatch.
  4. Clique em Criar função.
  5. Selecione Configuração > Configuração geral > Editar.
  6. Configure Timeout=5m e Memory=1024 MB.
  7. Clique em Guardar.
  8. Selecione Configuração > Variáveis de ambiente > Editar > Adicionar.
    1. INCYDR_BASE_URL = https://api.us.code42.com
    2. INCYDR_CLIENT_ID = <Client ID>
    3. INCYDR_CLIENT_SECRET = <Client Secret>
    4. S3_BUCKET = code42-incydr
    5. S3_PREFIX = code42/
    6. PAGE_SIZE = 500
    7. LOOKBACK_MINUTES = 60
    8. STREAMS = users,sessions,audit,cases
    9. Opcional: FE_ADV_QUERY_JSON = ``
    10. Opcional: FE_PAGE_SIZE = 1000
  9. Clique em Guardar.
  10. Selecione Código e introduza o seguinte código Python:

    import base64, json, os, time
    from datetime import datetime, timedelta, timezone
    from urllib.parse import urlencode
    from urllib.request import Request, urlopen
    import boto3
    
    BASE = os.environ["INCYDR_BASE_URL"].rstrip("/")
    CID = os.environ["INCYDR_CLIENT_ID"]
    CSECRET = os.environ["INCYDR_CLIENT_SECRET"]
    BUCKET = os.environ["S3_BUCKET"]
    PREFIX_BASE = os.environ.get("S3_PREFIX", "code42/")
    PAGE_SIZE = int(os.environ.get("PAGE_SIZE", "500"))
    LOOKBACK_MINUTES = int(os.environ.get("LOOKBACK_MINUTES", "60"))
    STREAMS = [s.strip() for s in os.environ.get("STREAMS", "users").split(",") if s.strip()]
    FE_ADV_QUERY_JSON = os.environ.get("FE_ADV_QUERY_JSON", "").strip()
    FE_PAGE_SIZE = int(os.environ.get("FE_PAGE_SIZE", "1000"))
    
    s3 = boto3.client("s3")
    
    def now_utc():
        return datetime.now(timezone.utc)
    
    def iso_minus(minutes: int):
        return (now_utc() - timedelta(minutes=minutes)).strftime("%Y-%m-%dT%H:%M:%SZ")
    
    def put_bytes(key: str, body: bytes):
        s3.put_object(Bucket=BUCKET, Key=key, Body=body)
    
    def put_json(prefix: str, page_label: str, data):
        ts = now_utc().strftime("%Y/%m/%d/%H%M%S")
        key = f"{PREFIX_BASE}{prefix}{ts}-{page_label}.json"
        put_bytes(key, json.dumps(data).encode("utf-8"))
        return key
    
    def auth_header():
        auth = base64.b64encode(f"{CID}:{CSECRET}".encode()).decode()
        req = Request(f"{BASE}/v1/oauth", data=b"", method="POST")
        req.add_header("Authorization", f"Basic {auth}")
        req.add_header("Accept", "application/json")
        with urlopen(req, timeout=30) as r:
            data = json.loads(r.read().decode())
        return {"Authorization": f"Bearer {data['access_token']}", "Accept": "application/json"}
    
    def http_get(path: str, params: dict | None = None, headers: dict | None = None):
        url = f"{BASE}{path}"
        if params:
            url += ("?" + urlencode(params))
        req = Request(url, method="GET")
        for k, v in (headers or {}).items():
            req.add_header(k, v)
        with urlopen(req, timeout=60) as r:
            return r.read()
    
    def http_post_json(path: str, body: dict, headers: dict | None = None):
        url = f"{BASE}{path}"
        req = Request(url, data=json.dumps(body).encode("utf-8"), method="POST")
        req.add_header("Content-Type", "application/json")
        for k, v in (headers or {}).items():
            req.add_header(k, v)
        with urlopen(req, timeout=120) as r:
            return r.read()
    
    # USERS (/v1/users)
    
    def pull_users(hdrs):
        next_token = None
        pages = 0
        while True:
            params = {"active": "true", "blocked": "false", "pageSize": PAGE_SIZE}
            if next_token:
                params["pgToken"] = next_token
            raw = http_get("/v1/users", params, hdrs)
            data = json.loads(raw.decode())
            put_json("users/", f"users-page-{pages}", data)
            pages += 1
            next_token = data.get("nextPgToken") or data.get("next_pg_token")
            if not next_token:
                break
        return pages
    
    # SESSIONS (/v1/sessions) — alerts live inside sessions
    
    def pull_sessions(hdrs):
        start_iso = iso_minus(LOOKBACK_MINUTES)
        next_token = None
        pages = 0
        while True:
            params = {
                "hasAlerts": "true",
                "startTime": start_iso,
                "pgSize": PAGE_SIZE,
            }
            if next_token:
                params["pgToken"] = next_token
            raw = http_get("/v1/sessions", params, hdrs)
            data = json.loads(raw.decode())
            put_json("sessions/", f"sessions-page-{pages}", data)
            pages += 1
            next_token = data.get("nextPgToken") or data.get("next_page_token")
            if not next_token:
                break
        return pages
    
    # AUDIT LOG (/v1/audit) — CSV export or paged JSON; write as received
    
    def pull_audit(hdrs):
        start_iso = iso_minus(LOOKBACK_MINUTES)
        next_token = None
        pages = 0
        while True:
            params = {"startTime": start_iso, "pgSize": PAGE_SIZE}
            if next_token:
                params["pgToken"] = next_token
            raw = http_get("/v1/audit", params, hdrs)
            try:
                data = json.loads(raw.decode())
                put_json("audit/", f"audit-page-{pages}", data)
                next_token = data.get("nextPgToken") or data.get("next_page_token")
                pages += 1
                if not next_token:
                    break
            except Exception:
                ts = now_utc().strftime("%Y/%m/%d/%H%M%S")
                key = f"{PREFIX_BASE}audit/{ts}-audit-export.bin"
                put_bytes(key, raw)
                pages += 1
                break
        return pages
    
    # CASES (/v1/cases)
    
    def pull_cases(hdrs):
        next_token = None
        pages = 0
        while True:
            params = {"pgSize": PAGE_SIZE}
            if next_token:
                params["pgToken"] = next_token
            raw = http_get("/v1/cases", params, hdrs)
            data = json.loads(raw.decode())
            put_json("cases/", f"cases-page-{pages}", data)
            pages += 1
            next_token = data.get("nextPgToken") or data.get("next_page_token")
            if not next_token:
                break
        return pages
    
    # FILE EVENTS (/v2/file-events/search) — enabled only if you provide FE_ADV_QUERY_JSON
    
    def pull_file_events(hdrs):
        if not FE_ADV_QUERY_JSON:
            return 0
        try:
            base_query = json.loads(FE_ADV_QUERY_JSON)
        except Exception:
            raise RuntimeError("FE_ADV_QUERY_JSON is not valid JSON")
    
        pages = 0
        next_token = None
        while True:
            body = dict(base_query)
            body["pgSize"] = FE_PAGE_SIZE
            if next_token:
                body["pgToken"] = next_token
            raw = http_post_json("/v2/file-events/search", body, hdrs)
            data = json.loads(raw.decode())
            put_json("file_events/", f"fileevents-page-{pages}", data)
            pages += 1
            next_token = (
                data.get("nextPgToken")
                or data.get("next_page_token")
                or (data.get("file_events") or {}).get("nextPgToken")
            )
            if not next_token:
                break
        return pages
    
    def handler(event, context):
        hdrs = auth_header()
        report = {}
        if "users" in STREAMS:
            report["users_pages"] = pull_users(hdrs)
        if "sessions" in STREAMS:
            report["sessions_pages"] = pull_sessions(hdrs)
        if "audit" in STREAMS:
            report["audit_pages"] = pull_audit(hdrs)
        if "cases" in STREAMS:
            report["cases_pages"] = pull_cases(hdrs)
        if "file_events" in STREAMS:
            report["file_events_pages"] = pull_file_events(hdrs)
        return report
    
    def lambda_handler(event, context):
        return handler(event, context)
    
  11. Clique em Implementar.

Crie um horário do EventBridge

  1. Na consola da AWS, aceda a Amazon EventBridge > Regras.
  2. Clique em Criar regra.
  3. Indique os seguintes detalhes de configuração:
    • Padrão de agendamento: selecione Taxa fixa de 1 hora.
    • Nome: introduza um nome exclusivo e significativo (por exemplo, code42-incydr-hourly).
    • Segmentação: selecione Função Lambda e escolha code42-incydr-pull.
  4. Clique em Criar regra

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

  1. Na consola da AWS, aceda a IAM > Users e, de seguida, clique em Add users.
  2. Indique os seguintes detalhes de configuração:
    • Utilizador: introduza um nome único (por exemplo, secops-reader)
    • Tipo de acesso: selecione Chave de acesso – Acesso programático
    • Clique em Criar utilizador.
  3. Anexe a política de leitura mínima (personalizada): Utilizadores > selecione secops-reader > Autorizações > Adicionar autorizações > Anexar políticas diretamente > Criar política
  4. No editor JSON, introduza a seguinte política:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "s3:GetObject"
          ],
          "Resource": "arn:aws:s3:::<your-bucket>/*"
        },
        {
          "Effect": "Allow",
          "Action": [
            "s3:ListBucket"
          ],
          "Resource": "arn:aws:s3:::<your-bucket>"
        }
      ]
    }
    
  5. Defina o nome como secops-reader-policy.

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

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

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

Configure um feed no Google SecOps para carregar o registo do Code42 Incydr

  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, Code42 Incydr Datasets).
  4. Selecione Amazon S3 V2 como o Tipo de origem.
  5. Selecione Code42 Incydr como o Tipo de registo.
  6. Clicar em Seguinte.
  7. Especifique valores para os seguintes parâmetros de entrada:
    • URI do S3: s3://code42-incydr/code42/
    • 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: predefinição de 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 a aplicar 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.

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