Raccogliere i log di TeamViewer

Supportato in:

Questo documento spiega come importare i log di TeamViewer in Google Security Operations utilizzando Amazon S3. Il parser estrae gli eventi di controllo dai log in formato JSON. Itera i dettagli degli eventi, mappando proprietà specifiche ai campi Unified Data Model (UDM), gestendo le informazioni di partecipanti e relatori e classificando gli eventi in base all'attività utente. Il parser esegue anche trasformazioni dei dati, ad esempio unisce le etichette e converte i timestamp in un formato standardizzato.

Prima di iniziare

Assicurati di soddisfare i seguenti prerequisiti:

  • Un'istanza Google SecOps.
  • Accesso privilegiato a TeamViewer.
  • Accesso privilegiato ad AWS (S3, Identity and Access Management (IAM), Lambda, EventBridge).

Requisiti di TeamViewer

  1. Accedi alla console di gestione di TeamViewer come amministratore.
  2. Vai a Il mio profilo > App.
  3. Fai clic su Crea app.
  4. Fornisci i seguenti dettagli di configurazione:
    • Nome app: inserisci un nome descrittivo (ad esempio, Google SecOps Integration).
    • Descrizione: inserisci la descrizione dell'app.
    • Autorizzazioni: seleziona le autorizzazioni per l'accesso ai log di controllo.
  5. Fai clic su Crea e salva le credenziali API generate in una posizione sicura.
  6. Registra l'URL di base dell'API TeamViewer (ad esempio, https://webapi.teamviewer.com/api/v1).
  7. Copia e salva in una posizione sicura i seguenti dettagli:
    • CLIENT_ID
    • CLIENT_SECRET
    • API_BASE_URL

Configura il bucket AWS S3 e IAM per Google SecOps

  1. Crea un bucket Amazon S3 seguendo questa guida utente: Creazione di un bucket
  2. Salva il nome e la regione del bucket per riferimento futuro (ad esempio, teamviewer-logs).
  3. Crea un utente seguendo questa guida utente: Creazione di un utente IAM.
  4. Seleziona l'utente creato.
  5. Seleziona la scheda Credenziali di sicurezza.
  6. Fai clic su Crea chiave di accesso nella sezione Chiavi di accesso.
  7. Seleziona Servizio di terze parti come Caso d'uso.
  8. Fai clic su Avanti.
  9. (Facoltativo) Aggiungi il tag della descrizione.
  10. Fai clic su Crea chiave di accesso.
  11. Fai clic su Scarica file CSV per salvare la chiave di accesso e la chiave di accesso segreta per riferimento futuro.
  12. Fai clic su Fine.
  13. Seleziona la scheda Autorizzazioni.
  14. Fai clic su Aggiungi autorizzazioni nella sezione Criteri per le autorizzazioni.
  15. Seleziona Aggiungi autorizzazioni.
  16. Seleziona Allega direttamente i criteri.
  17. Cerca i criteri AmazonS3FullAccess.
  18. Seleziona la policy.
  19. Fai clic su Avanti.
  20. Fai clic su Aggiungi autorizzazioni.

Configura il ruolo e il criterio IAM per i caricamenti S3

  1. Nella console AWS, vai a IAM > Policy.
  2. Fai clic su Crea criterio > scheda JSON.
  3. Copia e incolla i seguenti criteri.
  4. JSON delle policy (sostituisci teamviewer-logs se hai inserito un nome del bucket diverso):

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowPutObjects",
          "Effect": "Allow",
          "Action": "s3:PutObject",
          "Resource": "arn:aws:s3:::teamviewer-logs/*"
        },
        {
          "Sid": "AllowGetStateObject",
          "Effect": "Allow",
          "Action": "s3:GetObject",
          "Resource": "arn:aws:s3:::teamviewer-logs/teamviewer/audit/state.json"
        }
      ]
    }
    
  5. Fai clic su Avanti > Crea criterio.

  6. Vai a IAM > Ruoli > Crea ruolo > Servizio AWS > Lambda.

  7. Allega il criterio appena creato.

  8. Assegna al ruolo il nome TeamViewerToS3Role e fai clic su Crea ruolo.

Crea la funzione Lambda

  1. Nella console AWS, vai a Lambda > Funzioni > Crea funzione.
  2. Fai clic su Crea autore da zero.
  3. Fornisci i seguenti dettagli di configurazione:

    Impostazione Valore
    Nome teamviewer_to_s3
    Tempo di esecuzione Python 3.13
    Architettura x86_64
    Ruolo di esecuzione TeamViewerToS3Role
  4. Dopo aver creato la funzione, apri la scheda Codice, elimina lo stub e incolla il seguente codice (teamviewer_to_s3.py).

    #!/usr/bin/env python3
    # Lambda: Pull TeamViewer audit logs and store raw JSON payloads to S3
    # - Time window via {FROM}/{TO} placeholders (UTC ISO8601), URL-encoded.
    # - Preserves vendor-native JSON format for audit and session data.
    # - Retries with exponential backoff; unique S3 keys to avoid overwrites.
    
    import os, json, time, uuid, urllib.parse
    from urllib.request import Request, urlopen
    from urllib.error import URLError, HTTPError
    
    import boto3
    
    S3_BUCKET   = os.environ["S3_BUCKET"]
    S3_PREFIX   = os.environ.get("S3_PREFIX", "teamviewer/audit/")
    STATE_KEY   = os.environ.get("STATE_KEY", "teamviewer/audit/state.json")
    WINDOW_SEC  = int(os.environ.get("WINDOW_SECONDS", "3600"))  # default 1h
    HTTP_TIMEOUT= int(os.environ.get("HTTP_TIMEOUT", "60"))
    API_BASE_URL = os.environ["API_BASE_URL"]
    CLIENT_ID   = os.environ["CLIENT_ID"]
    CLIENT_SECRET = os.environ["CLIENT_SECRET"]
    MAX_RETRIES = int(os.environ.get("MAX_RETRIES", "3"))
    USER_AGENT  = os.environ.get("USER_AGENT", "teamviewer-to-s3/1.0")
    
    s3 = boto3.client("s3")
    
    def _load_state():
        try:
            obj = s3.get_object(Bucket=S3_BUCKET, Key=STATE_KEY)
            return json.loads(obj["Body"].read())
        except Exception:
            return {}
    
    def _save_state(st):
        s3.put_object(
            Bucket=S3_BUCKET,
            Key=STATE_KEY,
            Body=json.dumps(st, separators=(",", ":")).encode("utf-8"),
            ContentType="application/json",
        )
    
    def _iso(ts: float) -> str:
        return time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(ts))
    
    def _get_access_token() -> str:
        # OAuth2 Client Credentials flow for TeamViewer API
        token_url = f"{API_BASE_URL.rstrip('/')}/oauth2/token"
        data = urllib.parse.urlencode({
            'grant_type': 'client_credentials',
            'client_id': CLIENT_ID,
            'client_secret': CLIENT_SECRET
        }).encode('utf-8')
    
        req = Request(token_url, data=data, method="POST")
        req.add_header("Content-Type", "application/x-www-form-urlencoded")
        req.add_header("User-Agent", USER_AGENT)
    
        with urlopen(req, timeout=HTTP_TIMEOUT) as r:
            response = json.loads(r.read())
            return response["access_token"]
    
    def _build_audit_url(from_ts: float, to_ts: float, access_token: str) -> str:
        # Build URL for TeamViewer audit API endpoint
        base_endpoint = f"{API_BASE_URL.rstrip('/')}/reports/connections"
        params = {
            "from_date": _iso(from_ts),
            "to_date": _iso(to_ts)
        }
        query_string = urllib.parse.urlencode(params)
        return f"{base_endpoint}?{query_string}"
    
    def _fetch_audit_data(url: str, access_token: str) -> tuple[bytes, str]:
        attempt = 0
        while True:
            req = Request(url, method="GET")
            req.add_header("User-Agent", USER_AGENT)
            req.add_header("Authorization", f"Bearer {access_token}")
            req.add_header("Accept", "application/json")
    
            try:
                with urlopen(req, timeout=HTTP_TIMEOUT) as r:
                    return r.read(), (r.headers.get("Content-Type") or "application/json")
            except (HTTPError, URLError) as e:
                attempt += 1
                print(f"HTTP error on attempt {attempt}: {e}")
                if attempt > MAX_RETRIES:
                    raise
                # exponential backoff with jitter
                time.sleep(min(60, 2 ** attempt) + (time.time() % 1))
    
    def _put_audit_data(blob: bytes, content_type: str, from_ts: float, to_ts: float) -> str:
        # Create unique S3 key for audit data
        ts_path = time.strftime("%Y/%m/%d", time.gmtime(to_ts))
        uniq = f"{int(time.time()*1e6)}_{uuid.uuid4().hex[:8]}"
        key = f"{S3_PREFIX}{ts_path}/teamviewer_audit_{int(from_ts)}_{int(to_ts)}_{uniq}.json"
    
        s3.put_object(
            Bucket=S3_BUCKET, 
            Key=key, 
            Body=blob, 
            ContentType=content_type,
            Metadata={
                'source': 'teamviewer-audit',
                'from_timestamp': str(int(from_ts)),
                'to_timestamp': str(int(to_ts))
            }
        )
        return key
    
    def lambda_handler(event=None, context=None):
        st = _load_state()
        now = time.time()
        from_ts = float(st.get("last_to_ts") or (now - WINDOW_SEC))
        to_ts = now
    
        # Get OAuth2 access token
        access_token = _get_access_token()
    
        url = _build_audit_url(from_ts, to_ts, access_token)
        print(f"Fetching TeamViewer audit data from: {url}")
    
        blob, ctype = _fetch_audit_data(url, access_token)
    
        # Validate that we received valid JSON data
        try:
            audit_data = json.loads(blob)
            print(f"Successfully retrieved {len(audit_data.get('records', []))} audit records")
        except json.JSONDecodeError as e:
            print(f"Warning: Invalid JSON received: {e}")
    
        key = _put_audit_data(blob, ctype, from_ts, to_ts)
    
        st["last_to_ts"] = to_ts
        st["last_successful_run"] = now
        _save_state(st)
    
        return {
            "statusCode": 200,
            "body": {
                "success": True, 
                "s3_key": key, 
                "content_type": ctype,
                "from_timestamp": from_ts,
                "to_timestamp": to_ts
            }
        }
    
    if __name__ == "__main__":
        print(lambda_handler())
    
  5. Vai a Configurazione > Variabili di ambiente.

  6. Fai clic su Modifica > Aggiungi nuova variabile di ambiente.

  7. Inserisci le variabili di ambiente fornite nella tabella seguente sostituendo i valori di esempio con i tuoi valori.

    Variabili di ambiente

    Chiave Valore di esempio
    S3_BUCKET teamviewer-logs
    S3_PREFIX teamviewer/audit/
    STATE_KEY teamviewer/audit/state.json
    WINDOW_SECONDS 3600
    HTTP_TIMEOUT 60
    MAX_RETRIES 3
    USER_AGENT teamviewer-to-s3/1.0
    API_BASE_URL https://webapi.teamviewer.com/api/v1
    CLIENT_ID your-client-id (dal passaggio 2)
    CLIENT_SECRET your-client-secret (dal passaggio 2)
  8. Dopo aver creato la funzione, rimani sulla relativa pagina (o apri Lambda > Funzioni > la tua funzione).

  9. Seleziona la scheda Configurazione.

  10. Nel riquadro Configurazione generale, fai clic su Modifica.

  11. Modifica Timeout impostando 5 minuti (300 secondi) e fai clic su Salva.

Creare una pianificazione EventBridge

  1. Vai a Amazon EventBridge > Scheduler > Crea pianificazione.
  2. Fornisci i seguenti dettagli di configurazione:
    • Programma ricorrente: Tariffa (1 hour).
    • Target: la tua funzione Lambda teamviewer_to_s3.
    • Nome: teamviewer-audit-1h
  3. Fai clic su Crea pianificazione.

(Facoltativo) Crea chiavi e utenti IAM di sola lettura per Google SecOps

  1. Vai alla console AWS > IAM > Utenti > Aggiungi utenti.
  2. Fai clic su Add users (Aggiungi utenti).
  3. Fornisci i seguenti dettagli di configurazione:
    • Utente: inserisci secops-reader.
    • Tipo di accesso: seleziona Chiave di accesso - Accesso programmatico.
  4. Fai clic su Crea utente.
  5. Collega la criterio per la lettura minima (personalizzata): Utenti > secops-reader > Autorizzazioni > Aggiungi autorizzazioni > Collega le norme direttamente > Crea norma.
  6. JSON:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": ["s3:GetObject"],
          "Resource": "arn:aws:s3:::teamviewer-logs/*"
        },
        {
          "Effect": "Allow",
          "Action": ["s3:ListBucket"],
          "Resource": "arn:aws:s3:::teamviewer-logs"
        }
      ]
    }
    
  7. Name = secops-reader-policy.

  8. Fai clic su Crea criterio > cerca/seleziona > Avanti > Aggiungi autorizzazioni.

  9. Crea la chiave di accesso per secops-reader: Credenziali di sicurezza > Chiavi di accesso.

  10. Fai clic su Crea chiave di accesso.

  11. Scarica il CSV. Incollerai questi valori nel feed.

Configura un feed in Google SecOps per importare i log di TeamViewer

  1. Vai a Impostazioni SIEM > Feed.
  2. Fai clic su + Aggiungi nuovo feed.
  3. Nel campo Nome feed, inserisci un nome per il feed (ad esempio, TeamViewer logs).
  4. Seleziona Amazon S3 V2 come Tipo di origine.
  5. Seleziona TeamViewer come Tipo di log.
  6. Fai clic su Avanti.
  7. Specifica i valori per i seguenti parametri di input:
    • URI S3: s3://teamviewer-logs/teamviewer/audit/
    • Opzioni di eliminazione dell'origine: seleziona l'opzione di eliminazione in base alle tue preferenze.
    • Età massima del file: includi i file modificati nell'ultimo numero di giorni. Il valore predefinito è 180 giorni.
    • ID chiave di accesso: chiave di accesso utente con accesso al bucket S3.
    • Chiave di accesso segreta: chiave segreta dell'utente con accesso al bucket S3.
    • Spazio dei nomi dell'asset: lo spazio dei nomi dell'asset.
    • Etichette di importazione: l'etichetta applicata agli eventi di questo feed.
  8. Fai clic su Avanti.
  9. Controlla la nuova configurazione del feed nella schermata Finalizza e poi fai clic su Invia.

Tabella di mappatura UDM

Campo log Mappatura UDM Logic
AffectedItem metadata.product_log_id Il valore di AffectedItem del log non elaborato viene mappato direttamente a questo campo UDM.
EventDetails.NewValue principal.resource.attribute.labels.value Se PropertyName contiene (server), NewValue viene utilizzato come valore di un'etichetta in principal.resource.attribute.labels.
EventDetails.NewValue principal.user.user_display_name Se PropertyName è Name of participant, NewValue viene utilizzato come nome visualizzato dell'utente per l'entità.
EventDetails.NewValue principal.user.userid Se PropertyName è ID of participant, NewValue viene utilizzato come ID utente per l'entità.
EventDetails.NewValue security_result.about.labels.value Per tutti gli altri valori di PropertyName (tranne quelli gestiti da condizioni specifiche), NewValue viene utilizzato come valore di un'etichetta all'interno dell'array security_result.about.labels.
EventDetails.NewValue target.file.full_path Se PropertyName è Source file, NewValue viene utilizzato come percorso completo per il file di destinazione.
EventDetails.NewValue target.resource.attribute.labels.value Se PropertyName contiene (client), NewValue viene utilizzato come valore di un'etichetta in target.resource.attribute.labels.
EventDetails.NewValue target.user.user_display_name Se PropertyName è Name of presenter, viene analizzato NewValue. Se è un numero intero, viene ignorato. In caso contrario, viene utilizzato come nome visualizzato dell'utente per la destinazione.
EventDetails.NewValue target.user.userid Se PropertyName è ID of presenter, NewValue viene utilizzato come ID utente per il target.
EventDetails.PropertyName principal.resource.attribute.labels.key Se PropertyName contiene (server), PropertyName viene utilizzato come chiave di un'etichetta in principal.resource.attribute.labels.
EventDetails.PropertyName security_result.about.labels.key Per tutti gli altri valori di PropertyName (tranne quelli gestiti da condizioni specifiche), PropertyName viene utilizzato come chiave di un'etichetta all'interno dell'array security_result.about.labels.
EventDetails.PropertyName target.resource.attribute.labels.key Se PropertyName contiene (client), PropertyName viene utilizzato come chiave di un'etichetta in target.resource.attribute.labels.
EventName metadata.product_event_type Il valore di EventName del log non elaborato viene mappato direttamente a questo campo UDM.
Timestamp metadata.event_timestamp Il valore di Timestamp del log non elaborato viene analizzato e utilizzato come timestamp dell'evento nei metadati. Imposta su USER_UNCATEGORIZED se src_user (derivato da ID of participant) non è vuoto, altrimenti imposta su USER_RESOURCE_ACCESS. Codificato in TEAMVIEWER. Codificato in TEAMVIEWER. Codificato in TEAMVIEWER.

Hai bisogno di ulteriore assistenza? Ricevi risposte dai membri della community e dai professionisti di Google SecOps.