Harness IO-Audit-Logs erfassen

Unterstützt in:

In diesem Dokument wird beschrieben, wie Sie Harness IO-Audit-Logs 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 Harness mit Berechtigungen für:
    • API-Schlüssel erstellen
    • Auf Audit-Logs zugreifen
    • Kontoeinstellungen ansehen
  • Privilegierter Zugriff auf AWS (S3, IAM, Lambda, EventBridge).

Harness-API-Anmeldedaten erfassen

API-Schlüssel in Harness erstellen

  1. Melden Sie sich auf der Harness-Plattform an.
  2. Klicken Sie auf Ihr Nutzerprofil.
  3. Rufen Sie Meine API-Schlüssel auf.
  4. Klicken Sie auf + API-Schlüssel.
  5. Geben Sie die folgenden Konfigurationsdetails an:
    • Name: Geben Sie einen aussagekräftigen Namen ein, z. B. Google SecOps Integration.
    • Beschreibung: Optionale Beschreibung.
  6. Klicken Sie auf Speichern.
  7. Klicken Sie auf + Token, um ein neues Token zu erstellen.
  8. Geben Sie die folgenden Konfigurationsdetails an:
    • Name: Geben Sie Chronicle Feed Token ein.
    • Ablauf festlegen: Wählen Sie eine geeignete Ablaufzeit oder Kein Ablauf (für die Produktion) aus.
  9. Klicken Sie auf Generate Token (Token generieren).
  10. Kopieren und speichern Sie den Tokenwert sicher. Dieses Token wird als Header-Wert für x-api-key verwendet.

Harness-Konto-ID abrufen

  1. Notieren Sie sich in der Harness Platform die Account ID (Konto-ID) aus der URL.
    • Beispiel-URL: https://app.harness.io/ng/account/YOUR_ACCOUNT_ID/...
    • Der Teil YOUR_ACCOUNT_ID ist Ihre Konto-ID.
  2. Alternativ können Sie auch unter Kontoeinstellungen > Übersicht Ihre Konto-ID aufrufen.
  3. Kopieren und speichern Sie die Konto-ID zur Verwendung in der Lambda-Funktion.

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. harness-io-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 Lambda-S3-Uploads konfigurieren

  1. Rufen Sie in der AWS-Konsole IAM > Richtlinien > Richtlinie erstellen > Tab „JSON“ auf.
  2. Kopieren Sie die folgende Richtlinie und fügen Sie sie ein:

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

  4. Geben Sie der Richtlinie den Namen HarnessToS3Policy und klicken Sie auf Richtlinie erstellen.

  5. Klicken Sie auf IAM > Rollen > Rolle erstellen.

  6. Wählen Sie AWS-Dienst als Typ der vertrauenswürdigen Entität aus.

  7. Wählen Sie Lambda als Anwendungsfall aus.

  8. Klicken Sie auf Weiter.

  9. Suchen Sie nach den folgenden Richtlinien und wählen Sie sie aus:

    • HarnessToS3Policy (die Richtlinie, die Sie gerade erstellt haben)
    • AWSLambdaBasicExecutionRole (für CloudWatch Logs)
  10. Klicken Sie auf Weiter.

  11. Geben Sie der Rolle den Namen HarnessAuditLambdaRole 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 harness-audit-to-s3
    Laufzeit Python 3.13
    Architektur x86_64
    Ausführungsrolle HarnessAuditLambdaRole
  4. Klicken Sie auf Funktion erstellen.

  5. Öffnen Sie nach dem Erstellen der Funktion den Tab Code.

  6. Löschen Sie den Standard-Stub-Code und geben Sie den folgenden Lambda-Funktionscode ein:

    • Lambda-Funktionscode (harness_audit_to_s3.py)

      #!/usr/bin/env python3
      """
      Harness.io Audit Logs to S3 Lambda
      Fetches audit logs from Harness API and writes to S3 for Chronicle ingestion.
      """
      import os
      import json
      import time
      import uuid
      import logging
      import urllib.parse
      from datetime import datetime, timedelta, timezone
      from urllib.request import Request, urlopen
      from urllib.error import HTTPError, URLError
      import boto3
      
      # Configuration from Environment Variables
      API_BASE = os.environ.get("HARNESS_API_BASE", "https://app.harness.io").rstrip("/")
      ACCOUNT_ID = os.environ["HARNESS_ACCOUNT_ID"]
      API_KEY = os.environ["HARNESS_API_KEY"]
      BUCKET = os.environ["S3_BUCKET"]
      PREFIX = os.environ.get("S3_PREFIX", "harness/audit").strip("/")
      STATE_KEY = os.environ.get("STATE_KEY", "harness/audit/state.json")
      PAGE_SIZE = min(int(os.environ.get("PAGE_SIZE", "50")), 100)
      START_MINUTES_BACK = int(os.environ.get("START_MINUTES_BACK", "60"))
      
      # Optional filters (NEW)
      FILTER_MODULES = os.environ.get("FILTER_MODULES", "").split(",") if os.environ.get("FILTER_MODULES") else None
      FILTER_ACTIONS = os.environ.get("FILTER_ACTIONS", "").split(",") if os.environ.get("FILTER_ACTIONS") else None
      STATIC_FILTER = os.environ.get("STATIC_FILTER")  # e.g., "EXCLUDE_LOGIN_EVENTS"
      MAX_RETRIES = int(os.environ.get("MAX_RETRIES", "3"))
      
      # AWS clients
      s3 = boto3.client("s3")
      
      # HTTP headers for Harness API
      HDRS = {
          "x-api-key": API_KEY,
          "Content-Type": "application/json",
          "Accept": "application/json",
      }
      
      # Logging configuration
      logger = logging.getLogger()
      logger.setLevel(logging.INFO)
      
      # ============================================
      # State Management Functions
      # ============================================
      def _read_state():
          """Read checkpoint state from S3."""
          try:
              obj = s3.get_object(Bucket=BUCKET, Key=STATE_KEY)
              state = json.loads(obj["Body"].read())
      
              since_ms = state.get("since")
              page_token = state.get("pageToken")
      
              logger.info(f"State loaded: since={since_ms}, pageToken={page_token}")
              return since_ms, page_token
      
          except s3.exceptions.NoSuchKey:
              logger.info("No state file found, starting fresh collection")
              start_time = datetime.now(timezone.utc) - timedelta(minutes=START_MINUTES_BACK)
              since_ms = int(start_time.timestamp() * 1000)
              logger.info(f"Initial since timestamp: {since_ms} ({start_time.isoformat()})")
              return since_ms, None
      
          except Exception as e:
              logger.error(f"Error reading state: {e}")
              raise
      
      def _write_state(since_ms: int, page_token: str = None):
          """Write checkpoint state to S3."""
          state = {
              "since": since_ms,
              "pageToken": page_token,
              "lastRun": int(time.time() * 1000),
              "lastRunISO": datetime.now(timezone.utc).isoformat()
          }
      
          try:
              s3.put_object(
                  Bucket=BUCKET,
                  Key=STATE_KEY,
                  Body=json.dumps(state, indent=2).encode(),
                  ContentType="application/json"
              )
              logger.info(f"State saved: since={since_ms}, pageToken={page_token}")
          except Exception as e:
              logger.error(f"Error writing state: {e}")
              raise
      
      # ============================================
      # Harness API Functions
      # ============================================
      def _fetch_harness_audits(since_ms: int, page_token: str = None, retry_count: int = 0):
          """
          Fetch audit logs from Harness API with retry logic.
      
          API Endpoint: POST /audit/api/audits/listV2
          Documentation: https://apidocs.harness.io/audit/getauditeventlistv2
          """
          try:
              # Build URL with query parameters
              url = (
                  f"{API_BASE}/audit/api/audits/listV2"
                  f"?accountIdentifier={urllib.parse.quote(ACCOUNT_ID)}"
                  f"&pageSize={PAGE_SIZE}"
              )
      
              if page_token:
                  url += f"&pageToken={urllib.parse.quote(page_token)}"
      
              logger.info(f"Fetching from: {url[:100]}...")
      
              # Build request body with time filter and optional filters
              body_data = {
                  "startTime": since_ms,
                  "endTime": int(time.time() * 1000),
                  "filterType": "Audit" 
              }
      
              if FILTER_MODULES:
                  body_data["modules"] = [m.strip() for m in FILTER_MODULES if m.strip()]
                  logger.info(f"Applying module filter: {body_data['modules']}")
      
              if FILTER_ACTIONS:
                  body_data["actions"] = [a.strip() for a in FILTER_ACTIONS if a.strip()]
                  logger.info(f"Applying action filter: {body_data['actions']}")
      
              if STATIC_FILTER:
                  body_data["staticFilter"] = STATIC_FILTER
                  logger.info(f"Applying static filter: {STATIC_FILTER}")
      
              logger.debug(f"Request body: {json.dumps(body_data)}")
      
              # Make POST request
              req = Request(
                  url,
                  data=json.dumps(body_data).encode('utf-8'),
                  headers=HDRS,
                  method="POST"
              )
      
              resp = urlopen(req, timeout=30)
              resp_text = resp.read().decode('utf-8')
              resp_data = json.loads(resp_text)
      
              if "status" not in resp_data:
                  logger.warning(f"Response missing 'status' field: {resp_text[:200]}")
      
              # Check response status
              if resp_data.get("status") != "SUCCESS":
                  error_msg = resp_data.get("message", "Unknown error")
                  raise Exception(f"API returned status: {resp_data.get('status')} - {error_msg}")
      
              # Extract data from response structure
              data_obj = resp_data.get("data", {})
      
              if not data_obj:
                  logger.warning("Response 'data' object is empty or missing")
      
              events = data_obj.get("content", [])
              has_next = data_obj.get("hasNext", False)
              next_token = data_obj.get("pageToken")
      
              logger.info(f"API response: {len(events)} events, hasNext={has_next}, pageToken={next_token}")
      
              if not events and data_obj:
                  logger.info(f"Empty events but data present. Data keys: {list(data_obj.keys())}")
      
              return {
                  "events": events,
                  "hasNext": has_next,
                  "pageToken": next_token
              }
      
          except HTTPError as e:
              error_body = e.read().decode() if hasattr(e, 'read') else ''
      
              if e.code == 401:
                  logger.error("Authentication failed: Invalid API key")
                  raise Exception("Invalid Harness API key. Check HARNESS_API_KEY environment variable.")
      
              elif e.code == 403:
                  logger.error("Authorization failed: Insufficient permissions")
                  raise Exception("API key lacks required audit:read permissions")
      
              elif e.code == 429:
                  retry_after = int(e.headers.get("Retry-After", "60"))
                  logger.warning(f"Rate limit exceeded. Retry after {retry_after} seconds (attempt {retry_count + 1}/{MAX_RETRIES})")
      
                  if retry_count < MAX_RETRIES:
                      logger.info(f"Waiting {retry_after} seconds before retry...")
                      time.sleep(retry_after)
                      logger.info(f"Retrying request (attempt {retry_count + 2}/{MAX_RETRIES})")
                      return _fetch_harness_audits(since_ms, page_token, retry_count + 1)
                  else:
                      raise Exception(f"Max retries ({MAX_RETRIES}) exceeded for rate limiting")
      
              elif e.code == 400:
                  logger.error(f"Bad request: {error_body}")
                  raise Exception(f"Invalid request parameters: {error_body}")
      
              else:
                  logger.error(f"HTTP {e.code}: {e.reason} - {error_body}")
                  raise Exception(f"Harness API error {e.code}: {e.reason}")
      
          except URLError as e:
              logger.error(f"Network error: {e.reason}")
              raise Exception(f"Failed to connect to Harness API: {e.reason}")
      
          except json.JSONDecodeError as e:
              logger.error(f"Invalid JSON response: {e}")
              logger.error(f"Response text (first 500 chars): {resp_text[:500] if 'resp_text' in locals() else 'N/A'}")
              raise Exception("Harness API returned invalid JSON")
      
          except Exception as e:
              logger.error(f"Unexpected error in _fetch_harness_audits: {e}", exc_info=True)
              raise
      
      # ============================================
      # S3 Upload Functions
      # ============================================
      def _upload_to_s3(events: list) -> str:
          """
          Upload audit events to S3 in JSONL format.
          Each line is a complete JSON object (one event per line).
          """
          if not events:
              logger.info("No events to upload")
              return None
      
          try:
              # Create JSONL content (one JSON object per line)
              jsonl_lines = [json.dumps(event) for event in events]
              jsonl_content = "\n".join(jsonl_lines)
      
              # Generate S3 key with timestamp and UUID
              timestamp = datetime.now(timezone.utc)
              key = (
                  f"{PREFIX}/"
                  f"{timestamp:%Y/%m/%d}/"
                  f"harness-audit-{timestamp:%Y%m%d-%H%M%S}-{uuid.uuid4()}.jsonl"
              )
      
              # Upload to S3
              s3.put_object(
                  Bucket=BUCKET,
                  Key=key,
                  Body=jsonl_content.encode('utf-8'),
                  ContentType="application/x-ndjson",
                  Metadata={
                      "event-count": str(len(events)),
                      "source": "harness-audit-lambda",
                      "collection-time": timestamp.isoformat()
                  }
              )
      
              logger.info(f"Uploaded {len(events)} events to s3://{BUCKET}/{key}")
              return key
      
          except Exception as e:
              logger.error(f"Error uploading to S3: {e}", exc_info=True)
              raise
      
      # ============================================
      # Main Orchestration Function
      # ============================================
      def fetch_and_store():
          """
          Main function to fetch audit logs from Harness and store in S3.
          Handles pagination and state management.
          """
          logger.info("=== Harness Audit Collection Started ===")
          logger.info(f"Configuration: API_BASE={API_BASE}, ACCOUNT_ID={ACCOUNT_ID[:8]}..., PAGE_SIZE={PAGE_SIZE}")
      
          if FILTER_MODULES:
              logger.info(f"Module filter enabled: {FILTER_MODULES}")
          if FILTER_ACTIONS:
              logger.info(f"Action filter enabled: {FILTER_ACTIONS}")
          if STATIC_FILTER:
              logger.info(f"Static filter enabled: {STATIC_FILTER}")
      
          try:
              # Step 1: Read checkpoint state
              since_ms, page_token = _read_state()
      
              if page_token:
                  logger.info(f"Resuming pagination from saved pageToken")
              else:
                  since_dt = datetime.fromtimestamp(since_ms / 1000, tz=timezone.utc)
                  logger.info(f"Starting new collection from: {since_dt.isoformat()}")
      
              # Step 2: Collect all events with pagination
              all_events = []
              current_page_token = page_token
              page_count = 0
              max_pages = 100  # Safety limit
              has_next = True
      
              while has_next and page_count < max_pages:
                  page_count += 1
                  logger.info(f"--- Fetching page {page_count} ---")
      
                  # Fetch one page of results
                  result = _fetch_harness_audits(since_ms, current_page_token)
      
                  # Extract events
                  events = result.get("events", [])
                  all_events.extend(events)
      
                  logger.info(f"Page {page_count}: {len(events)} events (total: {len(all_events)})")
      
                  # Check pagination status
                  has_next = result.get("hasNext", False)
                  current_page_token = result.get("pageToken")
      
                  if not has_next:
                      logger.info("Pagination complete (hasNext=False)")
                      break
      
                  if not current_page_token:
                      logger.warning("hasNext=True but no pageToken, stopping pagination")
                      break
      
                  # Small delay between pages to avoid rate limiting
                  time.sleep(0.5)
      
              if page_count >= max_pages:
                  logger.warning(f"Reached max pages limit ({max_pages}), stopping")
      
              # Step 3: Upload collected events to S3
              if all_events:
                  s3_key = _upload_to_s3(all_events)
                  logger.info(f"Successfully uploaded {len(all_events)} total events")
              else:
                  logger.info("No new events to upload")
                  s3_key = None
      
              # Step 4: Update checkpoint state
              if not has_next:
                  # Pagination complete - update since to current time for next run
                  new_since = int(time.time() * 1000)
                  _write_state(new_since, None)
                  logger.info(f"Pagination complete, state updated with new since={new_since}")
              else:
                  # Pagination incomplete - save pageToken for continuation
                  _write_state(since_ms, current_page_token)
                  logger.info(f"Pagination incomplete, saved pageToken for next run")
      
              # Step 5: Return result
              result = {
                  "statusCode": 200,
                  "message": "Success",
                  "eventsCollected": len(all_events),
                  "pagesProcessed": page_count,
                  "paginationComplete": not has_next,
                  "s3Key": s3_key,
                  "filters": {
                      "modules": FILTER_MODULES,
                      "actions": FILTER_ACTIONS,
                      "staticFilter": STATIC_FILTER
                  }
              }
      
              logger.info(f"Collection completed: {json.dumps(result)}")
              return result
      
          except Exception as e:
              logger.error(f"Collection failed: {e}", exc_info=True)
      
              result = {
                  "statusCode": 500,
                  "message": "Error",
                  "error": str(e),
                  "errorType": type(e).__name__
              }
      
              return result
      
          finally:
              logger.info("=== Harness Audit Collection Finished ===")
      
      # ============================================
      # Lambda Handler
      # ============================================
      def lambda_handler(event, context):
          """AWS Lambda handler function."""
          return fetch_and_store()
      
      # ============================================
      # Local Testing
      # ============================================
      if __name__ == "__main__":
          # For local testing
          result = lambda_handler(None, None)
          print(json.dumps(result, indent=2))
      

  7. Klicken Sie auf Bereitstellen, um den Funktionscode zu speichern.

Lambda-Umgebungsvariablen konfigurieren

  1. Wählen Sie auf der Seite der Lambda-Funktion den Tab Konfiguration aus.
  2. Klicken Sie in der linken Seitenleiste auf Umgebungsvariablen.
  3. Klicken Sie auf Bearbeiten.
  4. Klicken Sie für jede der folgenden Variablen auf Umgebungsvariable hinzufügen:

    Erforderliche Umgebungsvariablen:

    Schlüssel Wert Beschreibung
    HARNESS_ACCOUNT_ID Ihre Harness-Konto-ID Konto-ID von Harness
    HARNESS_API_KEY Ihr API-Schlüssel-Token Token mit der Berechtigung „audit:read“
    S3_BUCKET harness-io-logs S3-Bucket-Name
    S3_PREFIX harness/audit Präfix für S3-Objekte
    STATE_KEY harness/audit/state.json Statusdateipfad in S3

    Optionale Umgebungsvariablen:

    Schlüssel Standardwert Beschreibung
    HARNESS_API_BASE https://app.harness.io Harness API-Basis-URL
    PAGE_SIZE 50 Ereignisse pro Seite (max. 100)
    START_MINUTES_BACK 60 Erster Rückblickzeitraum in Minuten
    FILTER_MODULES Keine Durch Kommas getrennte Module (z.B. CD,CI,CE)
    FILTER_ACTIONS Keine Durch Kommas getrennte Aktionen (z.B. CREATE,UPDATE,DELETE)
    STATIC_FILTER Keine Vordefinierter Filter: EXCLUDE_LOGIN_EVENTS oder EXCLUDE_SYSTEM_EVENTS
    MAX_RETRIES 3 Maximale Anzahl von Wiederholungsversuchen für die Ratenbegrenzung
  5. Klicken Sie auf Speichern.

Lambda-Zeitlimit und -Speicher konfigurieren

  1. Wählen Sie auf der Seite der Lambda-Funktion den Tab Konfiguration aus.
  2. Klicken Sie in der linken Seitenleiste auf Allgemeine Konfiguration.
  3. Klicken Sie auf Bearbeiten.
  4. Geben Sie die folgenden Konfigurationsdetails an:
    • Arbeitsspeicher: 256 MB (empfohlen)
    • Zeitüberschreitung: 5 min 0 sec (300 Sekunden)
  5. 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:
    • Name des Zeitplans: Geben Sie harness-audit-hourly ein.
    • Beschreibung: Optionale Beschreibung.
  3. Klicken Sie auf Weiter.
  4. Wählen Sie unter Zeitplanmuster die Option Wiederkehrender Zeitplan aus.
  5. Wählen Sie Ratenbasierter Zeitplan aus.
  6. Geben Sie die folgenden Konfigurationsdetails an:
    • Raten-Ausdruck: Geben Sie 1 hour ein.
  7. Klicken Sie auf Weiter.
  8. Geben Sie unter Ziel die folgenden Konfigurationsdetails an:
    • Ziel-API: Wählen Sie AWS Lambda Invoke aus.
    • Lambda-Funktion: Wählen Sie Ihre Funktion harness-audit-to-s3 aus.
  9. Klicken Sie auf Weiter.
  10. Überprüfen Sie die Planungskonfiguration.
  11. Klicken Sie auf Zeitplan erstellen.

IAM-Nutzer mit Lesezugriff für Google SecOps erstellen

Mit diesem IAM-Nutzer kann Google SecOps Logs aus dem S3-Bucket lesen.

  1. Rufen Sie die AWS-Konsole > IAM > Nutzer > Nutzer erstellen auf.
  2. Geben Sie die folgenden Konfigurationsdetails an:
    • Nutzername: Geben Sie chronicle-s3-reader ein.
  3. Klicken Sie auf Weiter.
  4. Wählen Sie Richtlinien direkt anhängen aus.
  5. Klicken Sie auf Richtlinie erstellen.
  6. Wählen Sie den Tab JSON aus.
  7. Fügen Sie die folgende Richtlinie ein:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "s3:GetObject"
          ],
          "Resource": "arn:aws:s3:::harness-io-logs/harness/audit/*"
        },
        {
          "Effect": "Allow",
          "Action": [
            "s3:ListBucket"
          ],
          "Resource": "arn:aws:s3:::harness-io-logs",
          "Condition": {
            "StringLike": {
              "s3:prefix": "harness/audit/*"
            }
          }
        }
      ]
    }
    
  8. Klicken Sie auf Weiter.

  9. Nennen Sie die Richtlinie ChronicleHarnessS3ReadPolicy.

  10. Klicken Sie auf Richtlinie erstellen.

  11. Kehren Sie zum Tab für die Nutzererstellung zurück und aktualisieren Sie die Richtlinienliste.

  12. Suchen Sie nach ChronicleHarnessS3ReadPolicy und wählen Sie den Eintrag aus.

  13. Klicken Sie auf Weiter.

  14. Prüfen Sie die Angaben und klicken Sie auf Nutzer erstellen.

Zugriffsschlüssel für den Leser erstellen

  1. Wählen Sie auf der Seite IAM Users (IAM-Nutzer) den Nutzer chronicle-s3-reader aus.
  2. Wählen Sie den Tab Sicherheitsanmeldedaten aus.
  3. Klicken Sie auf Zugriffsschlüssel erstellen.
  4. Wählen Sie Drittanbieterdienst als Anwendungsfall aus.
  5. Klicken Sie auf Weiter.
  6. Optional: Fügen Sie ein Beschreibungstag hinzu.
  7. Klicken Sie auf Zugriffsschlüssel erstellen.
  8. Klicken Sie auf CSV-Datei herunterladen, um die Zugriffsschlüssel-ID und den geheimen Zugriffsschlüssel zu speichern.
  9. Klicken Sie auf Fertig.

Feed in Google SecOps konfigurieren, um Harness IO-Logs aufzunehmen

  1. Rufen Sie die SIEM-Einstellungen > Feeds auf.
  2. Klicken Sie auf Neu hinzufügen.
  3. Klicken Sie auf der nächsten Seite auf Einen einzelnen Feed konfigurieren.
  4. Geben Sie im Feld Feedname einen Namen für den Feed ein, z. B. Harness Audit Logs.
  5. Wählen Sie Amazon S3 V2 als Quelltyp aus.
  6. Wählen Sie Harness IO als Logtyp aus.
  7. Klicken Sie auf Weiter.
  8. Geben Sie Werte für die folgenden Eingabeparameter an:

    • S3-URI: Geben Sie den S3-Bucket-URI mit dem Präfixpfad ein: s3://harness-io-logs/harness/audit/
    • Option zum Löschen der Quelle: Wählen Sie die gewünschte Option zum Löschen aus:

      • Nie: Es werden nie Dateien nach Übertragungen gelöscht (anfangs empfohlen).
      • Bei Erfolg: Löscht alle Dateien und leeren Verzeichnisse nach der erfolgreichen Übertragung.
    • Maximales Dateialter: Dateien einschließen, die in den letzten Tagen geändert wurden. Der Standardwert ist 180 Tage.

    • Zugriffsschlüssel-ID: Geben Sie die Zugriffsschlüssel-ID des Nutzers chronicle-s3-reader ein.

    • Geheimer Zugriffsschlüssel: Geben Sie den geheimen Zugriffsschlüssel des Nutzers chronicle-s3-reader ein.

    • Asset-Namespace: Der Asset-Namespace. Geben Sie harness.audit ein.

    • Aufnahmelabels: Optionale Labels, die auf Ereignisse aus diesem Feed angewendet werden sollen.

  9. Klicken Sie auf Weiter.

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