איסוף יומנים של 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
- נכנסים אל מסוף Google Cloud.
- בוחרים פרויקט או יוצרים פרויקט חדש.
- בתפריט הניווט, עוברים אל Cloud Storage > Buckets.
- לוחצים על Create bucket.
מזינים את פרטי ההגדרה הבאים:
הגדרה ערך Name your bucket (שם הקטגוריה) מזינים שם ייחודי בעולם (לדוגמה, fsf-logs-secops).סוג מיקום בוחרים לפי הצרכים שלכם (אזור, שני אזורים, כמה אזורים). Location בוחרים את המיקום (לדוגמה, us-central1).סוג אחסון (storage class) רגיל (מומלץ ליומנים שניגשים אליהם לעיתים קרובות). בקרת גישה אחיד (מומלץ). כלים להגנה אופציונלי: הפעלת ניהול גרסאות של אובייקטים או מדיניות שמירת נתונים. לוחצים על יצירה.
הגדרת ספריית פלט של יומן FSF
FSF כותב את תוצאות הסריקה בפורמט JSON לספריית יומן שניתנת להגדרה. הגדרת ספרייה ייעודית להעברה של נתונים ל-Google SecOps.
- מתחברים למארח השרת של FSF באמצעות SSH.
פותחים את קובץ ההגדרות של שרת FSF:
sudo nano /opt/fsf/fsf-server/conf/config.pyמאתרים את המילון
SCANNER_CONFIG.מעדכנים את הפרמטר
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 }שומרים את הקובץ וסוגרים אותו.
יוצרים את ספריית היומן עם ההרשאות המתאימות:
sudo mkdir -p /var/log/fsf sudo chown -R fsf:fsf /var/log/fsf sudo chmod 755 /var/log/fsfמפעילים מחדש את שרת ה-FSF כדי להחיל את השינויים:
sudo systemctl restart fsfמוודאים ש-FSF כותב יומנים לספרייה החדשה:
ls -lh /var/log/fsf/
התקנה והגדרה של Fluentd
Fluentd יעקוב אחרי קובצי יומן של FSF ויעביר אותם ל-Google Cloud Storage.
התקנת Fluentd
במארח השרת של FSF, מתקינים את Fluentd (td-agent):
curl -fsSL https://toolbelt.treasuredata.com/sh/install-ubuntu-jammy-td-agent4.sh | shמתקינים את פלאגין הפלט של GCS:
sudo td-agent-gem install fluent-plugin-gcsמאמתים את התקנת הפלאגין:
td-agent-gem list | grep fluent-plugin-gcs
יצירת חשבון שירות ב-GCP עבור Fluentd
- במסוף GCP, נכנסים אל IAM & Admin > Service Accounts.
- לוחצים על יצירת חשבון שירות.
- מזינים את פרטי ההגדרה הבאים:
- שם חשבון השירות: מזינים
fsf-fluentd-shipper. - תיאור חשבון השירות: מזינים
Service account for Fluentd to ship FSF logs to GCS.
- שם חשבון השירות: מזינים
- לוחצים על יצירה והמשך.
- בקטע Grant this service account access to project (הענקת גישה של חשבון השירות הזה לפרויקט):
- לוחצים על בחירת תפקיד.
- מחפשים את Storage Object Admin ובוחרים בו.
- לוחצים על Continue.
- לוחצים על סיום.
יצירת מפתח לחשבון שירות
- ברשימה Service Accounts (חשבונות שירות), לוחצים על חשבון השירות (
fsf-fluentd-shipper). - עוברים לכרטיסייה Keys.
- לוחצים על Add Key > Create new key.
- בוחרים באפשרות JSON בתור סוג המפתח.
- לוחצים על יצירה.
- קובץ ה-JSON עם המפתח יורד למחשב.
מעבירים את קובץ המפתח למארח השרת של FSF:
scp /path/to/downloaded-key.json user@fsf-server:/etc/td-agent/gcp-key.jsonמגדירים הרשאות מתאימות בקובץ המפתח:
sudo chown td-agent:td-agent /etc/td-agent/gcp-key.json sudo chmod 600 /etc/td-agent/gcp-key.json
מתן הרשאות IAM בקטגוריית GCS
- נכנסים אל Cloud Storage > Buckets (קטגוריות).
- לוחצים על שם הקטגוריה (
fsf-logs-secops). - עוברים לכרטיסייה Permissions.
- לוחצים על הענקת גישה.
- מזינים את פרטי ההגדרה הבאים:
- Add principals (הוספת ישויות מורשות): מזינים את כתובת האימייל בחשבון השירות (לדוגמה,
fsf-fluentd-shipper@PROJECT_ID.iam.gserviceaccount.com). - הקצאת תפקידים: בוחרים באפשרות אדמין של אובייקטים באחסון.
- Add principals (הוספת ישויות מורשות): מזינים את כתובת האימייל בחשבון השירות (לדוגמה,
- לוחצים על Save.
הגדרת Fluentd
במארח של שרת FSF, יוצרים קובץ הגדרה של Fluentd:
sudo nano /etc/td-agent/td-agent.confמוסיפים את ההגדרה הבאה:
# 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>מחליפים את
YOUR_GCP_PROJECT_IDבמזהה הפרויקט בפועל ב-GCP.שומרים את הקובץ וסוגרים אותו.
יוצרים את ספריית המאגר:
sudo mkdir -p /var/log/td-agent/buffer/gcs sudo chown -R td-agent:td-agent /var/log/td-agent/bufferמפעילים מחדש את Fluentd כדי להחיל את ההגדרה:
sudo systemctl restart td-agentמפעילים את Fluentd כדי להתחיל בהפעלה:
sudo systemctl enable td-agentמוודאים ש-Fluentd פועל:
sudo systemctl status td-agent
אימות של העברת יומנים
בודקים אם יש שגיאות ביומני Fluentd:
sudo tail -f /var/log/td-agent/td-agent.logמפעילים סריקת FSF לצורך בדיקה כדי ליצור יומנים:
echo "test content" > /tmp/test.txt /opt/fsf/fsf-client/fsf_client.py /tmp/test.txt --suppress-reportממתינים דקה או שתיים עד ש-Fluentd יעבד את היומנים וישלח אותם.
ב-GCP Console, עוברים אל Cloud Storage > Buckets.
לוחצים על שם הקטגוריה (
fsf-logs-secops).עוברים לקידומת
fsf-logs/.מוודאים שקובצי ה-JSON נוצרים עם חותמות זמן.
מורידים קובץ ובודקים שהוא מכיל תוצאות סריקה של FSF בפורמט JSON.
אחזור חשבון השירות של Google SecOps
Google SecOps משתמש בחשבון שירות ייחודי כדי לקרוא נתונים ממאגר GCS שלכם. צריך להעניק לחשבון השירות הזה גישה לדלי.
קבלת כתובת האימייל בחשבון השירות
- עוברים אל SIEM Settings > Feeds (הגדרות SIEM > פידים).
- לוחצים על הוספת פיד חדש.
- לוחצים על הגדרת פיד יחיד.
- בשדה שם הפיד, מזינים שם לפיד (לדוגמה,
FSF File Scanning Logs). - בוחרים באפשרות Google Cloud Storage V2 בתור סוג המקור.
- בוחרים באפשרות File Scanning Framework (מסגרת לסריקת קבצים) בתור סוג היומן.
לוחצים על Get Service Account (קבלת חשבון שירות). תוצג כתובת האימייל בחשבון שירות ייחודי, לדוגמה:
secops-12345678@secops-gcp-prod.iam.gserviceaccount.comמעתיקים את כתובת האימייל לשימוש בשלב הבא.
לוחצים על הבא.
מציינים ערכים לפרמטרים הבאים של הקלט:
כתובת ה-URL של קטגוריית האחסון: מזינים את ה-URI של קטגוריית GCS עם נתיב הקידומת:
gs://fsf-logs-secops/fsf-logs/אפשרות למחיקת המקור: בוחרים את אפשרות המחיקה לפי ההעדפה שלכם:
- אף פעם: לא נמחקים קבצים אחרי ההעברה (מומלץ לבדיקות).
- מחיקת קבצים שהועברו: הקבצים נמחקים אחרי שההעברה מסתיימת בהצלחה.
מחיקת קבצים שהועברו וספריות ריקות: מחיקת קבצים וספריות ריקות אחרי שההעברה מסתיימת בהצלחה.
הגיל המקסימלי של הקובץ: כולל קבצים ששונו במספר הימים האחרון (ברירת המחדל היא 180 ימים).
מרחב השמות של הנכס: מרחב השמות של הנכס.
תוויות להוספה: התווית שתתווסף לאירועים מהפיד הזה.
לוחצים על הבא.
בודקים את ההגדרות של הפיד החדש במסך סיום ולוחצים על שליחה.
הענקת הרשאות IAM לחשבון השירות של Google SecOps
לחשבון השירות של Google SecOps צריך להיות התפקיד צפייה באובייקט אחסון בקטגוריית GCS.
- נכנסים אל Cloud Storage > Buckets (קטגוריות).
- לוחצים על שם הקטגוריה (
fsf-logs-secops). - עוברים לכרטיסייה Permissions.
- לוחצים על הענקת גישה.
- מזינים את פרטי ההגדרה הבאים:
- Add principals (הוספת ישויות מורשות): מדביקים את כתובת האימייל בחשבון של חשבון השירות של Google SecOps.
- הקצאת תפקידים: בוחרים באפשרות צפייה באובייקט אחסון.
- לוחצים על Save.
אימות ההטמעה
- ממתינים 10-15 דקות עד שההטמעה הראשונית תושלם.
- ב-Google SecOps, עוברים אל SIEM Settings > Feeds.
- מאתרים את הפיד (
FSF File Scanning Logs). - מוודאים שהסטטוס הוא פעיל.
- לוחצים על שם הפיד כדי לראות את מדדי ההטמעה.
- בודקים שהמספר של האירועים שהועברו עולה.
- עוברים אל חיפוש ב-Google SecOps.
מריצים שאילתת חיפוש כדי לוודא שיומני FSF נקלטו:
metadata.log_type = "FILE_SCANNING_FRAMEWORK"מוודאים שתוצאות הסריקה של 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.