Slack-Audit-Logs erfassen

Unterstützt in:

In diesem Dokument wird beschrieben, wie Sie Slack-Audit-Logs über Amazon S3 in Google Security Operations aufnehmen. Der Parser normalisiert zuerst boolesche Werte und löscht vordefinierte Felder. Anschließend wird das Feld „message“ als JSON geparst. Nicht-JSON-Nachrichten werden verworfen. Je nach Vorhandensein bestimmter Felder (date_create und user_id) wendet der Parser unterschiedliche Logik an, um Rohlogfelder dem UDM zuzuordnen, einschließlich Metadaten, Prinzipal, Netzwerk, Ziel und Informationen zu, und erstellt ein Sicherheitsergebnis.

Hinweise

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

  • Google SecOps-Instanz
  • Privilegierter Zugriff auf den Slack Enterprise Grid-Mandanten und die Admin-Konsole
  • Privilegierter Zugriff auf AWS (S3, IAM, Lambda, EventBridge)

Slack-Voraussetzungen erfassen (App-ID, OAuth-Token, Organisations-ID)

  1. Melden Sie sich in der Slack-Admin-Konsole an.
  2. Rufen Sie https://api.slack.com/apps auf und klicken Sie auf Create New App > From scratch (Neue App erstellen > Von Grund auf).
  3. Geben Sie einen eindeutigen App-Namen ein und wählen Sie Ihren Slack-Workspace aus.
  4. Klicken Sie auf Anwendung erstellen.
  5. Rufen Sie in der linken Seitenleiste OAuth & Permissions (OAuth und Berechtigungen) auf.
  6. Gehen Sie zum Abschnitt Bereiche und fügen Sie den folgenden Nutzer-Token-Bereich hinzu: auditlogs:read.
  7. Klicken Sie auf Im Workspace installieren> Zulassen.
  8. Rufen Sie nach der Installation Apps auf Organisationsebene auf.
  9. Klicken Sie auf Für Organisation installieren.
  10. Autorisieren Sie die App mit einem Organisationsinhaber-/Administratorkonto.
  11. Kopieren Sie das User OAuth Token, das mit xoxp- beginnt, und speichern Sie es sicher. Dies ist Ihr SLACK_AUDIT_TOKEN.
  12. Notieren Sie sich die Organisations-ID, die Sie in der Slack-Admin-Konsole unter Einstellungen & Berechtigungen > Organisationseinstellungen finden.

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

  1. Erstellen Sie einen Amazon S3-Bucket. Folgen Sie dazu dieser Anleitung: Bucket erstellen.
  2. Speichern Sie den Namen und die Region des Buckets zur späteren Verwendung (z. B. slack-audit-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 als Anwendungsfall Drittanbieterdienst 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) zur späteren 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 und wählen Sie sie aus.
  18. Klicken Sie auf Weiter.
  19. Klicken Sie auf Berechtigungen hinzufügen.

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

  1. Rufen Sie in der AWS-Konsole IAM > Richtlinien > Richtlinie erstellen > Tab „JSON“ auf.
  2. Geben Sie die folgende Richtlinie ein:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowPutObjects",
          "Effect": "Allow",
          "Action": "s3:PutObject",
          "Resource": "arn:aws:s3:::slack-audit-logs/*"
        },
        {
          "Sid": "AllowGetStateObject",
          "Effect": "Allow",
          "Action": "s3:GetObject",
          "Resource": "arn:aws:s3:::slack-audit-logs/slack/audit/state.json"
        }
      ]
    }
    
    • Ersetzen Sie slack-audit-logs, wenn Sie einen anderen Bucket-Namen eingegeben haben.
  3. Klicken Sie auf Weiter > Richtlinie erstellen.

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

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

  6. Geben Sie der Rolle den Namen SlackAuditToS3Role 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 slack_audit_to_s3
Laufzeit Python 3.13
Architektur x86_64
Ausführungsrolle SlackAuditToS3Role
  1. Nachdem die Funktion erstellt wurde, öffnen Sie den Tab Code, löschen Sie den Stub und geben Sie Folgendes ein (slack_audit_to_s3.py):

    #!/usr/bin/env python3
    # Lambda: Pull Slack Audit Logs (Enterprise Grid) to S3 (no transform)
    
    import os, json, time, urllib.parse
    from urllib.request import Request, urlopen
    from urllib.error import HTTPError, URLError
    import boto3
    
    BASE_URL = "https://api.slack.com/audit/v1/logs"
    
    TOKEN        = os.environ["SLACK_AUDIT_TOKEN"]  # org-level user token with auditlogs:read
    BUCKET       = os.environ["S3_BUCKET"]
    PREFIX       = os.environ.get("S3_PREFIX", "slack/audit/")
    STATE_KEY    = os.environ.get("STATE_KEY", "slack/audit/state.json")
    LIMIT        = int(os.environ.get("LIMIT", "200"))             # Slack recommends <= 200
    MAX_PAGES    = int(os.environ.get("MAX_PAGES", "20"))
    LOOKBACK_SEC = int(os.environ.get("LOOKBACK_SECONDS", "3600")) # First-run window
    HTTP_TIMEOUT = int(os.environ.get("HTTP_TIMEOUT", "60"))
    HTTP_RETRIES = int(os.environ.get("HTTP_RETRIES", "3"))
    RETRY_AFTER_DEFAULT = int(os.environ.get("RETRY_AFTER_DEFAULT", "2"))
    # Optional server-side filters (comma-separated "action" values), empty means no filter
    ACTIONS      = os.environ.get("ACTIONS", "").strip()
    
    s3 = boto3.client("s3")
    
    def _get_state() -> dict:
        try:
            obj = s3.get_object(Bucket=BUCKET, Key=STATE_KEY)
            st = json.loads(obj["Body"].read() or b"{}")
            return {"cursor": st.get("cursor")}
        except Exception:
            return {"cursor": None}
    
    def _put_state(state: dict) -> None:
        body = json.dumps(state, separators=(",", ":")).encode("utf-8")
        s3.put_object(Bucket=BUCKET, Key=STATE_KEY, Body=body, ContentType="application/json")
    
    def _http_get(params: dict) -> dict:
        qs  = urllib.parse.urlencode(params, doseq=True)
        url = f"{BASE_URL}?{qs}" if qs else BASE_URL
        req = Request(url, method="GET")
        req.add_header("Authorization", f"Bearer {TOKEN}")
        req.add_header("Accept", "application/json")
    
        attempt = 0
        while True:
            try:
                with urlopen(req, timeout=HTTP_TIMEOUT) as r:
                    return json.loads(r.read().decode("utf-8"))
            except HTTPError as e:
                # Respect Retry-After on 429/5xx
                if e.code in (429, 500, 502, 503, 504) and attempt < HTTP_RETRIES:
                    retry_after = 0
                    try:
                        retry_after = int(e.headers.get("Retry-After", RETRY_AFTER_DEFAULT))
                    except Exception:
                        retry_after = RETRY_AFTER_DEFAULT
                    time.sleep(max(1, retry_after))
                    attempt += 1
                    continue
                # Re-raise other HTTP errors
                raise
            except URLError:
                if attempt < HTTP_RETRIES:
                    time.sleep(RETRY_AFTER_DEFAULT)
                    attempt += 1
                    continue
                raise
    
    def _write_page(payload: dict, page_idx: int) -> str:
        ts  = time.strftime("%Y/%m/%d/%H%M%S", time.gmtime())
        key = f"{PREFIX}/{ts}-slack-audit-p{page_idx:05d}.json"
        body = json.dumps(payload, separators=(",", ":")).encode("utf-8")
        s3.put_object(Bucket=BUCKET, Key=key, Body=body, ContentType="application/json")
        return key
    
    def lambda_handler(event=None, context=None):
        state  = _get_state()
        cursor = state.get("cursor")
    
        params = {"limit": LIMIT}
        if ACTIONS:
            params["action"] = [a.strip() for a in ACTIONS.split(",") if a.strip()]
        if cursor:
            params["cursor"] = cursor
        else:
            # First run (or reset): fetch a recent window by time
            params["oldest"] = int(time.time()) - LOOKBACK_SEC
    
        pages = 0
        total = 0
        last_cursor = None
    
        while pages < MAX_PAGES:
            data = _http_get(params)
            _write_page(data, pages)
    
            entries = data.get("entries") or []
            total += len(entries)
    
            # Cursor for next page
            meta = data.get("response_metadata") or {}
            next_cursor = meta.get("next_cursor") or data.get("next_cursor")
            if next_cursor:
                params = {"limit": LIMIT, "cursor": next_cursor}
                if ACTIONS:
                    params["action"] = [a.strip() for a in ACTIONS.split(",") if a.strip()]
                last_cursor = next_cursor
                pages += 1
                continue
            break
    
        if last_cursor:
            _put_state({"cursor": last_cursor})
    
        return {"ok": True, "pages": pages + (1 if total or last_cursor else 0), "entries": total, "cursor": last_cursor}
    
    if __name__ == "__main__":
        print(lambda_handler())
    
  2. Klicken Sie auf Konfiguration> Umgebungsvariablen> Bearbeiten> Neue Umgebungsvariable hinzufügen.

  3. Geben Sie die folgenden Umgebungsvariablen ein und ersetzen Sie die Platzhalter durch Ihre Werte:

    Schlüssel Beispielwert
    S3_BUCKET slack-audit-logs
    S3_PREFIX slack/audit/
    STATE_KEY slack/audit/state.json
    SLACK_AUDIT_TOKEN xoxp-*** (Nutzer-Token auf Organisationsebene mit auditlogs:read)
    LIMIT 200
    MAX_PAGES 20
    LOOKBACK_SECONDS 3600
    HTTP_TIMEOUT 60
    HTTP_RETRIES 3
    RETRY_AFTER_DEFAULT 2
    ACTIONS (optional, CSV) user_login,app_installed
  4. Bleiben Sie nach dem Erstellen der Funktion auf der zugehörigen Seite oder öffnen Sie Lambda > Funktionen > Ihre Funktion.

  5. Wählen Sie den Tab Konfiguration aus.

  6. Klicken Sie im Bereich Allgemeine Konfiguration auf Bearbeiten.

  7. Ä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 slack_audit_to_s3.
    • Name: slack-audit-1h.
  3. Klicken Sie auf Zeitplan erstellen.

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

  1. Rufen Sie in der 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: secops-reader.
    • Zugriffstyp: Zugriffsschlüssel – programmatischer Zugriff.
  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. Geben Sie im JSON-Editor die folgende Richtlinie ein:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": ["s3:GetObject"],
          "Resource": "arn:aws:s3:::slack-audit-logs/*"
        },
        {
          "Effect": "Allow",
          "Action": ["s3:ListBucket"],
          "Resource": "arn:aws:s3:::slack-audit-logs"
        }
      ]
    }
    
  7. Legen Sie secops-reader-policy als Name fest.

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

  9. Rufen Sie Sicherheitsanmeldedaten > Zugriffsschlüssel > Zugriffsschlüssel erstellen auf.

  10. Laden Sie die CSV herunter (diese Werte werden in den Feed eingegeben).

Feed in Google SecOps konfigurieren, um Slack-Audit-Logs aufzunehmen

  1. Rufen Sie die SIEM-Einstellungen > Feeds auf.
  2. Klicken Sie auf + Neuen Feed hinzufügen.
  3. Geben Sie im Feld Feed name (Feedname) einen Namen für den Feed ein, z. B. Slack Audit Logs.
  4. Wählen Sie Amazon S3 V2 als Quelltyp aus.
  5. Wählen Sie Slack Audit als Logtyp aus.
  6. Klicken Sie auf Weiter.
  7. Geben Sie Werte für die folgenden Eingabeparameter an:
    • S3-URI: s3://slack-audit-logs/slack/audit/
    • Optionen zum Löschen von Quellen: 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: Zugriffsschlüssel des Nutzers mit Zugriff auf den S3-Bucket.
    • Secret Access Key (Geheimer Zugriffsschlüssel): Geheimer Nutzersicherheitsschlüssel 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.

UDM-Zuordnungstabelle

Logfeld UDM-Zuordnung Logik
action metadata.product_event_type Direkt aus dem Feld action im Rohlog zugeordnet.
actor.type principal.labels.value Direkt aus dem Feld actor.type zugeordnet, mit dem Schlüssel actor.type.
actor.user.email principal.user.email_addresses Direkt aus dem Feld actor.user.email zugeordnet.
actor.user.id principal.user.product_object_id Direkt aus dem Feld actor.user.id zugeordnet.
actor.user.id principal.user.userid Direkt aus dem Feld actor.user.id zugeordnet.
actor.user.name principal.user.user_display_name Direkt aus dem Feld actor.user.name zugeordnet.
actor.user.team principal.user.group_identifiers Direkt aus dem Feld actor.user.team zugeordnet.
context.ip_address principal.ip Direkt aus dem Feld context.ip_address zugeordnet.
context.location.domain about.resource.attribute.labels.value Direkt aus dem Feld context.location.domain zugeordnet, mit dem Schlüssel context.location.domain.
context.location.id about.resource.id Direkt aus dem Feld context.location.id zugeordnet.
context.location.name about.resource.name Direkt aus dem Feld context.location.name zugeordnet.
context.location.name about.resource.attribute.labels.value Direkt aus dem Feld context.location.name zugeordnet, mit dem Schlüssel context.location.name.
context.location.type about.resource.resource_subtype Direkt aus dem Feld context.location.type zugeordnet.
context.session_id network.session_id Direkt aus dem Feld context.session_id zugeordnet.
context.ua network.http.user_agent Direkt aus dem Feld context.ua zugeordnet.
context.ua network.http.parsed_user_agent Geprüfte User-Agent-Informationen, die aus dem Feld context.ua mit dem Filter parseduseragent abgeleitet wurden.
country principal.location.country_or_region Direkt aus dem Feld country zugeordnet.
date_create metadata.event_timestamp.seconds Der Epoch-Zeitstempel aus dem Feld date_create wird in ein Zeitstempelobjekt konvertiert.
details.inviter.email target.user.email_addresses Direkt aus dem Feld details.inviter.email zugeordnet.
details.inviter.id target.user.product_object_id Direkt aus dem Feld details.inviter.id zugeordnet.
details.inviter.name target.user.user_display_name Direkt aus dem Feld details.inviter.name zugeordnet.
details.inviter.team target.user.group_identifiers Direkt aus dem Feld details.inviter.team zugeordnet.
details.reason security_result.description Direkt aus dem Feld details.reason zugeordnet oder, falls es sich um ein Array handelt, durch Kommas verkettet.
details.type about.resource.attribute.labels.value Direkt aus dem Feld details.type zugeordnet, mit dem Schlüssel details.type.
details.type security_result.summary Direkt aus dem Feld details.type zugeordnet.
entity.app.id target.resource.id Direkt aus dem Feld entity.app.id zugeordnet.
entity.app.name target.resource.name Direkt aus dem Feld entity.app.name zugeordnet.
entity.channel.id target.resource.id Direkt aus dem Feld entity.channel.id zugeordnet.
entity.channel.name target.resource.name Direkt aus dem Feld entity.channel.name zugeordnet.
entity.channel.privacy target.resource.attribute.labels.value Direkt aus dem Feld entity.channel.privacy zugeordnet, mit dem Schlüssel entity.channel.privacy.
entity.file.filetype target.resource.attribute.labels.value Direkt aus dem Feld entity.file.filetype zugeordnet, mit dem Schlüssel entity.file.filetype.
entity.file.id target.resource.id Direkt aus dem Feld entity.file.id zugeordnet.
entity.file.name target.resource.name Direkt aus dem Feld entity.file.name zugeordnet.
entity.file.title target.resource.attribute.labels.value Direkt aus dem Feld entity.file.title zugeordnet, mit dem Schlüssel entity.file.title.
entity.huddle.date_end about.resource.attribute.labels.value Direkt aus dem Feld entity.huddle.date_end zugeordnet, mit dem Schlüssel entity.huddle.date_end.
entity.huddle.date_start about.resource.attribute.labels.value Direkt aus dem Feld entity.huddle.date_start zugeordnet, mit dem Schlüssel entity.huddle.date_start.
entity.huddle.id about.resource.attribute.labels.value Direkt aus dem Feld entity.huddle.id zugeordnet, mit dem Schlüssel entity.huddle.id.
entity.huddle.participants.0 about.resource.attribute.labels.value Direkt aus dem Feld entity.huddle.participants.0 zugeordnet, mit dem Schlüssel entity.huddle.participants.0.
entity.huddle.participants.1 about.resource.attribute.labels.value Direkt aus dem Feld entity.huddle.participants.1 zugeordnet, mit dem Schlüssel entity.huddle.participants.1.
entity.type target.resource.resource_subtype Direkt aus dem Feld entity.type zugeordnet.
entity.user.email target.user.email_addresses Direkt aus dem Feld entity.user.email zugeordnet.
entity.user.id target.user.product_object_id Direkt aus dem Feld entity.user.id zugeordnet.
entity.user.name target.user.user_display_name Direkt aus dem Feld entity.user.name zugeordnet.
entity.user.team target.user.group_identifiers Direkt aus dem Feld entity.user.team zugeordnet.
entity.workflow.id target.resource.id Direkt aus dem Feld entity.workflow.id zugeordnet.
entity.workflow.name target.resource.name Direkt aus dem Feld entity.workflow.name zugeordnet.
id metadata.product_log_id Direkt aus dem Feld id zugeordnet.
ip principal.ip Direkt aus dem Feld ip zugeordnet. Wird durch Logik basierend auf dem Feld action bestimmt. Der Standardwert ist USER_COMMUNICATION. Er ändert sich jedoch in andere Werte wie USER_CREATION, USER_LOGIN, USER_LOGOUT, USER_RESOURCE_ACCESS, USER_RESOURCE_UPDATE_PERMISSIONS oder USER_CHANGE_PERMISSIONS, je nach Wert von action. Fest codiert auf „SLACK_AUDIT“. Auf „Enterprise Grid“ festlegen, wenn date_create vorhanden ist, andernfalls auf „Audit-Logs“, wenn user_id vorhanden ist. Fest codiert auf „Slack“. Fest codiert auf „REMOTE“. Auf „SSO“ festgelegt, wenn action „user_login“ oder „user_logout“ enthält. Andernfalls auf „MACHINE“ setzen. In den bereitgestellten Beispielen nicht zugeordnet. Der Standardwert ist „ALLOW“, wird aber auf „BLOCK“ gesetzt, wenn action „user_login_failed“ ist. Auf „Slack“ setzen, wenn date_create vorhanden ist, andernfalls auf „SLACK“, wenn user_id vorhanden ist.
user_agent network.http.user_agent Direkt aus dem Feld user_agent zugeordnet.
user_id principal.user.product_object_id Direkt aus dem Feld user_id zugeordnet.
username principal.user.product_object_id Direkt aus dem Feld username zugeordnet.

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