איסוף יומנים של PingIDM (לשעבר ForgeRock OpenIDM)

גרסת המנתח: 4.0

נתמך ב:

במסמך הזה מוסבר איך להטמיע יומני PingIDM (לשעבר ForgeRock OpenIDM) ב-Google Security Operations באמצעות Google Cloud Storage V2.

‫PingIDM היא פלטפורמה לניהול זהויות שמאפשרת הקצאת משתמשים, סנכרון, ניהול סיסמאות וניהול הרשאות גישה. הוא מתעד אירועים במחזור החיים של הזהות, ניסיונות אימות, פעולות התאמה ושינויים בהגדרות ביומני ביקורת שאפשר לגשת אליהם דרך REST.

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

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

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

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

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

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

איסוף פרטי הכניסה של ForgeRock OpenIDM

קבלת כתובת ה-URL הבסיסית של ForgeRock OpenIDM

  1. נכנסים למכונה של ForgeRock OpenIDM או PingIDM.
  2. שימו לב לכתובת ה-URL הבסיסית מסרגל הכתובות של הדפדפן.
    • פורמט: https://openidm.example.com
    • אל תכללו לוכסנים בסוף או נתיבים כמו /admin.

קבלת פרטי כניסה של אדמין

  1. משיגים פרטי כניסה של אדמין למכונה של ForgeRock OpenIDM.
  2. מה צריך:
    • שם משתמש: שם משתמש אדמין (למשל, openidm-admin)
    • סיסמה: סיסמת אדמין

אימות ההרשאות

  1. נכנסים ל-ForgeRock OpenIDM.
  2. עוברים אל Configure (הגדרה) > System Preferences (העדפות מערכת) > Audit (ביקורת).
  3. אם אתם יכולים לראות את הגדרות הביקורת ואת הנושאים, יש לכם את ההרשאות הנדרשות.
  4. אם האפשרות הזו לא מופיעה, פנו לאדמין כדי לקבל הרשאות קריאה של ביקורת.

בדיקת הגישה ל-API

  • לפני שממשיכים בתהליך השילוב, בודקים את פרטי הכניסה:

    # Replace with your actual credentials
    OPENIDM_BASE_URL="[https://openidm.example.com](https://openidm.example.com)"
    OPENIDM_USERNAME="openidm-admin"
    OPENIDM_PASSWORD="your-admin-password"
    
    # Test API access to authentication audit topic
    curl -v \
        -H "X-OpenIDM-Username: ${OPENIDM_USERNAME}" \
        -H "X-OpenIDM-Password: ${OPENIDM_PASSWORD}" \
        -H "Accept-API-Version: resource=1.0" \
        -H "Accept: application/json" \
        "${OPENIDM_BASE_URL}/openidm/audit/authentication?_queryFilter=true&_pageSize=1"
    

התגובה הצפויה: HTTP 200 עם JSON שמכיל אירועי ביקורת.

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

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

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

  1. במסוף GCP, נכנסים לדף IAM & Admin > Service Accounts.
  2. לוחצים על Create Service Account.
  3. מזינים את פרטי ההגדרה הבאים:
    • שם חשבון השירות: forgerock-openidm-collector-sa
    • תיאור חשבון השירות: Service account for Cloud Run function to collect ForgeRock OpenIDM logs
  4. לוחצים על יצירה והמשך.
  5. בקטע Grant this service account access to project, מוסיפים את התפקידים הבאים:
    1. אדמין של אובייקט אחסון: כדי לכתוב יומנים בקטגוריית GCS ולנהל קובצי תמונת מצב.
    2. Cloud Run Invoker: כדי לאפשר ל-Pub/Sub להפעיל את הפונקציה.
    3. ‫Cloud Functions Invoker: כדי לאפשר הפעלה של פונקציות.
  6. לוחצים על המשך ואז על סיום.

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

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

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

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

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

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

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

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

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

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

    • חשבון שירות: בוחרים באפשרות forgerock-openidm-collector-sa.
  9. עוברים לכרטיסייה מאגרי תגים:

    1. לוחצים על Variables & Secrets.
    2. לוחצים על ‎+ Add variable לכל משתנה סביבה:
    שם משתנה ערך לדוגמה תיאור
    GCS_BUCKET forgerock-openidm-audit-logs שם הקטגוריה ב-GCS
    GCS_PREFIX openidm קידומת לקובצי יומן
    STATE_KEY openidm/state.json נתיב קובץ תמונת המצב
    OPENIDM_BASE_URL https://openidm.example.com כתובת ה-URL הבסיסית של OpenIDM
    OPENIDM_USERNAME openidm-admin שם המשתמש של האדמין ב-OpenIDM
    OPENIDM_PASSWORD your-admin-password סיסמת אדמין ב-OpenIDM
    AUDIT_TOPICS access,activity,authentication,config,sync נושאים מופרדים בפסיקים
    PAGE_SIZE 100 רשומות בכל דף
    MAX_PAGES 50 מספר הדפים המקסימלי לכל נושא
  10. בקטע בקשות:

    • ‫Request timeout: ‏600 שניות.
  11. עוברים לכרטיסייה הגדרות:

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

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

  1. בשדה Entry point, מזינים main.
  2. יוצרים שני קבצים בכלי לעריכת טקסט:

    • main.py:
    import functions_framework
    from google.cloud import storage
    import json
    import os
    import urllib3
    from datetime import datetime, timezone
    
    # Initialize HTTP client with timeouts
    http = urllib3.PoolManager(
        timeout=urllib3.Timeout(connect=5.0, read=30.0),
        retries=False,
    )
    
    # Initialize Storage client
    storage_client = storage.Client()
    
    # Environment variables
    GCS_BUCKET = os.environ.get('GCS_BUCKET')
    GCS_PREFIX = os.environ.get('GCS_PREFIX', 'openidm')
    STATE_KEY = os.environ.get('STATE_KEY', 'openidm/state.json')
    OPENIDM_BASE_URL = os.environ.get('OPENIDM_BASE_URL')
    OPENIDM_USERNAME = os.environ.get('OPENIDM_USERNAME')
    OPENIDM_PASSWORD = os.environ.get('OPENIDM_PASSWORD')
    AUDIT_TOPICS = os.environ.get('AUDIT_TOPICS', 'access,activity,authentication,config,sync').split(',')
    PAGE_SIZE = int(os.environ.get('PAGE_SIZE', '100'))
    MAX_PAGES = int(os.environ.get('MAX_PAGES', '50'))
    
    @functions_framework.cloud_event
    def main(cloud_event):
        """
        Cloud Run function triggered by Pub/Sub to fetch ForgeRock OpenIDM logs and write to GCS.
        """
        if not all([GCS_BUCKET, OPENIDM_BASE_URL, OPENIDM_USERNAME, OPENIDM_PASSWORD]):
            print('Error: Missing required environment variables')
            return
    
        try:
            bucket = storage_client.bucket(GCS_BUCKET)
            state = load_state(bucket, STATE_KEY)
    
            all_events = []
            for topic in AUDIT_TOPICS:
                topic = topic.strip()
                print(f"Fetching audit logs for topic: {topic}")
                events = fetch_audit_logs(topic, state.get(topic, {}))
                all_events.extend(events)
    
                if events:
                    latest_timestamp = max(e.get('timestamp', '') for e in events)
                    state[topic] = {
                        'last_timestamp': latest_timestamp,
                        'last_run': datetime.now(timezone.utc).isoformat(),
                        'events_count': len(events)
                    }
    
            if all_events:
                write_to_gcs(bucket, all_events)
                save_state(bucket, STATE_KEY, state)
                print(f"Successfully processed {len(all_events)} audit events")
            else:
                print("No new audit events to process")
    
        except Exception as e:
            print(f'Error processing logs: {str(e)}')
            raise
    
    def load_state(bucket, key):
        try:
            blob = bucket.blob(key)
            if blob.exists():
                return json.loads(blob.download_as_text())
        except Exception as e:
            print(f"Warning: Could not load state: {e}")
        return {}
    
    def save_state(bucket, key, state):
        try:
            blob = bucket.blob(key)
            blob.upload_from_string(json.dumps(state, indent=2), content_type='application/json')
        except Exception as e:
            print(f"Warning: Could not save state: {e}")
    
    def fetch_audit_logs(topic, topic_state):
        base_url = OPENIDM_BASE_URL.rstrip('/')
        all_events = []
        last_timestamp = topic_state.get('last_timestamp')
        query_filter = 'true' if not last_timestamp else f'timestamp gt "{last_timestamp}"'
        page_offset = 0
        page_count = 0
    
        while page_count < MAX_PAGES:
            try:
                url = f"{base_url}/openidm/audit/{topic}"
                params = {
                    '_queryFilter': query_filter,
                    '_pageSize': str(PAGE_SIZE),
                    '_pagedResultsOffset': str(page_offset),
                    '_sortKeys': 'timestamp'
                }
    
                headers = {
                    'X-OpenIDM-Username': OPENIDM_USERNAME,
                    'X-OpenIDM-Password': OPENIDM_PASSWORD,
                    'Accept-API-Version': 'resource=1.0',
                    'Accept': 'application/json'
                }
    
                response = http.request('GET', url, fields=params, headers=headers)
                if response.status != 200:
                    print(f"API error for topic {topic}: {response.status}")
                    break
    
                data = json.loads(response.data.decode('utf-8'))
                events = data.get('result', [])
                if not events:
                    break
    
                all_events.extend(events)
                page_offset += PAGE_SIZE
                page_count += 1
                if len(events) < PAGE_SIZE:
                    break
            except Exception as e:
                print(f"Error for topic {topic}: {str(e)}")
                break
        return all_events
    
    def write_to_gcs(bucket, events):
        timestamp = datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')
        filename = f"{GCS_PREFIX}/openidm_audit_{timestamp}.json"
        ndjson_content = '\n'.join([json.dumps(event) for event in events])
        bucket.blob(filename).upload_from_string(ndjson_content, content_type='application/x-ndjson')
    
    • requirements.txt:
    functions-framework==3.*
    google-cloud-storage==2.*
    urllib3>=2.0.0
    
  3. לוחצים על Deploy. הפריסה נמשכת 2-3 דקות.

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

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

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

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

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

בדיקת השילוב

  1. ב-Cloud Scheduler, לוחצים על Force run במשימה.
  2. מאמתים את ההרצה ביומני Cloud Run. מחפשים את: Successfully processed X audit events.
  3. מוודאים שקובץ json חדש קיים בקטגוריה של Cloud Storage בתיקייה openidm/.

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

הגדרת פיד ב-Google SecOps

  1. עוברים אל הגדרות > ניהול נתונים > פידים. אם אתם משתמשים בפלטפורמה של SIEM בלבד, עוברים אל הגדרות > פידים.
  2. לוחצים על הוספת פיד חדש > הגדרת פיד יחיד.
  3. שם הפיד: ForgeRock OpenIDM Audit Logs.
  4. סוג המקור: Google Cloud Storage V2.
  5. סוג היומן: FORGEROCK_OPENIDM.
  6. לוחצים על Get Service Account (קבלת חשבון שירות) ומעתיקים את כתובת האימייל שמופיעה (למשל, chronicle-12345...).
  7. לוחצים על הבא.
  8. כתובת ה-URL של קטגוריית האחסון: gs://forgerock-openidm-audit-logs/openidm/.
  9. אפשרות מחיקת מקור: בוחרים לפי ההעדפה (למשל, אף פעם).
  10. לוחצים על הבא, בודקים את הפרטים ולוחצים על שליחה.

מתן הרשאות IAM

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

טבלת מיפוי UDM

שדה ביומן מיפוי UDM Logic (פונקציה לוגית)
fluenttag_label, topic_label, context_roles_label additional.fields צמדי מפתח/ערך להקשר.
Via intermediary.hostname שם המארח של שרת ה-proxy או הגורם המתווך.
x_forwarded_ip, caller.callerIps intermediary.ip כתובת ה-IP של המתווך.
timestamp metadata.event_timestamp חותמת הזמן של האירוע.
transactionId metadata.product_deployment_id מזהה עסקה ייחודי.
eventName metadata.product_event_type שם האירוע מ-ForgeRock.
_id metadata.product_log_id מזהה יומן ייחודי.
request_method network.http.method שיטת ה-HTTP שבה נעשה שימוש.
response.statusCode network.http.response_code קוד סטטוס של HTTP.
user_agent network.http.user_agent תיאור מלא של סוכן המשתמש.
client.ip, context.ipAddress principal.ip כתובת ה-IP של המקור של המשתמש.
userId, principalData.0 principal.user.userid המזהה של המשתמש שביצע את הפעולה.
security_action security_result.action התקבלה החלטה בנושא אבטחה.
level security_result.severity רמת החומרה הממופה.
server.ip target.ip כתובת ה-IP של מערכת היעד.
http.request.path target.url כתובת URL או נתיב של יעד.
לא רלוונטי metadata.product_name מגדירים את ForgeRock OpenIDM.
לא רלוונטי metadata.vendor_name מגדירים את ForgeRock.
elapsed_time" and "X-Content-Type-Options additional.fields מופה מיומן השינויים
trackingIds.0 metadata.product_log_id מופה מיומן השינויים
context.userRolesProperty", "context.authenticationId", and "context.authenticationIdProperty principal.user.attribute.roles מופה מיומן השינויים
context.component", "context.moduleId", and "context.queryId principal.resource.attribute.labels מופה מיומן השינויים
context.roles", "_normalized.fieldNames", and "_eventId additional.fields מופה מיומן השינויים

יומן שינויים

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

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