Zendesk CRM-Protokolle erfassen

Unterstützt in:

In diesem Dokument wird beschrieben, wie Sie Zendesk CRM-Logs (Customer Relationship Management) mit Amazon S3 in Google Security Operations aufnehmen.

Hinweise

Prüfen Sie, ob folgende Voraussetzungen erfüllt sind:

  • Eine Google SecOps-Instanz.
  • Privilegierter Zugriff auf Zendesk.
  • Privilegierter Zugriff auf AWS (S3, Identity and Access Management (IAM), Lambda, EventBridge).

Zendesk-Voraussetzungen

  1. Tarif und Rolle bestätigen
    1. Sie müssen Zendesk-Administrator sein, um API-Tokens oder OAuth-Clients zu erstellen. Die Audit Logs API ist nur im Enterprise-Abo verfügbar. Wenn Sie kein Enterprise-Konto haben, überspringen Sie audit_logs in RESOURCES.
  2. API-Tokenzugriff aktivieren (einmalig)
    1. Gehen Sie im Admin Center zu Apps und Integrationen > APIs > API-Konfiguration.
    2. Aktivieren Sie API-Token-Zugriff zulassen.
  3. API-Token generieren (für die einfache Authentifizierung)
    1. Klicken Sie auf Apps und Integrationen > APIs > API-Tokens.
    2. Klicken Sie auf API-Token hinzufügen> (optional) Beschreibung hinzufügen> Speichern.
    3. Kopieren und speichern Sie jetzt das API-Token. Sie können es später nicht mehr aufrufen.
    4. Speichern Sie die Administrator-E-Mail-Adresse, mit der dieses Token authentifiziert wird.
      • Von der Lambda verwendetes Format für die Basisauthentifizierung: email_address/token:api_token
  4. (Optional) OAuth-Client erstellen (für die Bearer-Authentifizierung anstelle eines API-Tokens)
    1. Rufen Sie Apps und Integrationen > APIs > OAuth-Clients > OAuth-Client hinzufügen auf.
    2. Geben Sie Name, Unique Identifier (eindeutige Kennung, automatisch), Redirect URLs (Umleitungs-URLs, kann Platzhalter sein, wenn Sie Tokens nur mit der API erstellen) ein und klicken Sie auf Save (Speichern).
    3. Erstellen Sie ein Zugriffstoken für die Integration und gewähren Sie die in dieser Anleitung erforderlichen Mindestbereiche:
      • tickets:read (für inkrementelle Tickets)
      • auditlogs:read (für Audit-Logs; nur Enterprise)
      • Wenn Sie sich nicht sicher sind, funktioniert read auch für den schreibgeschützten Zugriff.
    4. Kopieren Sie das Zugriffstoken (fügen Sie es in ZENDESK_BEARER_TOKEN ein) und notieren Sie die Client-ID/den Clientschlüssel sicher (für zukünftige Token-Aktualisierungsabläufe).
  5. Zendesk-Basis-URL notieren

    • Verwenden Sie https://<your_subdomain>.zendesk.com (fügen Sie sie in die Umgebungsvariable ZENDESK_BASE_URL ein).

    Was soll kopiert und für später gespeichert werden?

    • Basis-URL (z. B. https://acme.zendesk.com)
    • E-Mail-Adresse des Administratornutzers (für die API-Token-Authentifizierung)
    • API-Token (bei Verwendung von AUTH_MODE=token)
    • oder OAuth-Zugriffstoken (bei Verwendung von AUTH_MODE=bearer)
    • Optional: OAuth-Client-ID/Schlüssel für die Lebenszyklusverwaltung

AWS S3-Bucket und IAM für Google SecOps konfigurieren

  1. Erstellen Sie einen Amazon S3-Bucket. Folgen Sie dazu der Anleitung unter Bucket erstellen.
  2. Speichern Sie den Namen und die Region des Buckets zur späteren Verwendung (z. B. zendesk-crm-logs).
  3. Erstellen Sie einen Nutzer gemäß dieser Anleitung: IAM-Nutzer erstellen.
  4. Wählen Sie den erstellten Nutzer aus.
  5. Wählen Sie den Tab Sicherheitsanmeldedaten aus.
  6. Klicken Sie im Abschnitt Zugriffsschlüssel auf Zugriffsschlüssel erstellen.
  7. Wählen Sie Drittanbieterdienst als Anwendungsfall aus.
  8. Klicken Sie auf Weiter.
  9. Optional: Fügen Sie ein Beschreibungstag hinzu.
  10. Klicken Sie auf Zugriffsschlüssel erstellen.
  11. Klicken Sie auf CSV-Datei herunterladen, um den Access Key (Zugriffsschlüssel) und den Secret Access Key (geheimer Zugriffsschlüssel) für die zukünftige Verwendung zu speichern.
  12. Klicken Sie auf Fertig.
  13. Wählen Sie den Tab Berechtigungen aus.
  14. Klicken Sie im Bereich Berechtigungsrichtlinien auf Berechtigungen hinzufügen.
  15. Wählen Sie Berechtigungen hinzufügen aus.
  16. Wählen Sie Richtlinien direkt anhängen aus.
  17. Suchen Sie nach der Richtlinie AmazonS3FullAccess.
  18. Wählen Sie die Richtlinie aus.
  19. Klicken Sie auf Weiter.
  20. Klicken Sie auf Berechtigungen hinzufügen.

IAM-Richtlinie und ‑Rolle für S3-Uploads konfigurieren

  1. Rufen Sie in der AWS-Konsole IAM > Richtlinien auf.
  2. Klicken Sie auf Richtlinie erstellen> Tab „JSON“.
  3. Kopieren Sie die folgende Richtlinie und fügen Sie sie ein.
  4. Policy JSON (ersetzen Sie zendesk-crm-logs, wenn Sie einen anderen Bucket-Namen eingegeben haben):

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowPutObjects",
          "Effect": "Allow",
          "Action": "s3:PutObject",
          "Resource": "arn:aws:s3:::zendesk-crm-logs/*"
        },
        {
          "Sid": "AllowGetStateObject",
          "Effect": "Allow",
          "Action": "s3:GetObject",
          "Resource": "arn:aws:s3:::zendesk-crm-logs/zendesk/crm/state.json"
        }
      ]
    }
    
  5. Klicken Sie auf Weiter > Richtlinie erstellen.

  6. Rufen Sie IAM > Rollen > Rolle erstellen > AWS-Service > Lambda auf.

  7. Hängen Sie die neu erstellte Richtlinie an.

  8. Geben Sie der Rolle den Namen ZendeskCRMToS3Role und klicken Sie auf Rolle erstellen.

Lambda-Funktion erstellen

  1. Rufen Sie in der AWS Console Lambda > Funktionen > Funktion erstellen auf.
  2. Klicken Sie auf Von Grund auf erstellen.
  3. Geben Sie die folgenden Konfigurationsdetails an:

    Einstellung Wert
    Name zendesk_crm_to_s3
    Laufzeit Python 3.13
    Architektur x86_64
    Ausführungsrolle ZendeskCRMToS3Role
  4. Nachdem die Funktion erstellt wurde, öffnen Sie den Tab Code, löschen Sie den Stub und fügen Sie den folgenden Code (zendesk_crm_to_s3.py) ein.

    #!/usr/bin/env python3
    
    import os, json, time, base64
    from urllib.request import Request, urlopen
    from urllib.error import HTTPError, URLError
    import boto3
    
    S3_BUCKET    = os.environ["S3_BUCKET"]
    S3_PREFIX    = os.environ.get("S3_PREFIX", "zendesk/crm/")
    STATE_KEY    = os.environ.get("STATE_KEY", "zendesk/crm/state.json")
    BASE_URL     = os.environ["ZENDESK_BASE_URL"].rstrip("/")  # e.g. https://your_subdomain.zendesk.com
    AUTH_MODE    = os.environ.get("AUTH_MODE", "token").lower()  # token|bearer
    EMAIL        = os.environ.get("ZENDESK_EMAIL", "")
    API_TOKEN    = os.environ.get("ZENDESK_API_TOKEN", "")
    BEARER       = os.environ.get("ZENDESK_BEARER_TOKEN", "")
    RESOURCES    = [r.strip() for r in os.environ.get("RESOURCES", "audit_logs,incremental_tickets").split(",") if r.strip()]
    MAX_PAGES    = int(os.environ.get("MAX_PAGES", "20"))
    LOOKBACK     = int(os.environ.get("LOOKBACK_SECONDS", "3600"))  # 1h default
    HTTP_TIMEOUT = int(os.environ.get("HTTP_TIMEOUT", "60"))
    HTTP_RETRIES = int(os.environ.get("HTTP_RETRIES", "3"))
    
    s3 = boto3.client("s3")
    
    def _headers() -> dict:
        if AUTH_MODE == "bearer" and BEARER:
            return {"Authorization": f"Bearer {BEARER}", "Accept": "application/json"}
        if AUTH_MODE == "token" and EMAIL and API_TOKEN:
            token = base64.b64encode(f"{EMAIL}/token:{API_TOKEN}".encode()).decode()
            return {"Authorization": f"Basic {token}", "Accept": "application/json"}
        raise RuntimeError("Invalid auth settings: provide token (EMAIL + API_TOKEN) or BEARER")
    
    def _get_state() -> dict:
        try:
            obj = s3.get_object(Bucket=S3_BUCKET, Key=STATE_KEY)
            b = obj["Body"].read()
            return json.loads(b) if b else {"audit_logs": {}, "incremental_tickets": {}}
        except Exception:
            return {"audit_logs": {}, "incremental_tickets": {}}
    
    def _put_state(st: dict) -> None:
        s3.put_object(
            Bucket=S3_BUCKET, Key=STATE_KEY,
            Body=json.dumps(st, separators=(",", ":")).encode("utf-8"),
            ContentType="application/json",
        )
    
    def _http_get_json(url: str) -> dict:
        attempt = 0
        while True:
            try:
                req = Request(url, method="GET")
                for k, v in _headers().items():
                    req.add_header(k, v)
                with urlopen(req, timeout=HTTP_TIMEOUT) as r:
                    return json.loads(r.read().decode("utf-8"))
            except HTTPError as e:
                if e.code in (429, 500, 502, 503, 504) and attempt < HTTP_RETRIES:
                    ra = 1 + attempt
                    try:
                        ra = int(e.headers.get("Retry-After", ra))
                    except Exception:
                        pass
                    time.sleep(max(1, ra))
                    attempt += 1
                    continue
                raise
            except URLError:
                if attempt < HTTP_RETRIES:
                    time.sleep(1 + attempt)
                    attempt += 1
                    continue
                raise
    
    def _put_page(payload: dict, resource: str) -> str:
        ts = time.gmtime()
        key = f"{S3_PREFIX}/{time.strftime('%Y/%m/%d/%H%M%S', ts)}-zendesk-{resource}.json"
        s3.put_object(
            Bucket=S3_BUCKET, Key=key,
            Body=json.dumps(payload, separators=(",", ":")).encode("utf-8"),
            ContentType="application/json",
        )
        return key
    
    def fetch_audit_logs(state: dict):
        """GET /api/v2/audit_logs.json with pagination via `next_page` (Zendesk)."""
        next_url = state.get("next_url") or f"{BASE_URL}/api/v2/audit_logs.json?page=1"
        pages = 0
        written = 0
        last_next = None
        while pages < MAX_PAGES and next_url:
            data = _http_get_json(next_url)
            _put_page(data, "audit_logs")
            written += len(data.get("audit_logs", []))
            last_next = data.get("next_page")
            next_url = last_next
            pages += 1
        return {"resource": "audit_logs", "pages": pages, "written": written, "next_url": last_next}
    
    def fetch_incremental_tickets(state: dict):
        """Cursor-based incremental export: /api/v2/incremental/tickets/cursor.json (pagination via `links.next`)."""
        next_link = state.get("next")
        if not next_link:
            start = int(time.time()) - LOOKBACK
            next_link = f"{BASE_URL}/api/v2/incremental/tickets/cursor.json?start_time={start}"
        pages = 0
        written = 0
        last_next = None
        while pages < MAX_PAGES and next_link:
            data = _http_get_json(next_link)
            _put_page(data, "incremental_tickets")
            written += len(data.get("tickets", []))
            links = data.get("links") or {}
            next_link = links.get("next")
            last_next = next_link
            pages += 1
        return {"resource": "incremental_tickets", "pages": pages, "written": written, "next": last_next}
    
    def lambda_handler(event=None, context=None):
        state = _get_state()
        summary = []
    
        if "audit_logs" in RESOURCES:
            res = fetch_audit_logs(state.get("audit_logs", {}))
            state["audit_logs"] = {"next_url": res.get("next_url")}
            summary.append(res)
    
        if "incremental_tickets" in RESOURCES:
            res = fetch_incremental_tickets(state.get("incremental_tickets", {}))
            state["incremental_tickets"] = {"next": res.get("next")}
            summary.append(res)
    
        _put_state(state)
        return {"ok": True, "summary": summary}
    
    if __name__ == "__main__":
        print(lambda_handler())
    
  5. Rufen Sie Konfiguration > Umgebungsvariablen auf.

  6. Klicken Sie auf Bearbeiten> Neue Umgebungsvariable hinzufügen.

  7. Geben Sie die in der folgenden Tabelle aufgeführten Umgebungsvariablen ein und ersetzen Sie die Beispielwerte durch Ihre Werte.

    Umgebungsvariablen

    Schlüssel Beispielwert
    S3_BUCKET zendesk-crm-logs
    S3_PREFIX zendesk/crm/
    STATE_KEY zendesk/crm/state.json
    ZENDESK_BASE_URL https://your_subdomain.zendesk.com
    AUTH_MODE token
    ZENDESK_EMAIL analyst@example.com
    ZENDESK_API_TOKEN <api_token>
    ZENDESK_BEARER_TOKEN <leave empty unless using OAuth bearer>
    RESOURCES audit_logs,incremental_tickets
    MAX_PAGES 20
    LOOKBACK_SECONDS 3600
    HTTP_TIMEOUT 60
  8. Bleiben Sie nach dem Erstellen der Funktion auf der zugehörigen Seite oder öffnen Sie Lambda > Funktionen > Ihre Funktion.

  9. Wählen Sie den Tab Konfiguration aus.

  10. Klicken Sie im Bereich Allgemeine Konfiguration auf Bearbeiten.

  11. Ändern Sie Zeitlimit in 5 Minuten (300 Sekunden) und klicken Sie auf Speichern.

EventBridge-Zeitplan erstellen

  1. Gehen Sie zu Amazon EventBridge > Scheduler > Create schedule (Amazon EventBridge > Scheduler > Zeitplan erstellen).
  2. Geben Sie die folgenden Konfigurationsdetails an:
    • Wiederkehrender Zeitplan: Preis (1 hour).
    • Ziel: Ihre Lambda-Funktion zendesk_crm_to_s3.
    • Name: zendesk_crm_to_s3-1h.
  3. Klicken Sie auf Zeitplan erstellen.

(Optional) IAM-Nutzer mit Lesezugriff und Schlüssel für Google SecOps erstellen

  1. Rufen Sie die AWS-Konsole > IAM > Nutzer > Nutzer hinzufügen auf.
  2. Klicken Sie auf Add users (Nutzer hinzufügen).
  3. Geben Sie die folgenden Konfigurationsdetails an:
    • Nutzer: Geben Sie secops-reader ein.
    • Zugriffstyp: Wählen Sie Zugriffsschlüssel – programmatischer Zugriff aus.
  4. Klicken Sie auf Nutzer erstellen.
  5. Minimale Leseberechtigung (benutzerdefiniert) anhängen: Nutzer > secops-reader > Berechtigungen > Berechtigungen hinzufügen > Richtlinien direkt anhängen > Richtlinie erstellen.
  6. JSON:

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

  8. Klicken Sie auf Richtlinie erstellen> suchen/auswählen> Weiter> Berechtigungen hinzufügen.

  9. Erstellen Sie einen Zugriffsschlüssel für secops-reader: Sicherheitsanmeldedaten > Zugriffsschlüssel.

  10. Klicken Sie auf Zugriffsschlüssel erstellen.

  11. Laden Sie die Datei .CSV herunter. Sie fügen diese Werte in den Feed ein.

Feed in Google SecOps konfigurieren, um Zendesk CRM-Logs aufzunehmen

  1. Rufen Sie die SIEM-Einstellungen > Feeds auf.
  2. Klicken Sie auf + Neuen Feed hinzufügen.
  3. Geben Sie im Feld Feedname einen Namen für den Feed ein, z. B. Zendesk CRM logs.
  4. Wählen Sie Amazon S3 V2 als Quelltyp aus.
  5. Wählen Sie Zendesk CRM als Logtyp aus.
  6. Klicken Sie auf Weiter.
  7. Geben Sie Werte für die folgenden Eingabeparameter an:
    • S3-URI: s3://zendesk-crm-logs/zendesk/crm/
    • Optionen zum Löschen der Quelle: Wählen Sie die gewünschte Option zum Löschen aus.
    • Maximales Dateialter: Dateien einschließen, die in den letzten Tagen geändert wurden. Der Standardwert ist 180 Tage.
    • Zugriffsschlüssel-ID: Nutzerzugriffsschlüssel mit Zugriff auf den S3-Bucket.
    • Geheimer Zugriffsschlüssel: Der geheime Schlüssel des Nutzers mit Zugriff auf den S3-Bucket.
    • Asset-Namespace: Der Asset-Namespace.
    • Aufnahmelabels: Das Label, das auf die Ereignisse aus diesem Feed angewendet wird.
  8. Klicken Sie auf Weiter.
  9. Prüfen Sie die neue Feedkonfiguration auf dem Bildschirm Abschließen und klicken Sie dann auf Senden.

Benötigen Sie weitere Hilfe? Antworten von Community-Mitgliedern und Google SecOps-Experten erhalten