איסוף יומני ביקורת של Harness IO

נתמך ב:

במסמך הזה מוסבר איך להטמיע יומני ביקורת של Harness IO ב-Google Security Operations באמצעות Google Cloud Storage. ‫Harness היא פלטפורמה לפיתוח רציף (continuous delivery) ול-DevOps, שמספקת כלים להכנת תוכנה להפצה, ל-feature flags, לניהול עלויות בענן ולבדיקות אבטחה.

לפני שמתחילים

חשוב לוודא שיש לכם את הדברים הבאים:

  • מכונה של Google SecOps
  • פרויקט ב-GCP שבו מופעל Cloud Storage API
  • הרשאות ליצירה ולניהול של קטגוריות ב-GCS
  • הרשאות לניהול מדיניות IAM בקטגוריות של GCS
  • הרשאות ליצירת שירותי Cloud Run, נושאי Pub/Sub ומשימות ב-Cloud Scheduler
  • גישה עם הרשאות ניהול ל-Harness, עם ההרשאות הבאות:
    • יצירת מפתחות API
    • יומני ביקורת של גישה
    • הצגת הגדרות החשבון

איסוף פרטי הכניסה ל-Harness API

יצירת מפתח API ב-Harness

  1. נכנסים לפלטפורמת Harness.
  2. לוחצים על פרופיל המשתמש.
  3. עוברים אל My API Keys (מפתחות ה-API שלי).
  4. לוחצים על ‎+ מפתח API.
  5. מזינים את פרטי ההגדרה הבאים:
    • שם: מזינים שם תיאורי (לדוגמה, Google SecOps Integration).
    • תיאור: תיאור אופציונלי.
  6. לוחצים על Save.
  7. לוחצים על + Token כדי ליצור אסימון חדש.
  8. מזינים את פרטי ההגדרה הבאים:
    • שם: מזינים Chronicle Feed Token.
    • הגדרת תפוגה: בוחרים את זמן התפוגה המתאים או ללא תפוגה (לשימוש בסביבת ייצור).
  9. לוחצים על Generate Token.
  10. מעתיקים ושומרים את ערך הטוקן באופן מאובטח. האסימון הזה ישמש כערך הכותרת של x-api-key.

קבלת מזהה החשבון ב-Harness

  1. ב-Harness Platform, מאתרים את מזהה החשבון בכתובת ה-URL.

כתובת URL לדוגמה: https://app.harness.io/ng/account/YOUR_ACCOUNT_ID/.... החלק YOUR_ACCOUNT_ID הוא מזהה החשבון.

אפשר גם לעבור אל הגדרות החשבון > סקירה כללית כדי לראות את מזהה החשבון.

  1. מעתיקים ושומרים את מזהה החשבון כדי להשתמש בו בפונקציית Cloud Run.

יצירת קטגוריה של Google Cloud Storage

  1. נכנסים למסוף Google Cloud.
  2. בוחרים את הפרויקט או יוצרים פרויקט חדש.
  3. בתפריט הניווט, נכנסים ל-Cloud Storage > Buckets.
  4. לוחצים על Create bucket.
  5. ממלאים את פרטי ההגדרה הבאים:

    הגדרה ערך
    Name your bucket מזינים שם ייחודי ברמה גלובלית (לדוגמה, harness-io-logs)
    סוג המיקום בוחרים לפי הצרכים (אזור, שני אזורים, מספר אזורים)
    Location בוחרים את המיקום (לדוגמה, us-central1)
    סוג אחסון (storage class) רגיל (מומלץ ליומנים שהגישה אליהם תכופה)
    בקרת גישה אחידה (מומלץ)
    כלי הגנה אופציונלי: הפעלת ניהול גרסאות של אובייקטים או מדיניות שמירת נתונים
  6. לוחצים על יצירה.

יצירת חשבון שירות לפונקציית Cloud Run

לפונקציית Cloud Run נדרש חשבון שירות עם הרשאות כתיבה בקטגוריית GCS, וצריך להפעיל אותה באמצעות Pub/Sub.

יצירת חשבון שירות

  1. במסוף GCP, נכנסים לדף IAM & Admin > Service Accounts.
  2. לוחצים על Create Service Account.
  3. מזינים את פרטי ההגדרה הבאים:
    • שם חשבון השירות: מזינים harness-audit-collector-sa.
    • Service account description: מזינים Service account for Cloud Run function to collect Harness IO audit logs.
  4. לוחצים על יצירה והמשך.
  5. בקטע Grant this service account access to project, מוסיפים את התפקידים הבאים:
    1. לוחצים על בחירת תפקיד.
    2. מחפשים את התפקיד Storage Object Admin ובוחרים אותו.
    3. לוחצים על + הוספת תפקיד.
    4. מחפשים את התפקיד Cloud Run Invoker ובוחרים בו.
    5. לוחצים על + הוספת תפקיד.
    6. מחפשים את התפקיד Cloud Functions Invoker ובוחרים אותו.
  6. לוחצים על Continue.
  7. לוחצים על סיום.

התפקידים האלה נדרשים כדי:

  • אדמין של אובייקט אחסון: כתיבת יומנים לקטגוריית GCS וניהול קובצי תמונת מצב
  • Cloud Run Invoker: מאפשר ל-Pub/Sub להפעיל את הפונקציה
  • מפעיל פונקציות של Cloud Functions: מאפשר להפעיל פונקציות

הענקת הרשאות IAM בקטגוריית GCS

נותנים לחשבון השירות הרשאות כתיבה בקטגוריה של GCS:

  1. נכנסים לדף Cloud Storage > Buckets.
  2. לוחצים על שם הקטגוריה.
  3. עוברים לכרטיסייה Permissions.
  4. לוחצים על הענקת גישה.
  5. מזינים את פרטי ההגדרה הבאים:
    • הוספת חשבונות משתמשים: מזינים את כתובת האימייל של חשבון השירות (לדוגמה, harness-audit-collector-sa@PROJECT_ID.iam.gserviceaccount.com).
    • הקצאת תפקידים: בוחרים באפשרות אדמין של אובייקטים באחסון.
  6. לוחצים על Save.

יצירת נושא Pub/Sub

יוצרים נושא Pub/Sub ש-Cloud Scheduler יפרסם בו ופונקציית Cloud Run תירשם אליו.

  1. במסוף GCP, נכנסים לדף Pub/Sub > Topics.
  2. לוחצים על Create topic.
  3. מזינים את פרטי ההגדרה הבאים:
    • מזהה הנושא: מזינים את הערך harness-audit-trigger.
    • משאירים את ההגדרות האחרות כברירת מחדל.
  4. לוחצים על יצירה.

יצירת פונקציית Cloud Run לאיסוף יומנים

הפונקציה של Cloud Run מופעלת על ידי הודעות Pub/Sub מ-Cloud Scheduler כדי לאחזר יומנים מ-Harness API ולכתוב אותם ב-GCS.

  1. במסוף GCP, נכנסים ל-Cloud Run.
  2. לוחצים על Create service.
  3. בוחרים באפשרות Function (שימוש בעורך ישיר כדי ליצור פונקציה).
  4. בקטע Configure, מזינים את פרטי ההגדרה הבאים:

    הגדרה ערך
    שם השירות harness-audit-collector
    אזור בוחרים את האזור שתואם לקטגוריית ה-GCS (לדוגמה, us-central1)
    זמן ריצה בוחרים באפשרות Python 3.12 או גרסה עדכנית יותר.
  5. בקטע טריגר (אופציונלי):

    1. לוחצים על + הוספת טריגר.
    2. בוחרים באפשרות Cloud Pub/Sub.
    3. בקטע Select a Cloud Pub/Sub topic, בוחרים את הנושא ב-Pub/Sub‏ (harness-audit-trigger).
    4. לוחצים על Save.
  6. בקטע אימות:

    1. לוחצים על דרישת אימות.
    2. בודקים את ניהול הזהויות והרשאות הגישה (IAM).
  7. גוללים למטה ומרחיבים את הקטע Containers, Networking, Security.

  8. עוברים לכרטיסייה אבטחה:

    • ‫Service account: בוחרים את חשבון השירות (harness-audit-collector-sa).
  9. עוברים לכרטיסייה מאגרי תגים:

    1. לוחצים על Variables & Secrets.
    2. לוחצים על ‎+ Add variable לכל משתנה סביבה:
    שם משתנה ערך לדוגמה תיאור
    HARNESS_ACCOUNT_ID מזהה החשבון שלכם ב-Harness מזהה החשבון מ-Harness
    HARNESS_API_KEY הטוקן של מפתח ה-API שלכם אסימון עם הרשאות audit:read
    GCS_BUCKET harness-io-logs שם הקטגוריה ב-GCS
    GCS_PREFIX harness/audit קידומת לאובייקטים ב-GCS
    STATE_KEY harness/audit/state.json נתיב קובץ תמונת המצב ב-GCS
    • משתני סביבה אופציונליים:
    שם משתנה ערך ברירת המחדל תיאור
    HARNESS_API_BASE https://app.harness.io כתובת ה-URL הבסיסית של Harness API (שינוי של מופעים באירוח עצמי)
    PAGE_SIZE 50 אירועים בכל דף (עד 100)
    START_MINUTES_BACK 60 תקופת המבט לאחור הראשונית בדקות
    FILTER_MODULES ללא מודולים מופרדים בפסיקים (למשל, CD,CI,CE)
    FILTER_ACTIONS ללא פעולות מופרדות בפסיקים (למשל, CREATE,UPDATE,DELETE)
    STATIC_FILTER ללא מסנן מוגדר מראש: EXCLUDE_LOGIN_EVENTS או EXCLUDE_SYSTEM_EVENTS
    MAX_RETRIES 3 מספר הניסיונות המקסימלי להגבלת קצב של יצירת בקשות
  10. גוללים למטה בכרטיסייה Variables & Secrets (משתנים וסודות) עד שמגיעים לקטע Requests (בקשות):

    • ‫Request timeout: מזינים 600 שניות (10 דקות).
  11. עוברים לכרטיסייה הגדרות בקטע מאגרים:

    • בקטע Resources:
      • זיכרון: בוחרים באפשרות ‎512 MiB או יותר.
      • מעבד (CPU): בוחרים באפשרות 1.
    • לוחצים על סיום.
  12. גוללים אל סביבת הפעלה:

    • בוחרים באפשרות ברירת מחדל (מומלץ).
  13. בקטע Revision scaling:

    • מספר מינימלי של מכונות: מזינים 0.
    • Maximum number of instances: מזינים 100 (או משנים בהתאם לעומס הצפוי).
  14. לוחצים על יצירה.

  15. ממתינים ליצירת השירות (דקה או שתיים).

  16. אחרי שיוצרים את השירות, עורך הקוד המוטבע נפתח באופן אוטומטי.

הוספת קוד פונקציה

  1. מזינים main בשדה Function entry point.
  2. בעורך הקוד, יוצרים שני קבצים:

    • הקובץ הראשון: main.py:
    import functions_framework
    from google.cloud import storage
    import json
    import os
    import urllib3
    from datetime import datetime, timedelta, timezone
    import time
    
    # Initialize HTTP client
    http = urllib3.PoolManager()
    
    # Initialize Storage client
    storage_client = storage.Client()
    
    # 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["GCS_BUCKET"]
    PREFIX = os.environ.get("GCS_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
    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")
    MAX_RETRIES = int(os.environ.get("MAX_RETRIES", "3"))
    
    # HTTP headers for Harness API
    HDRS = {
        "x-api-key": API_KEY,
        "Content-Type": "application/json",
        "Accept": "application/json",
    }
    
    def read_state(bucket):
        """Read checkpoint state from GCS."""
        try:
            blob = bucket.blob(STATE_KEY)
            if blob.exists():
                state_data = blob.download_as_text()
                state = json.loads(state_data)
                since_ms = state.get("since")
                page_token = state.get("pageToken")
                print(f"State loaded: since={since_ms}, pageToken={page_token}")
                return since_ms, page_token
        except Exception as e:
            print(f"Warning: Could not load state: {e}")
    
        print("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)
        print(f"Initial since timestamp: {since_ms} ({start_time.isoformat()})")
        return since_ms, None
    
    def write_state(bucket, since_ms, page_token=None):
        """Write checkpoint state to GCS."""
        state = {
            "since": since_ms,
            "pageToken": page_token,
            "lastRun": int(time.time() * 1000),
            "lastRunISO": datetime.now(timezone.utc).isoformat()
        }
        try:
            blob = bucket.blob(STATE_KEY)
            blob.upload_from_string(
                json.dumps(state, indent=2),
                content_type="application/json"
            )
            print(f"State saved: since={since_ms}, pageToken={page_token}")
        except Exception as e:
            print(f"Error writing state: {e}")
            raise
    
    def fetch_harness_audits(since_ms, page_token=None, retry_count=0):
        """
        Fetch audit logs from Harness API with retry logic.
        API Endpoint: POST /audit/api/audits/listV2
        """
        try:
            # Build URL with query parameters
            url = (
                f"{API_BASE}/audit/api/audits/listV2"
                f"?accountIdentifier={ACCOUNT_ID}"
                f"&pageSize={PAGE_SIZE}"
            )
            if page_token:
                url += f"&pageToken={page_token}"
    
            print(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()]
                print(f"Applying module filter: {body_data['modules']}")
    
            if FILTER_ACTIONS:
                body_data["actions"] = [a.strip() for a in FILTER_ACTIONS if a.strip()]
                print(f"Applying action filter: {body_data['actions']}")
    
            if STATIC_FILTER:
                body_data["staticFilter"] = STATIC_FILTER
                print(f"Applying static filter: {STATIC_FILTER}")
    
            # Make POST request
            response = http.request(
                'POST',
                url,
                body=json.dumps(body_data).encode('utf-8'),
                headers=HDRS,
                timeout=30.0
            )
    
            resp_data = json.loads(response.data.decode('utf-8'))
    
            if "status" not in resp_data:
                print(f"Response missing 'status' field: {response.data[: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:
                print("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")
    
            print(f"API response: {len(events)} events, hasNext={has_next}, pageToken={next_token}")
    
            if not events and data_obj:
                print(f"Empty events but data present. Data keys: {list(data_obj.keys())}")
    
            return {
                "events": events,
                "hasNext": has_next,
                "pageToken": next_token
            }
    
        except Exception as e:
            if hasattr(e, 'status') and e.status == 429:
                retry_after = 60
                print(f"Rate limit exceeded. Retry after {retry_after} seconds (attempt {retry_count + 1}/{MAX_RETRIES})")
                if retry_count < MAX_RETRIES:
                    print(f"Waiting {retry_after} seconds before retry...")
                    time.sleep(retry_after)
                    print(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")
            print(f"Error in fetch_harness_audits: {e}")
            raise
    
    def upload_to_gcs(bucket, events):
        """Upload audit events to GCS in JSONL format."""
        if not events:
            print("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 GCS key with timestamp
            timestamp = datetime.now(timezone.utc)
            key = (
                f"{PREFIX}/"
                f"{timestamp:%Y/%m/%d}/"
                f"harness-audit-{timestamp:%Y%m%d-%H%M%S}.jsonl"
            )
    
            # Upload to GCS
            blob = bucket.blob(key)
            blob.upload_from_string(
                jsonl_content,
                content_type="application/x-ndjson"
            )
            blob.metadata = {
                "event-count": str(len(events)),
                "source": "harness-audit-function",
                "collection-time": timestamp.isoformat()
            }
            blob.patch()
    
            print(f"Uploaded {len(events)} events to gs://{BUCKET}/{key}")
            return key
    
        except Exception as e:
            print(f"Error uploading to GCS: {e}")
            raise
    
    @functions_framework.cloud_event
    def main(cloud_event):
        """
        Cloud Run function triggered by Pub/Sub to fetch Harness audit logs and write to GCS.
    
        Args:
            cloud_event: CloudEvent object containing Pub/Sub message
        """
        print("=== Harness Audit Collection Started ===")
        print(f"Configuration: API_BASE={API_BASE}, ACCOUNT_ID={ACCOUNT_ID[:8]}..., PAGE_SIZE={PAGE_SIZE}")
    
        if FILTER_MODULES:
            print(f"Module filter enabled: {FILTER_MODULES}")
        if FILTER_ACTIONS:
            print(f"Action filter enabled: {FILTER_ACTIONS}")
        if STATIC_FILTER:
            print(f"Static filter enabled: {STATIC_FILTER}")
    
        try:
            # Get GCS bucket
            bucket = storage_client.bucket(BUCKET)
    
            # Step 1: Read checkpoint state
            since_ms, page_token = read_state(bucket)
    
            if page_token:
                print("Resuming pagination from saved pageToken")
            else:
                since_dt = datetime.fromtimestamp(since_ms / 1000, tz=timezone.utc)
                print(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
            has_next = True
    
            while has_next and page_count < max_pages:
                page_count += 1
                print(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)
                print(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:
                    print("Pagination complete (hasNext=False)")
                    break
    
                if not current_page_token:
                    print("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:
                print(f"Reached max pages limit ({max_pages}), stopping")
    
            # Step 3: Upload collected events to GCS
            if all_events:
                gcs_key = upload_to_gcs(bucket, all_events)
                print(f"Successfully uploaded {len(all_events)} total events")
            else:
                print("No new events to upload")
                gcs_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(bucket, new_since, None)
                print(f"Pagination complete, state updated with new since={new_since}")
            else:
                # Pagination incomplete - save pageToken for continuation
                write_state(bucket, since_ms, current_page_token)
                print("Pagination incomplete, saved pageToken for next run")
    
            # Step 5: Log result
            result = {
                "status": "Success",
                "eventsCollected": len(all_events),
                "pagesProcessed": page_count,
                "paginationComplete": not has_next,
                "gcsKey": gcs_key,
                "filters": {
                    "modules": FILTER_MODULES,
                    "actions": FILTER_ACTIONS,
                    "staticFilter": STATIC_FILTER
                }
            }
            print(f"Collection completed: {json.dumps(result)}")
    
        except Exception as e:
            print(f"Collection failed: {e}")
            raise
        finally:
            print("=== Harness Audit Collection Finished ===")
    
    • הקובץ השני: requirements.txt:
    functions-framework==3.*
    google-cloud-storage==2.*
    urllib3>=2.0.0
    
  3. לוחצים על Deploy כדי לשמור ולפרוס את הפונקציה.

  4. מחכים שהפריסה תסתיים (2-3 דקות).

יצירת משימה ב-Cloud Scheduler

‫Cloud Scheduler מפרסם הודעות בנושא Pub/Sub במרווחי זמן קבועים, ומפעיל את פונקציית Cloud Run.

  1. במסוף GCP, נכנסים ל-Cloud Scheduler.
  2. לוחצים על Create Job.
  3. ממלאים את פרטי ההגדרה הבאים:

    הגדרה ערך
    שם harness-audit-hourly
    אזור בוחרים את אותו אזור כמו של פונקציית Cloud Run.
    תדירות ‫0 * * * * (כל שעה, בשעה עגולה)
    אזור זמן בחירת אזור זמן (מומלץ לבחור ב-UTC)
    סוג היעד Pub/Sub
    נושא בוחרים את נושא Pub/Sub (harness-audit-trigger)
    גוף ההודעה ‫{} (אובייקט JSON ריק)
  4. לוחצים על יצירה.

אפשרויות לתדירות התזמון

  • בוחרים את התדירות בהתאם לנפח היומן ולדרישות לגבי זמן האחזור:

    תדירות ביטוי Cron תרחיש לדוגמה
    כל 5 דקות */5 * * * * נפח גבוה, זמן אחזור נמוך
    כל 15 דקות */15 * * * * נפח חיפושים בינוני
    כל שעה 0 * * * * רגיל (מומלץ)
    כל 6 שעות 0 */6 * * * נפח נמוך, עיבוד ברצף (batch processing)
    יומי 0 0 * * * איסוף נתונים היסטוריים

בדיקת השילוב

  1. במסוף Cloud Scheduler, מוצאים את המשימה.
  2. לוחצים על Force run כדי להפעיל את המשימה באופן ידני.
  3. מחכים כמה שניות.
  4. נכנסים לדף Cloud Run > Services.
  5. לוחצים על שם הפונקציה (harness-audit-collector).
  6. לוחצים על הכרטיסייה Logs.
  7. מוודאים שהפונקציה בוצעה בהצלחה. מחפשים את הדברים הבאים:

    === Harness Audit Collection Started ===
    State loaded: since=... or No state file found, starting fresh collection
    --- Fetching page 1 ---
    API response: X events, hasNext=...
    Uploaded X events to gs://harness-io-logs/harness/audit/...
    Successfully processed X records
    === Harness Audit Collection Finished ===
    
  8. נכנסים לדף Cloud Storage > Buckets.

  9. לוחצים על שם הקטגוריה.

  10. עוברים לתיקיית הקידומת (harness/audit/).

  11. מוודאים שנוצר קובץ .jsonl חדש עם חותמת הזמן הנוכחית.

אם מופיעות שגיאות ביומנים:

  • ‫HTTP 401: בודקים את פרטי הכניסה ל-API במשתני הסביבה
  • ‫HTTP 403: מוודאים שלחשבון יש את ההרשאות הנדרשות
  • ‫HTTP 429: הגבלת קצב של יצירת בקשות – הפונקציה תנסה שוב באופן אוטומטי עם השהיה (backoff)
  • חסרים משתני סביבה: צריך לוודא שכל המשתנים הנדרשים מוגדרים

אחזור של חשבון השירות של Google SecOps

מערכת Google SecOps משתמשת בחשבון שירות ייחודי כדי לקרוא נתונים מהקטגוריה שלכם ב-GCS. אתם צריכים לתת לחשבון השירות הזה גישה לקטגוריה שלכם.

איך מקבלים את כתובת האימייל של חשבון השירות

  1. עוברים אל הגדרות > ניהול נתונים > פידים. אם אתם משתמשים בפלטפורמה של SIEM בלבד, עוברים אל הגדרות > פידים.
  2. לוחצים על הוספת פיד חדש.
  3. לוחצים על הגדרת פיד יחיד.
  4. בשדה שם הפיד, מזינים שם לפיד (לדוגמה, Harness Audit Logs).
  5. בוחרים באפשרות Google Cloud Storage V2 בתור סוג המקור.
  6. בוחרים באפשרות Harness IO בתור Log type.
  7. לוחצים על Get Service Account (קבלת חשבון שירות). מוצגת כתובת אימייל ייחודית של חשבון שירות, לדוגמה:

    chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com
    
  8. מעתיקים את כתובת האימייל הזו כדי להשתמש בה בשלב הבא.

מתן הרשאות IAM לחשבון השירות של Google SecOps

לחשבון השירות של Google SecOps צריך להיות התפקיד צפייה באובייקט אחסון בקטגוריה של GCS.

  1. נכנסים לדף Cloud Storage > Buckets.
  2. לוחצים על שם הקטגוריה.
  3. עוברים לכרטיסייה Permissions.
  4. לוחצים על הענקת גישה.
  5. מזינים את פרטי ההגדרה הבאים:
    • הוספת חשבונות משתמשים: מדביקים את כתובת האימייל של חשבון השירות של Google SecOps.
    • הקצאת תפקידים: בוחרים באפשרות צפייה באובייקטים באחסון.
  6. לוחצים על Save.

הגדרת פיד ב-Google SecOps כדי להטמיע יומנים של Harness IO

  1. עוברים אל הגדרות > ניהול נתונים > פידים. אם אתם משתמשים בפלטפורמה של SIEM בלבד, עוברים אל הגדרות > פידים.
  2. לוחצים על הוספת פיד חדש.
  3. לוחצים על הגדרת פיד יחיד.
  4. בשדה שם הפיד, מזינים שם לפיד (לדוגמה, Harness Audit Logs).
  5. בוחרים באפשרות Google Cloud Storage V2 בתור סוג המקור.
  6. בוחרים באפשרות Harness IO בתור Log type.
  7. לוחצים על הבא.
  8. מציינים ערכים לפרמטרים הבאים של הקלט:

    • כתובת ה-URL של קטגוריית האחסון: מזינים את ה-URI של קטגוריית GCS עם נתיב הקידומת:

      gs://harness-io-logs/harness/audit/
      
      • מחליפים את:

        • ‫harness-io-logs: השם של קטגוריית GCS.
        • ‫harness/audit: נתיב הקידומת או התיקייה שבהם נשמרים היומנים.
      • לדוגמה:

        • קטגוריית הבסיס: gs://company-logs/
        • עם הקידומת: gs://company-logs/harness-logs/
        • עם תיקיית משנה: gs://company-logs/harness/audit/
    • אפשרות מחיקת המקור: בוחרים את אפשרות המחיקה המועדפת:

      • Never: אף פעם לא למחוק קבצים אחרי העברות (מומלץ לבדיקה).
      • מחיקת קבצים שהועברו: מחיקת קבצים אחרי שהם הועברו בהצלחה.
      • מחיקת קבצים שהועברו וספריות ריקות: מחיקת קבצים וספריות ריקות אחרי שההעברה מסתיימת.

    • גיל הקובץ המקסימלי: כולל קבצים ששונו במספר הימים האחרונים. ברירת המחדל היא 180 ימים.

    • מרחב השמות של הנכס: מרחב השמות של הנכס. מזינים את הערך harness.audit.

    • תוויות הטמעה: התווית שתתווסף לאירועים מהפיד הזה.

  9. לוחצים על הבא.

  10. בודקים את הגדרות הפיד החדש במסך סיום ולוחצים על שליחה.

יומן שינויים

הצגת יומן השינויים של המנתח הזה

הבעיה עדיין לא נפתרה? קבלת תשובות מחברי הקהילה וממומחי Google SecOps.