איסוף יומנים של File Scanning Framework

גרסת מנתח הנתונים: 3.0

נתמך ב:

במאמר הזה מוסבר איך להטמיע יומנים של File Scanning Framework ב-Google Security Operations באמצעות Google Cloud Storage V2.

File Scanning Framework‏ (FSF) הוא פתרון סריקת קבצים רקורסיבי ומודולרי בקוד פתוח שפותח על ידי Emerson Electric Co. ‏FSF משתמש בארכיטקטורת לקוח-שרת כדי לנתח קבצים וליצור תוצאות סריקה מפורטות בפורמט JSON, כולל מטא-נתונים של קבצים, התאמות של חתימות YARA, אובייקטים משניים שחולצו ומטא-נתונים ספציפיים למודול.

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

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

  • מופע של Google SecOps
  • פרויקט ב-GCP עם Cloud Storage API מופעל
  • הרשאות ליצירה ולניהול של קטגוריות GCS
  • הרשאות לניהול מדיניות IAM בקטגוריות GCS
  • מופע של שרת FSF שנפרס עם גישת כתיבה לספריית היומן
  • גישת רוט (Root) או גישת sudo למארח השרת של FSF

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

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

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

הגדרת ספריית פלט של יומן FSF

FSF כותב את תוצאות הסריקה בפורמט JSON לספריית יומן שניתנת להגדרה. הגדרת ספרייה ייעודית להעברה של נתונים ל-Google SecOps.

  1. מתחברים למארח השרת של FSF באמצעות SSH.
  2. פותחים את קובץ ההגדרות של שרת FSF:

    sudo nano /opt/fsf/fsf-server/conf/config.py
    
  3. מאתרים את המילון SCANNER_CONFIG.

  4. מעדכנים את הפרמטר LOG_PATH לספרייה ייעודית:

    SCANNER_CONFIG = {
        'LOG_PATH': '/var/log/fsf',
        'YARA_PATH': '/opt/fsf/fsf-server/yara/rules.yara',
        'PID_PATH': '/tmp/scanner.pid',
        'EXPORT_PATH': '/tmp',
        'TIMEOUT': 60,
        'MAX_DEPTH': 10
    }
    
  5. שומרים את הקובץ וסוגרים אותו.

  6. יוצרים את ספריית היומן עם ההרשאות המתאימות:

    sudo mkdir -p /var/log/fsf
    sudo chown -R fsf:fsf /var/log/fsf
    sudo chmod 755 /var/log/fsf
    
  7. מפעילים מחדש את שרת ה-FSF כדי להחיל את השינויים:

    sudo systemctl restart fsf
    
  8. מוודאים ש-FSF כותב יומנים לספרייה החדשה:

    ls -lh /var/log/fsf/
    

התקנה והגדרה של Fluentd

‫Fluentd יעקוב אחרי קובצי יומן של FSF ויעביר אותם ל-Google Cloud Storage.

התקנת Fluentd

  1. במארח השרת של FSF, מתקינים את Fluentd‏ (td-agent):

    curl -fsSL https://toolbelt.treasuredata.com/sh/install-ubuntu-jammy-td-agent4.sh | sh
    
  2. מתקינים את פלאגין הפלט של GCS:

    sudo td-agent-gem install fluent-plugin-gcs
    
  3. מאמתים את התקנת הפלאגין:

    td-agent-gem list | grep fluent-plugin-gcs
    

יצירת חשבון שירות ב-GCP עבור Fluentd

  1. במסוף GCP, נכנסים אל IAM & Admin > Service Accounts.
  2. לוחצים על יצירת חשבון שירות.
  3. מזינים את פרטי ההגדרה הבאים:
    • שם חשבון השירות: מזינים fsf-fluentd-shipper.
    • תיאור חשבון השירות: מזינים Service account for Fluentd to ship FSF logs to GCS.
  4. לוחצים על יצירה והמשך.
  5. בקטע Grant this service account access to project (הענקת גישה של חשבון השירות הזה לפרויקט):
    1. לוחצים על בחירת תפקיד.
    2. מחפשים את Storage Object Admin ובוחרים בו.
  6. לוחצים על Continue.
  7. לוחצים על סיום.

יצירת מפתח לחשבון שירות

  1. ברשימה Service Accounts (חשבונות שירות), לוחצים על חשבון השירות (fsf-fluentd-shipper).
  2. עוברים לכרטיסייה Keys.
  3. לוחצים על Add Key > Create new key.
  4. בוחרים באפשרות JSON בתור סוג המפתח.
  5. לוחצים על יצירה.
  6. קובץ ה-JSON עם המפתח יורד למחשב.
  7. מעבירים את קובץ המפתח למארח השרת של FSF:

    scp /path/to/downloaded-key.json user@fsf-server:/etc/td-agent/gcp-key.json
    
  8. מגדירים הרשאות מתאימות בקובץ המפתח:

    sudo chown td-agent:td-agent /etc/td-agent/gcp-key.json
    sudo chmod 600 /etc/td-agent/gcp-key.json
    

מתן הרשאות IAM בקטגוריית GCS

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

הגדרת Fluentd

  1. במארח של שרת FSF, יוצרים קובץ הגדרה של Fluentd:

    sudo nano /etc/td-agent/td-agent.conf
    
  2. מוסיפים את ההגדרה הבאה:

    # Tail FSF JSON logs
    <source>
        @type tail
        path /var/log/fsf/*.log
        pos_file /var/log/td-agent/fsf.log.pos
        tag fsf.scan
        read_from_head true
        <parse>
            @type json
            time_key timestamp
            time_format %Y-%m-%dT%H:%M:%S.%L%z
        </parse>
    </source>
    
    # Ship to Google Cloud Storage
    <match fsf.scan>
        @type gcs
        project YOUR_GCP_PROJECT_ID
        keyfile /etc/td-agent/gcp-key.json
        bucket fsf-logs-secops
        object_key_format %{path}%{time_slice}_%{index}.%{file_extension}
        path fsf-logs/
        <buffer tag,time>
            @type file
            path /var/log/td-agent/buffer/gcs
            timekey 3600
            timekey_wait 10m
            timekey_use_utc true
            chunk_limit_size 10MB
        </buffer>
        <format>
            @type json
        </format>
        store_as json
        auto_create_bucket false
    </match>
    
  3. מחליפים את YOUR_GCP_PROJECT_ID במזהה הפרויקט בפועל ב-GCP.

  4. שומרים את הקובץ וסוגרים אותו.

  5. יוצרים את ספריית המאגר:

    sudo mkdir -p /var/log/td-agent/buffer/gcs
    sudo chown -R td-agent:td-agent /var/log/td-agent/buffer
    
  6. מפעילים מחדש את Fluentd כדי להחיל את ההגדרה:

    sudo systemctl restart td-agent
    
  7. מפעילים את Fluentd כדי להתחיל בהפעלה:

    sudo systemctl enable td-agent
    
  8. מוודאים ש-Fluentd פועל:

    sudo systemctl status td-agent
    

אימות של העברת יומנים

  1. בודקים אם יש שגיאות ביומני Fluentd:

    sudo tail -f /var/log/td-agent/td-agent.log
    
  2. מפעילים סריקת FSF לצורך בדיקה כדי ליצור יומנים:

    echo "test content" > /tmp/test.txt
    /opt/fsf/fsf-client/fsf_client.py /tmp/test.txt --suppress-report
    
  3. ממתינים דקה או שתיים עד ש-Fluentd יעבד את היומנים וישלח אותם.

  4. ב-GCP Console, עוברים אל Cloud Storage > Buckets.

  5. לוחצים על שם הקטגוריה (fsf-logs-secops).

  6. עוברים לקידומת fsf-logs/.

  7. מוודאים שקובצי ה-JSON נוצרים עם חותמות זמן.

  8. מורידים קובץ ובודקים שהוא מכיל תוצאות סריקה של FSF בפורמט JSON.

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

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

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

  1. עוברים אל SIEM Settings > Feeds (הגדרות SIEM > פידים).
  2. לוחצים על הוספת פיד חדש.
  3. לוחצים על הגדרת פיד יחיד.
  4. בשדה שם הפיד, מזינים שם לפיד (לדוגמה, FSF File Scanning Logs).
  5. בוחרים באפשרות Google Cloud Storage V2 בתור סוג המקור.
  6. בוחרים באפשרות File Scanning Framework (מסגרת לסריקת קבצים) בתור סוג היומן.
  7. לוחצים על Get Service Account (קבלת חשבון שירות). תוצג כתובת האימייל בחשבון שירות ייחודי, לדוגמה:

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

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

  10. מציינים ערכים לפרמטרים הבאים של הקלט:

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

      gs://fsf-logs-secops/fsf-logs/
      
    • אפשרות למחיקת המקור: בוחרים את אפשרות המחיקה לפי ההעדפה שלכם:

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

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

    • מרחב השמות של הנכס: מרחב השמות של הנכס.

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

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

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

הענקת הרשאות IAM לחשבון השירות של Google SecOps

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

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

אימות ההטמעה

  1. ממתינים 10-15 דקות עד שההטמעה הראשונית תושלם.
  2. ב-Google SecOps, עוברים אל SIEM Settings > Feeds.
  3. מאתרים את הפיד (FSF File Scanning Logs).
  4. מוודאים שהסטטוס הוא פעיל.
  5. לוחצים על שם הפיד כדי לראות את מדדי ההטמעה.
  6. בודקים שהמספר של האירועים שהועברו עולה.
  7. עוברים אל חיפוש ב-Google SecOps.
  8. מריצים שאילתת חיפוש כדי לוודא שיומני FSF נקלטו:

    metadata.log_type = "FILE_SCANNING_FRAMEWORK"
    
  9. מוודאים שתוצאות הסריקה של FSF מופיעות בתוצאות החיפוש.

פתרון בעיות

לא מופיעים יומנים ב-GCS

  • בודקים ש-FSF כותב יומנים אל /var/log/fsf/:

    ls -lh /var/log/fsf/
    tail -f /var/log/fsf/*.log
    
  • בודקים אם יש שגיאות ביומני Fluentd:

    sudo tail -f /var/log/td-agent/td-agent.log
    
  • מוודאים שמפתח חשבון השירות ב-GCP תקין ושיש לו את ההרשאות הנכונות.

  • מוודאים ששם הקטגוריה בהגדרת Fluentd זהה לשם הקטגוריה בפועל.

שגיאות הרשאה ב-Fluentd

  • מוודאים שלחשבון השירות (fsf-fluentd-shipper) יש את התפקיד אדמין של אובייקטים באחסון בקטגוריה.
  • בודקים שנתיב המפתח בהגדרות של Fluentd נכון.
  • מוודאים שלקובץ המפתח יש בעלות והרשאות נכונות:

    ls -l /etc/td-agent/gcp-key.json
    

יומנים לא מוטמעים ב-Google SecOps

  • מוודאים שלחשבון השירות של Google SecOps יש את התפקיד צפייה באובייקט אחסון בקטע.
  • בודקים שערך ה-URI של מאגר הנתונים בהגדרות הפיד נכון וכולל את קו הנטוי בסוף.
  • מוודאים שהקבצים קיימים בקטגוריה ב-GCS בנתיב הקידומת שצוין.
  • בודקים את סטטוס הפיד בהגדרות SIEM > פידים כדי לראות אם יש הודעות שגיאה.

יומני FSF לא בפורמט הצפוי

  • מוודאים ש-FSF מוגדר לכתוב פלט JSON (התנהגות ברירת המחדל).
  • בודקים שהקטע <parse> של Fluentd מוגדר עם @type json.
  • בודקים קובץ יומן באופן ידני כדי לוודא שהוא מכיל JSON תקין:

    head -n 1 /var/log/fsf/*.log | jq .
    

טבלת מיפוי UDM

שדה ביומן מיפוי UDM לוגיקה
CompressType_label, compressed_parents about.labels מוזגו מ-CompressType_label (מפתח Compress Type, ערך מ-Object.EXTRACT_ZIP.Object_0.Compress Type אם ההודעה מכילה Compress Type) ומ-compressed_parents (מפתח Compressed Parent Files, שרשור מ-Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.additional_info.compressed_parents)
Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.MD5, Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.MD5, Object.EXTRACT_SWF.META_BASIC_INFO.MD5, Object.EXTRACT_GZIP.META_BASIC_INFO.MD5, Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.MD5 intermediary.file.md5 הערך מ-Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.MD5 אם EXTRACT_EMBEDDED קיים, אחרת הערך מ-Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.MD5 אם EXTRACT_ZIP קיים, אחרת הערך מ-Object.EXTRACT_SWF.META_BASIC_INFO.MD5 אם EXTRACT_SWF קיים, אחרת הערך מ-Object.EXTRACT_GZIP.META_BASIC_INFO.MD5 אם EXTRACT_GZIP קיים, אחרת הערך מ-Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.MD5
Object.EXTRACT_EMBEDDED.Object_0.Description intermediary.file.mime_type הערך הועתק ישירות
Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.SHA1, Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.SHA1, Object.EXTRACT_SWF.META_BASIC_INFO.SHA1, Object.EXTRACT_GZIP.META_BASIC_INFO.SHA1, Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.SHA1 intermediary.file.sha1 הערך מ-Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.SHA1 אם EXTRACT_EMBEDDED קיים, אחרת הערך מ-Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.SHA1 אם EXTRACT_ZIP קיים, אחרת הערך מ-Object.EXTRACT_SWF.META_BASIC_INFO.SHA1 אם EXTRACT_SWF קיים, אחרת הערך מ-Object.EXTRACT_GZIP.META_BASIC_INFO.SHA1 אם EXTRACT_GZIP קיים, אחרת הערך מ-Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.SHA1
Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.SHA256, Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.SHA256, Object.EXTRACT_SWF.META_BASIC_INFO.SHA256, Object.EXTRACT_GZIP.META_BASIC_INFO.SHA256, Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.SHA256 intermediary.file.sha256 הערך מ-Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.SHA256 אם EXTRACT_EMBEDDED קיים, אחרת הערך מ-Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.SHA256 אם EXTRACT_ZIP קיים, אחרת הערך מ-Object.EXTRACT_SWF.META_BASIC_INFO.SHA256 אם EXTRACT_SWF קיים, אחרת הערך מ-Object.EXTRACT_GZIP.META_BASIC_INFO.SHA256 אם EXTRACT_GZIP קיים, אחרת הערך מ-Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.SHA256
Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.Size, Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.Size, Object.EXTRACT_SWF.META_BASIC_INFO.Size, Object.EXTRACT_GZIP.META_BASIC_INFO.Size, Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.Size, intermediary.file.size הערך מ-Object.EXTRACT_EMBEDDED.Object_0.META_BASIC_INFO.Size אם EXTRACT_EMBEDDED קיים, אחרת הערך מ-Object.EXTRACT_ZIP.Object_0.META_BASIC_INFO.Size אם EXTRACT_ZIP קיים, אחרת הערך מ-Object.EXTRACT_SWF.META_BASIC_INFO.Size אם EXTRACT_SWF קיים, אחרת הערך מ-Object.EXTRACT_GZIP.META_BASIC_INFO.Size אם EXTRACT_GZIP קיים, אחרת הערך מ-Object.EXTRACT_CAB.Object_0.META_BASIC_INFO.Size. הערך הזה נלקח אחרי הסרת התו .*‎ בסוף והמרה למספר שלם לא שלילי.
Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.scan_id intermediary.resource.id הערך הועתק ישירות
Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.permalink intermediary.url הערך הועתק ישירות
Object.META_EMERSON_INFO.results intermediary.user.email_addresses מוזג מ-matched_email במערך התוצאות
Summary.Observations metadata.description המחרוזת נוצרה מאיחוד של רכיבי מערך עם פסיק ורווח כמפריד, והפסיק הראשון הוסר
זמן הסריקה metadata.event_timestamp ההמרה בוצעה באמצעות מסנן תאריכים בפורמט yyyy-MM-dd HH:mm:ss
מקור metadata.event_type הערך הוא SCAN_FILE אם המקור לא ריק, אחרת GENERIC_EVENT
Object.META_VT_CACHE._id metadata.product_log_id הערך הועתק ישירות
result.ad_data.message network.http.response_code הערך חולץ כמספר שלם באמצעות תבנית grok ‏INT מהתוצאה result.ad_data.message
מקור principal.hostname הערך הועתק ישירות
Object.META_EMERSON_INFO.result_summary, Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.verbose_msg security_result.summary מוגדר ל-Object.META_EMERSON_INFO.result_summary אם הוא קיים, אחרת ל-Object.EXTRACT_ZIP.Object_0.META_VT_CACHE.vt_data.verbose_msg
שם קובץ target.file.full_path הערך הועתק ישירות
Object.META_BASIC_INFO.MD5 target.file.md5 הערך הועתק ישירות
Summary.Yara target.file.mime_type הערך מחולץ מהאינדקס הראשון של Summary.Yara, מומר לאותיות רישיות ומוסר ממנו הערך FT_ אם Yara קיים, אחרת הערך מוגדר כ-ZIP אם EXTRACT_ZIP קיים, כ-SWF אם EXTRACT_SWF קיים, כ-GZIP אם EXTRACT_GZIP קיים, כ-CAB אם EXTRACT_CAB קיים
Object.META_BASIC_INFO.SHA1, Object.META_VT_CACHE.SHA1 target.file.sha1 ערך מ-Object.META_BASIC_INFO.SHA1 אם הוא לא ריק, אחרת מ-Object.META_VT_CACHE.SHA1
Object.META_BASIC_INFO.SHA256 target.file.sha256 הערך הועתק ישירות
Object.META_BASIC_INFO.Size target.file.size הוסר הערך " .*" בסוף והומר ל-uinteger
metadata.vendor_name הוגדר כ-EMERSON
metadata.product_name ההגדרה היא FILE SCANNING FRAMEWORK (מסגרת לסריקת קבצים)

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