איסוף יומנים של Google App Engine
גרסת מנתח הנתונים: 3.0
במאמר הזה מוסבר איך להטמיע יומנים של Google App Engine ב-Google Security Operations באמצעות Google Cloud Storage V2.
Google App Engine היא פלטפורמה מנוהלת ללא שרת (serverless) לבנייה ולפריסה של אפליקציות אינטרנט וממשקי API. App Engine יוצר באופן אוטומטי יומני בקשות לבקשות HTTP ויומני אפליקציות מהקוד שלכם. היומנים האלה נשלחים אל Cloud Logging ואפשר לייצא אותם אל Cloud Storage לצורך הטמעה ב-Google Security Operations.
לפני שמתחילים
חשוב לוודא שמתקיימות דרישות הסף הבאות:
- מופע של Google SecOps
- פרויקט ב-GCP עם Cloud Storage API מופעל
- הרשאות ליצירה ולניהול של קטגוריות GCS
- הרשאות לניהול מדיניות IAM בקטגוריות GCS
- הרשאות ליצירת sinks ב-Cloud Logging (roles/logging.configWriter)
- אפליקציית App Engine פעילה (סביבה רגילה או גמישה)
יצירת קטגוריה של Google Cloud Storage
- נכנסים אל מסוף Google Cloud.
- בוחרים פרויקט או יוצרים פרויקט חדש.
- בתפריט הניווט, עוברים אל Cloud Storage > Buckets.
- לוחצים על Create bucket.
מזינים את פרטי ההגדרה הבאים:
הגדרה ערך Name your bucket (שם הקטגוריה) מזינים שם ייחודי גלובלית (לדוגמה, appengine-logs-export)סוג מיקום בוחרים לפי הצרכים שלכם (אזור, בשני אזורים, במספר אזורים) Location בוחרים את המיקום (לדוגמה, us-central1).סוג אחסון (storage class) רגיל (מומלץ ליומנים שמתבצעת אליהם גישה לעיתים קרובות) בקרת גישה אחיד (מומלץ) כלים להגנה אופציונלי: הפעלת ניהול גרסאות של אובייקטים או מדיניות שמירת נתונים לוחצים על יצירה.
הגדרת Cloud Logging לייצוא יומנים של App Engine ל-GCS
שירות Cloud Logging משתמש ביעדי יומן כדי לנתב רשומות ביומן ליעדים נתמכים, כולל קטגוריות של Cloud Storage. לזהות הכותב של יעד הנתונים נדרש התפקיד 'יצירת אובייקטים של אחסון' (roles/storage.objectCreator) בקטגוריית היעד.
יצירת יעד ב-Cloud Logging
- ב-מסוף Google Cloud, עוברים אל רישום ביומן > Log Router.
- לוחצים על Create sink (יצירת יעד).
- מזינים את פרטי ההגדרה הבאים:
- שם יעד: מזינים שם תיאורי (לדוגמה,
appengine-to-gcs). - תיאור של יעד: תיאור אופציונלי.
- שם יעד: מזינים שם תיאורי (לדוגמה,
- לוחצים על הבא.
- בקטע Select sink service (בחירת שירות יעד):
- שירות היעד: בוחרים באפשרות קטגוריה של Cloud Storage.
- בחירת קטגוריית אחסון של Cloud Storage: בוחרים באפשרות
appengine-logs-exportמהתפריט הנפתח.
- לוחצים על הבא.
בקטע Choose logs to include in sink, מזינים שאילתת סינון כדי לבחור יומנים של App Engine. סוג המשאב חייב להיות בדיוק gae_app.
לכל היומנים של App Engine (יומני בקשות ויומני אפליקציות):
resource.type="gae_app"רק לגבי יומני בקשות של App Engine:
resource.type="gae_app" logName="projects/PROJECT_ID/logs/appengine.googleapis.com/request_log"עבור יומנים של אפליקציות App Engine (stdout/stderr):
resource.type="gae_app" (logName="projects/PROJECT_ID/logs/stdout" OR logName="projects/PROJECT_ID/logs/stderr")מחליפים את
PROJECT_IDבמזהה הפרויקט ב-GCP.לוחצים על הבא.
בודקים את ההגדרות ולוחצים על Create sink.
מתן הרשאות לזהות של כלי הכתיבה ליעד
אחרי שיוצרים את יעד ההעברה, צריך להקצות לזהות הכתיבה של יעד ההעברה את התפקיד 'יצירת אובייקטים של אחסון' בקטגוריית היעד. הזהות של בעל הרשאת כתיבה עבור חשבון השירות נראית בערך כך: serviceAccount:service-123456789012@gcp-sa-logging.iam.gserviceaccount.com
- בדף Log Router, מאתרים את היעד החדש שנוצר.
- לוחצים על סמל התפריט (שלוש נקודות אנכיות) לצד שם היעד.
- בוחרים באפשרות הצגת פרטים של יעד.
- מעתיקים את הזהות של הכותב (כתובת האימייל של חשבון השירות).
- נכנסים אל Cloud Storage > Buckets (קטגוריות).
- לוחצים על שם הקטגוריה (
appengine-logs-export). - עוברים לכרטיסייה Permissions.
- לוחצים על הענקת גישה.
- מזינים את פרטי ההגדרה הבאים:
- הוספת חשבונות משתמשים: מדביקים את זהות הכתיבה של יעד הסינכרון (כתובת האימייל של חשבון השירות).
- הקצאת תפקידים: בוחרים באפשרות יצירת אובייקטים של אחסון.
- לוחצים על Save.
אחזור חשבון השירות של Google SecOps
Google SecOps משתמש בחשבון שירות ייחודי כדי לקרוא נתונים ממאגר GCS שלכם. צריך להעניק לחשבון השירות הזה גישה לדלי.
הגדרת פיד ב-Google SecOps להזנת יומנים של App Engine
- עוברים אל SIEM Settings > Feeds (הגדרות SIEM > פידים).
- לוחצים על הוספת פיד חדש.
- לוחצים על הגדרת פיד יחיד.
- בשדה שם הפיד, מזינים שם לפיד (לדוגמה,
App Engine Logs). - בוחרים באפשרות Google Cloud Storage V2 בתור סוג המקור.
בוחרים באפשרות GCP_APP_ENGINE בתור סוג היומן.
לוחצים על Get Service Account (קבלת חשבון שירות).
תוצג כתובת האימייל בחשבון שירות ייחודי, לדוגמה:
chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.comמעתיקים את כתובת האימייל הזו. תשתמשו בו בשלב הבא.
לוחצים על הבא.
מציינים ערכים לפרמטרים הבאים של הקלט:
כתובת ה-URL של קטגוריית האחסון: מזינים את ה-URI של קטגוריית GCS עם נתיב הקידומת:
gs://appengine-logs-export/ב-Cloud Logging, קובצי יומן מיוצאים מאורגנים בהיררכיות של ספריות לפי סוג היומן והתאריך. סוג היומן יכול להיות שם מורכב כמו appengine.googleapis.com/request_log. הקבצים מחולקים לשברי קבצים (shard) והשם שלהם כולל תקופות זמן (לדוגמה, 08:00:00_08:59:59_S0.json).
אפשרות למחיקת המקור: בוחרים את אפשרות המחיקה לפי ההעדפה שלכם:
- אף פעם: לא נמחקים קבצים אחרי ההעברה (מומלץ לבדיקות).
- מחיקת קבצים שהועברו: הקבצים נמחקים אחרי שההעברה מסתיימת בהצלחה.
- מחיקת קבצים שהועברו וספריות ריקות: מחיקת קבצים וספריות ריקות אחרי שההעברה מסתיימת בהצלחה.
הגיל המקסימלי של הקובץ: כולל קבצים שעברו שינוי במספר הימים האחרון. ברירת המחדל היא 180 ימים.
מרחב השמות של הנכס: מרחב השמות של הנכס.
תוויות להוספה: התווית שתתווסף לאירועים מהפיד הזה.
לוחצים על הבא.
בודקים את ההגדרות של הפיד החדש במסך סיום ולוחצים על שליחה.
הענקת הרשאות IAM לחשבון השירות של Google SecOps
לחשבון השירות של Google SecOps צריך להיות התפקיד צפייה באובייקט אחסון בקטגוריית GCS.
- נכנסים אל Cloud Storage > Buckets (קטגוריות).
- לוחצים על שם הקטגוריה (
appengine-logs-export). - עוברים לכרטיסייה Permissions.
- לוחצים על הענקת גישה.
- מזינים את פרטי ההגדרה הבאים:
- Add principals (הוספת ישויות מורשות): מדביקים את כתובת האימייל בחשבון של חשבון השירות של Google SecOps.
- הקצאת תפקידים: בוחרים באפשרות צפייה באובייקט אחסון.
לוחצים על Save.
הסבר על מבנה היומנים ב-App Engine
App Engine שולח אוטומטית את יומני הבקשות ואת יומני האפליקציות אל Cloud Logging. App Engine מפיק באופן אוטומטי יומנים של בקשות שנשלחות לאפליקציה, כך שאין צורך לכתוב יומנים של בקשות. בקטע הזה מוסבר איך לכתוב יומני רישום של אפליקציות.
ביומני הבקשות של App Engine יש רשומות ביומן שמכילות שדות protoPayload שמחזיקים אובייקטים מסוג RequestLog עם @type 'type.googleapis.com/google.appengine.logging.v1.RequestLog'. סוג המשאב הוא gae_app.
כברירת מחדל, מטען היומן הוא מחרוזת טקסט שמאוחסנת בשדה textPayload של רשומת היומן. המחרוזות מופיעות כהודעות ב-Logs Explorer והן משויכות לשירות ולגרסה של App Engine שפלטו אותן.
כדי לכתוב יומנים מובנים, כותבים יומנים בצורה של שורה אחת של JSON שעבר סריאליזציה. כשמספקים יומן מובנה כמילון JSON, חלק מהשדות המיוחדים מוסרים מה-jsonPayload ונכתבים בשדה המתאים ב-LogEntry שנוצר. לדוגמה, אם קובץ ה-JSON כולל מאפיין חומרה, הוא מוסר מה-jsonPayload ומופיע במקום זאת כחומרה של רשומת היומן.
מגבלות ידועות
כשמנתבים יומנים מ-sink ביומן ל-Cloud Storage, יעד Cloud Storage מכיל רק יומני בקשות. App Engine כותב יומנים של אפליקציות לתיקיות שונות.
רשומות ביומן שמועברות לניתוב נשמרות בקטגוריות של Cloud Storage בקבוצות של שעה. יכול להיות שיחלפו שעתיים או שלוש עד שהרשומות הראשונות יתחילו להופיע.
בסביבה הגמישה של App Engine, הרישום מתבצע באופן אוטומטי. עם זאת, היומנים נאספים בפורמט אחר. הרישומים לא יצורפו לבקשות, והרישומים מ-stdout ומ-stderr נאספים בנפרד.
טבלת מיפוי UDM
| שדה ביומן | מיפוי UDM | לוגיקה |
|---|---|---|
| jsonPayload.logger, taskTypeName, jsonPayload.@type, jsonPayload.backendTargetProjectNumber, jsonPayload.cacheDecision, resource.labels.version_id, resource.labels.module_id, logName, spanId, trace, protoPayload.@type, labels.clone_id, operation.producer | additional.fields | המיזוג עם תוויות של צמדי מפתח/ערך שנוצרו מכל שדה |
| מטא-נתונים | מטא-נתונים | שינוי שם ממטא-נתונים |
| receiveTimestamp | metadata.collected_timestamp | ניתוח באמצעות מסנן התאריכים עם RFC 3339 |
| metadata.event_type | הערך הוא USER_LOGIN אם has_principal, has_target, has_principal_user; NETWORK_CONNECTION אם has_principal ו-has_target; USER_UNCATEGORIZED אם לא has_principal ו-has_target; STATUS_UPDATE אם has_principal; USER_UNCATEGORIZED אם has_principal_user; אחרת, הערך הוא GENERIC_EVENT. | |
| metadata.extensions.auth.type | מגדירים את הערך AUTHTYPE_UNSPECIFIED אם המאפיינים has_principal, has_target ו-has_principal_user מוגדרים | |
| insertId | metadata.product_log_id | הערך הועתק ישירות |
| httpRequest.requestMethod,protoPayload.method | network.http.method | הערך מ-httpRequest.requestMethod אם הוא לא ריק, אחרת הערך מ-protoPayload.method |
| httpRequest.userAgent | network.http.parsed_user_agent | בוצעה המרה ל-parseduseragent |
| httpRequest.status | network.http.response_code | הומר למחרוזת ואז למספר שלם |
| httpRequest.userAgent | network.http.user_agent | הערך הועתק ישירות |
| httpRequest.responseSize | network.received_bytes | הומר ל-uinteger |
| httpRequest.requestSize | network.sent_bytes | הומר ל-uinteger |
| משתמש (principal) | משתמש (principal) | השם שונה מ-principal אם הוא לא ריק |
| protoPayload.host | principal.asset.hostname | הערך הועתק ישירות |
| httpRequest.serverIp, protoPayload.ip | principal.asset.ip | מוזג עם server_ip מ-httpRequest.serverIp או מ-protoPayload.ip |
| protoPayload.host | principal.hostname | הערך הועתק ישירות |
| httpRequest.serverIp, protoPayload.ip | principal.ip | מוזג עם server_ip מ-httpRequest.serverIp או מ-protoPayload.ip |
| protoPayload.appId | principal.resource.attribute.labels | מוזג עם appId_label שמכיל את המפתח appId ואת הערך מהשדה |
| requestUser | principal.user.email_addresses | המיזוג עם requestUser מתבצע אם יש התאמה לדפוס האימייל |
| security_result | security_result | התוצאות ממוזגות מ-security_result |
| resource.labels.forwarding_rule_name | security_result.rule_labels | מוזג עם rule_label שמכיל את המפתח forwarding_rule_name ואת הערך מהשדה |
| severity | security_result.severity | הערך מוגדר כ-severity אם יש התאמה ל-(?i)ERROR|CRITICAL, INFORMATIONAL אם יש התאמה ל-(?i)INFO, MEDIUM אם יש התאמה ל-(?i)WARN, LOW אם יש התאמה ל-(?i)DEBUG, אחרת UNKNOWN_SEVERITY |
| jsonPayload.statusDetails | security_result.summary | הערך הועתק ישירות |
| יעד | יעד | השם שונה מהשם של היעד אם הוא לא ריק |
| resource.labels.backend_service_name | target.application | הערך הועתק ישירות |
| httpRequest.remoteIp, jsonPayload.remoteIp | target.asset.ip | מוזג עם remote_ip שחולץ מ-httpRequest.remoteIp או מ-jsonPayload.remoteIp |
| resource.labels.project_id | target.cloud.project.name | הערך הועתק ישירות |
| httpRequest.remoteIp, jsonPayload.remoteIp | target.ip | מוזג עם remote_ip שחולץ מ-httpRequest.remoteIp או מ-jsonPayload.remoteIp |
| resource.labels.zone | target.resource.attribute.cloud.availability_zone | הערך הועתק ישירות |
| resource.labels.target_proxy_name, resource.labels.url_map_name | target.resource.attribute.labels | מיזוג עם תוויות מכל מקור |
| resource.type | target.resource.type | הערך הועתק ישירות |
| httpRequest.requestUrl | target.url | הערך הועתק ישירות |
| metadata.product_name | הערך שמוגדר הוא GCP_APP_ENGINE | |
| metadata.vendor_name | הגדרה כ-GCP | |
protoPayload.requestMetadata.callerIp |
event.idm.read_only_udm.principal.ip |
מופה מיומן השינויים |
protoPayload.requestMetadata.callerIp |
event.idm.read_only_udm.principal.asset.ip |
מופה מיומן השינויים |
protoPayload.authenticationInfo.principalEmail |
event.idm.read_only_udm.principal.user.email_addresses |
מופה מיומן השינויים |
protoPayload.methodName |
event.idm.read_only_udm.metadata.product_event_type |
מופה מיומן השינויים |
protoPayload.resourceName |
event.idm.read_only_udm.target.resource.name |
מופה מיומן השינויים |
protoPayload.serviceName |
event.idm.read_only_udm.target.application |
מופה מיומן השינויים |
protoPayload.resourceLocation.currentLocations |
event.idm.read_only_udm.target.resource.attribute.labels |
מופה מיומן השינויים |
protoPayload.authenticationInfo.oauthInfo.oauthClientId |
event.idm.read_only_udm.principal.resource.attribute.labels |
מופה מיומן השינויים |
protoPayload.requestMetadata.requestAttributes.time |
event.idm.read_only_udm.additional.fields |
מופה מיומן השינויים |
operation.first |
event.idm.read_only_udm.additional.fields |
מופה מיומן השינויים |
protoPayload.serviceData.updateService.request.updateMask |
event.idm.read_only_udm.additional.fields |
מופה מיומן השינויים |
operation.id |
event.idm.read_only_udm.additional.fields |
מופה מיומן השינויים |
protoPayload.authenticationInfo.serviceAccountKeyName |
event.idm.read_only_udm.additional.fields |
מופה מיומן השינויים |
protoPayload.authorizationInfo.permission |
event.idm.read_only_udm.security_result.rule_name |
מופה מיומן השינויים |
protoPayload.authorizationInfo.permissionType |
event.idm.read_only_udm.security_result.description |
מופה מיומן השינויים |
protoPayload.authorizationInfo.granted |
event.idm.read_only_udm.security_result.action |
מופה מיומן השינויים |
protoPayload.@type" , "labels.clone_id" and "operation.producer |
additional.labels |
מופה מיומן השינויים |
שנה רישום
צפייה ביומן השינויים של כלי הניתוח הזה
הבעיה עדיין לא נפתרה? קבלת תשובות מחברי הקהילה וממומחי Google SecOps.