פתרון בעיות נפוצות

בדף הזה מפורטות בעיות שונות שאפשר להיתקל בהן כשמגדירים את VPC Service Controls.

התנהגות לא צפויה של מדיניות בהיקף מוגבל

יכול להיות שתבחינו בהפרות לא צפויות של VPC Service Controls, שהמדיניות המוגבלת שלכם אמורה לאפשר. זו בעיה מוכרת: אם אין לכם מדיניות גישה ברמת הארגון, יכול להיות שתיתקלו בבעיות לא צפויות במדיניות הגישה המוגבלת שלכם.

כדי לפתור את הבעיה הזו, יוצרים מדיניות גישה ברמת הארגון באמצעות הפקודה הבאה:

gcloud access-context-manager policies create --organization <var>ORGANIZATION_ID</var> --title <var>POLICY_TITLE</var>

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

  • ORGANIZATION_ID: מזהה הארגון.
  • POLICY_TITLE: שם קריא לאנשים של מדיניות הגישה.

מידע נוסף זמין במאמר יצירת מדיניות גישה.

VPC משותף

כשמשתמשים ב-VPC משותף, גבולות גזרה לשירות שכוללים פרויקטים ששייכים לרשת VPC משותפת צריכים לכלול גם את הפרויקט שמארח את הרשת. אם פרויקטים ששייכים לרשת VPC משותפת לא נמצאים באותו גבולות גזרה כמו הפרויקט המארח, יכול להיות שהשירותים לא יפעלו כמו שצריך או שהם ייחסמו לחלוטין.

חשוב לוודא שהמארח של רשת ה-VPC המשותפת נמצא באותם גבולות גזרה לשירות כמו הפרויקטים שמחוברים לרשת.

אי אפשר להוסיף רשת VPC

השגיאה הבאה יכולה להתרחש כשמנסים להוסיף רשת VPC לגבולות גזרה לשירות:

ERROR: (gcloud.access-context-manager.perimeters.update) PERMISSION_DENIED: Permission 'compute.networks.get' denied on resource '//compute.googleapis.com/projects/PROJECT_NAME/global/networks/VPC_NETWORK_NAME' (or it may not exist)

השגיאה הזו מתרחשת בגלל אחת מהסיבות הבאות:

  • רשת ה-VPC לא קיימת.
  • רשת ה-VPC קיימת, אבל אין לה רשת משנה.
  • למתקשר אין את ההרשאה הנדרשת.

כדי לפתור את הבעיה, מבצעים את השלבים הבאים:

  1. בודקים אם רשת ה-VPC שצוינה בהודעת השגיאה קיימת על ידי הצגת הרשתות בפרויקט.

    • לפני שמאמתים את רשת ה-VPC, צריך לוודא ש-Compute Engine API מופעל בפרויקט שמשויך לקריאה ל-API. לשם כך, מבצעים את השלבים הבאים:

      1. במסוף Cloud de Confiance , נכנסים לדף APIs & Services.
        כניסה אל APIs & Services

      2. בדף APIs & Services, בודקים אם API של Compute Engine מופיע ברשימה.

      3. אם Compute Engine API לא מופיע, צריך להפעיל אותו.
        הפעלת ה-API

  2. כדי לבדוק אם קיימת לפחות רשת משנה אחת ברשת ה-VPC, צריך להציג את רשתות המשנה. אם אין תת-רשתות, מוסיפים תת-רשת לרשת ה-VPC.

  3. בודקים אם למבצע הקריאה החוזרת יש את ההרשאה הבאה בפרויקט המארח של רשת ה-VPC: ‏compute.networks.get. ההרשאה הזו מאפשרת לכם לראות רשתות VPC בפרויקט.

    • מבקשים ממנהל המערכת של הארגון שבבעלותו הפרויקט המארח של רשת ה-VPC להעניק לקורא תפקיד IAM עם הרשאה compute.networks.get בפרויקט המארח. לדוגמה, התפקיד 'צפייה ברשת Compute'.

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

חשוב לקרוא את המגבלות שקשורות לשימוש ברשתות VPC ב-service perimeters.

בקשות בין היקפים

בדרך כלל, רמות גישה משמשות כדי לאפשר בקשות מחוץ לגבולות גזרה של שירותים למשאבים מוגנים בתוך גבולות הגזרה.

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

לדוגמה, נניח שבפרויקט א' בגבול גזרה 1 מתבצעת בקשה למשאב מפרויקט ב'. המשאב בפרויקט ב' מוגן על ידי גבול גזרה 2. מכיוון שפרויקט א' נמצא בגבולות גזרה, גם אם רמת הגישה לגבולות גזרה 2 מאפשרת בדרך כלל את הבקשה למשאב המוגן, הבקשה נדחית.

כדי לאפשר בקשות בין היקפים, אפשר להשתמש באחת מהגישות הבאות:

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

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

  • מוודאים שגם השירות ששולח את הבקשה וגם משאב היעד לא מוגנים על ידי גבולות הגזרה. במקרה כזה, הפעולה תצליח כי השירותים לא מוגנים.

כתובת האימייל לא תקינה או לא קיימת

כשמעדכנים גבולות גזרה שכוללים ישות מורשית שנמחקה, יכול להיות שתיתקלו בשגיאה The email address is invalid or non-existent.

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

  1. ייצוא כל ההיקפים. הפקודה לדוגמה הבאה מייצאת רשימה של גבולות שירות בפורמט JSON:

    gcloud access-context-manager perimeters list \
        --policy=POLICY_NAME \
        --format="json(name,title,description,perimeterType,status,\
    spec,useExplicitDryRunSpec)" \
        > my-perimeters.json
  2. מסירים את כתובת האימייל הלא תקינה מהקובץ my-perimeters.json ושומרים אותו בשם my-perimeters-updated.json.

  3. החלפה בכמות גדולה של כל ההיקפים.

הפרות של כללים לתעבורת נתונים נכנסת ויוצאת

יומן הביקורת מכיל מידע על הפרות של כללי הכניסה והיציאה, שיעזור לכם להבין את ההפרות של ההיקף.

הפרה של כלל לתעבורת נתונים נכנסת (ingress)

הפרה של כלל לתעבורת נתונים נכנסת מציינת שלקוח API מחוץ לגבול הגזרה ניסה לגשת למשאב בתוך גבול הגזרה. הבקשה נדחית על ידי גבולות גזרה לשירות כי אין כללים תואמים של תעבורת נתונים נכנסת או רמות גישה.

הפרטים הבאים מופיעים ביומן הביקורת לגבי הפרה של כלל כניסה:

  • שם גבולות הגזרה שבהם התרחשה ההפרה של כלל הכניסה.
  • המשאב בתוך גבולות הגזרה שלקוח ה-API מחוץ לגבולות הגזרה ניסה לגשת אליו.

בדוגמה הבאה להפרת כלל כניסה, לקוח API מחוץ לגבולות הגזרה מנסה לגשת לקטגוריה של Cloud Storage‏ prod-protected-storage-bucket בתוך גבולות הגזרה prod-perimeter.

ingressViolations: [
  0: {
    targetResource: "projects/1234/buckets/prod-protected-storage-bucket"
    servicePerimeter: "accessPolicies/123456789/servicePerimeters/prod-perimeter"
  }
]

כדי לפתור את הבעיה, צריך ליצור כלל כניסה לגבולות הגזרה. מידע נוסף על כללי תעבורה נכנסת זמין במאמר הפניה לכללי תעבורה נכנסת.

הפרה של כלל לתעבורת נתונים יוצאת (egress)

הפרה של כלל יציאה ביומן הביקורת מציינת אחד מהאירועים הבאים:

  • לקוח API בתוך ההיקף ניסה לגשת למשאב מחוץ להיקף.
  • בקשת API שכוללת משאב בתוך גבולות הגזרה ומשאב מחוץ לגבולות הגזרה. לדוגמה, לקוח Cloud Storage שמפעיל פקודת העתקה כשקטגוריה אחת נמצאת בתוך גבולות הגזרה והקטגוריה השנייה נמצאת מחוץ לגבולות הגזרה.

גבולות גזרה לשירות דוחים את הבקשה כי אין כללים תואמים לתעבורת נתונים יוצאת (egress). הפרטים הבאים מופיעים ביומן הביקורת לגבי הפרה של כלל יציאה:

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

בדוגמה הבאה של הפרת כלל יציאה, בקשת ה-API כוללת משאב מ-projects/5678, שנמצא בתוך ההיקף prod-perimeter, ואובייקט מהקטגוריה external-storage-bucket ב-Cloud Storage, שנמצא מחוץ להיקף.

egressViolations: [
  0: {
    sourceType: "Resource"
    source: "projects/5678"
    targetResource: "projects/4321/buckets/external-storage-bucket/objects/corp-resources.json"
    servicePerimeter: "accessPolicies/123456789/servicePerimeters/prod-perimeter"
  }
]

כדי לפתור את הבעיה, צריך ליצור כלל ליציאה עבור ההיקף. מידע נוסף על כללי יציאה זמין במאמר הפניה לכללי יציאה.

ניפוי באגים בבקשות שנחסמו על ידי VPC Service Controls

יומן הביקורת של VPC Service Controls הוא הכלי העיקרי לניפוי באגים בבקשה שנחסמה על ידי VPC Service Controls.

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

אם אתם משתמשים בתבניות שירות של VPC Service Controls כדי לנהל גישה לשירותי Google שלא נתמכים, ונתקלים בדחיות לא צפויות, יכול להיות שהסיבה לבעיה היא אחת מהבאות:

חשוב לוודא שהגדרת ה-YAML בגבולות גזרה לשירות משקפת בצורה מדויקת את תבניות כתובות ה-URL הרצויות.

בקטעים הבאים מפורטים הערכים של violationReason שאולי תיתקלו בהם כשמשתמשים ב-VPC Service Controls.

NETWORK_NOT_IN_SAME_SERVICE_PERIMETER

הסיבות האפשריות לבעיה:

  • לקוח ברשת VPC בתוך גבולות גזרה לשירות מנסה לגשת לפרויקט שלא נמצא באותם גבולות גזרה. הבקשה הזו גורמת להפרה של תעבורת נתונים יוצאת (egress). כדי לפתור את הבעיה, צריך ליצור כלל ליציאה.
  • לקוח ברשת VPC שנמצאת מחוץ לגבולות גזרה לשירות מנסה לגשת לפרויקט שמוגן על ידי גבולות גזרה לשירות. הבקשה הזו גורמת להפרה של תנועת נכנסת. כדי לפתור את הבעיה הזו, צריך ליצור כלל תעבורת נתונים נכנסת (ingress).

הלקוח יכול לשלוח את הבקשה ממכונה וירטואלית של Compute Engine או Google Kubernetes Engine, או מרשת מקומית דרך Cloud Interconnect או VPN שהוגדר באמצעות רשת VPC.

בתרשים הבא מוצג מצב שבו מתרחשת הפרה של תעבורת נתונים יוצאת (egress) כשלקוח ברשת VPC בתוך גבול גזרה של שירות מנסה לגשת לפרויקט מחוץ לגבול הגזרה:

הפרת יציאה בגלל NETWORK_NOT_IN_SAME_SERVICE_PERIMETER.

דוגמה להפרה של יציאת נתונים:

egressViolations: [
{
  servicePerimeter: "accessPolicies/<POLICY_NAME>/servicePerimeters/<PERIMETER_NAME>"
  source: "projects/<NETWORK_PROJECT_NUMBER>"
  sourceType: "Network"
  targetResource: "projects/<RESOURCE_PROJECT_NUMBER>"
}
]

כאשר:

  • <POLICY_NAME> הוא השם המספרי של מדיניות הגישה.
  • <PERIMETER_NAME> הוא השם של גבולות גזרה לשירות.
  • <NETWORK_PROJECT_NUMBER> הוא מספר הפרויקט של Cloud de Confiance by S3NS הפרויקט שמכיל את רשת ה-VPC.
  • <RESOURCE_PROJECT_NUMBER> הוא מספר הפרויקט של Cloud de Confiance הפרויקט שמכיל את המשאב.

בתרשים הבא אפשר לראות שמתרחשת הפרה של כניסה כשלקוח מחוץ להיקף מנסה לגשת לפרויקט בתוך ההיקף:

הפרת כניסה בגלל NETWORK_NOT_IN_SAME_SERVICE_PERIMETER.

דוגמה להפרה של כללי הכניסה:

ingressViolations: [
{
          targetResource: "projects/<RESOURCE_PROJECT_NUMBER>",
      source: "projects/<NETWORK_PROJECT_NUMBER>"
          servicePerimeter: "accessPolicies/<POLICY_NAME>/servicePerimeters/<PERIMETER_NAME>"
}
]

כאשר:

  • <RESOURCE_PROJECT_NUMBER> הוא מספר הפרויקט של Cloud de Confiance הפרויקט שמכיל את המשאב.
  • <NETWORK_PROJECT_NUMBER> הוא מספר הפרויקט של Cloud de Confiance הפרויקט שמכיל את רשת ה-VPC.
  • <POLICY_NAME> הוא השם המספרי של מדיניות הגישה.
  • <PERIMETER_NAME> הוא השם של גבולות גזרה לשירות.

רזולוציה

כדי לפתור את השגיאה הזו, צריך ליצור כלל תעבורה נכנסת או יוצאת עבור ההיקף.

RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER

הבעיה הזו מתרחשת כשבקשה אחת ניגשת למספר משאבים, אבל המשאבים לא נמצאים באותם גבולות גזרה לשירות. הבעיה הזו מתרחשת בלי קשר למיקום של הלקוח ולשאלה אם יש לו גישה למשאבים.

בתרשים הבא מוצגת גישה של לקוח למשאבים מפרויקט מחוץ לגבולות הגזרה ומפרויקט בתוך גבולות הגזרה של השירות:

הפרת תעבורת נתונים יוצאת (egress) בגלל גישה של לקוח למשאבים מפרויקט מחוץ לגבולות הגזרה.

בתרשים הבא מוצג לקוח שניגש למשאבים מפרויקטים שנמצאים בשני היקפי שירות שונים, אבל היקפי השירות לא מתקשרים ביניהם:

הפרת יציאה (egress) בגלל גישת לקוח למשאבים מפרויקטים שנמצאים בשני גבולות גזרה שונים של שירות.

דוגמה להפרה של יציאת נתונים:

egressViolations: [
{
  servicePerimeter: "accessPolicies/<POLICY_NAME>/servicePerimeters/<PERIMETER_NAME>"
  source: "projects/<RESOURCE_PROJECT_INSIDE_THIS_PERIMETER>"
  sourceType: "Resource"
  targetResource: "projects/<RESOURCE_PROJECT_OUTSIDE_THIS-PERIMETER>"
}
]

כאשר:

  • <POLICY_NAME> הוא השם המספרי של מדיניות הגישה.
  • <PERIMETER_NAME> הוא השם של גבולות גזרה לשירות.
  • <RESOURCE_PROJECT_INSIDE_THIS_PERIMETER> הוא מספר הפרויקט של Cloud de Confiance הפרויקט שנמצא בתוך ההיקף.
  • <RESOURCE_PROJECT_OUTSIDE_THIS_PERIMETER> הוא מספר הפרויקט של הפרויקט Cloud de Confiance שנמצא מחוץ להיקף.

רזולוציה

כדי לפתור את הבעיה, צריך ליצור כלל יציאה להיקף.

NO_MATCHING_ACCESS_LEVEL

הבעיה הזו מתרחשת כשכתובת ה-IP, דרישת המכשיר או זהות המשתמש לא תואמות לאף כלל כניסה או רמת גישה שהוקצו לגבולות הגזרה. המשמעות היא שלקוח שלא שייך לרשת Cloud de Confiance מנסה לגשת למשאבי הרשת של Cloud de Confiance מחוץ להיקף. לדוגמה, כתובת ה-IP שמתאימה לשדה callerIp ברשומת הביקורת לא תואמת לאף טווח CIDR שמוגדר ברמות הגישה של גבולות גזרה לשירות.

אם כתובת ה-IP של הגורם ששלח את הקריאה חסרה או מופיעה ככתובת IP פנימית, יכול להיות שההפרה הזו נובעת מ Cloud de Confiance שירות שלא משולב עם VPC Service Controls. הסיבה לכך יכולה להיות שהשירותCloud de Confiance מנסה לגשת לשירות מוגן ונכשל, כצפוי.

כדי לפתור את הבעיה הזו, מומלץ ליצור כלל תעבורת נתונים נכנסת במקום רמת גישה, כי כלל תעבורת נתונים נכנסת מספק בקרת גישה פרטנית.

בתרשים הבא מוצג לקוח שמנסה לגשת למשאבים מחוץ להיקף:

הפרה של כניסה בגלל NO_MATCHING_ACCESS_LEVEL.

דוגמה להפרה של כללי הכניסה:

authenticationInfo: {
  principalEmail: "EMAIL"
}
requestMetadata: {
callerIp: "<PUBLIC_IP_ADDRESS>"
deviceState: "Cross Organization"
}
ingressViolations: [
        {
          targetResource: "projects/<RESOURCE_PROJECT_NUMBER>",
          servicePerimeter: "accessPolicies/<POLICY_NAME>/servicePerimeters/<PERIMETER-NAME>"
        }
  ]

כאשר:

  • <EMAIL> היא כתובת האימייל של חשבון השירות או של המשתמש המאומת.

    אם אתם משתמשים בשירות Cloud de Confiance ש-VPC Service Controls לא תומך בו, כתובות אימייל ששייכות לדומיין google.com יוסתרו ויוחלפו ב-google-internal. ‫google-internal מתייחס לזהויות פנימיות בבעלות Google.

  • <PUBLIC_IP_ADDRESS> היא כתובת ה-IP של המתקשר. למתקשר מהאינטרנט, זו תהיה כתובת IPv4 או IPv6 ציבורית.

  • <RESOURCE_PROJECT_NUMBER> הוא מספר הפרויקט של Cloud de Confiance הפרויקט שמכיל את המשאב.

  • <POLICY_NAME> הוא השם המספרי של מדיניות הגישה.

  • <PERIMETER_NAME> הוא השם של גבולות גזרה לשירות.

שימו לב: במקרה הזה, יכול להיות שעדיין תהיה גישה ל-metadata.accessLevels כי יכול להיות שרמות הגישה האלה לא צוינו בהיקף שהופר.

SERVICE_NOT_ALLOWED_FROM_VPC

הבעיה הזו מתרחשת כשלקוח מנסה לגשת למשאבים מרשת VPC. Cloud de Confiance הלקוח יכול לשלוח את הבקשה ממכונה וירטואלית של Compute Engine או Google Kubernetes Engine, או מרשת מקומית דרך Cloud Interconnect או VPN שהוגדר באמצעות רשת VPC.

כדי לפתור את הבעיה, צריך לוודא שהשירות שאליו מתבצעת הקריאה מותר בהגדרה של שירותים שאפשר לגשת אליהם ב-VPC בגבולות גזרה לשירות.

תרחישים לדוגמה

בדוגמאות הבאות מוסבר על בעיות שאתם עשויים להיתקל בהן במהלך השימוש ב-VPC Service Controls.

גישה ל-Cloud Storage משרתים מקומיים

בדוגמה הזו, VPC Service Controls חוסם בקשה מתחנת עבודה של עובד (מזוהה על ידי callerIp) לקטגוריה של Cloud Storage בפרויקט corp-storage.

הבקשה יוצרת את הרשומה הבאה ביומן הביקורת:

{
 insertId:  "222lvajc6f7"
 logName:  "projects/corp-storage/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "someone@google.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/_"
   ]
   violationReason:  "NO_MATCHING_ACCESS_LEVEL"
  }
  methodName:  "google.storage.NoBillingOk"
  requestMetadata: {
   callerIp:  "b1d5:d26d:5b17:43fe:d358:586b:db59:9617"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/690885588241"
  serviceName:  "storage.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-27T21:40:43.823209571Z"
 resource: {
  labels: {
   method:  "google.storage.NoBillingOk"
   project_id:  "corp-storage"
   service:  "storage.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-27T21:40:42.973784140Z"
}

הפרויקט corp-storage נכלל בגבולות גזרה לשירות. תחנת העבודה של העובד לא שייכת לאף רשת בתוך ההיקף הזה. מכיוון שתחנת העבודה של העובד נמצאת מחוץ להיקף, הבקשה נחסמת.

גישה ל-BigQuery ממכונה וירטואלית מחוץ לפרויקט

בדוגמה הזו, מכונה וירטואלית ששייכת לפרויקט 458854174376 (data-collector) מנסה להריץ שאילתת BigQuery על מערך נתונים בפרויקט 798816221974 (corp-resources-protected), אבל הפעולה נדחית.

מכונת ה-VM משתמשת בשאילתה הבאה:

bq --project=corp-resources-protected query 'select count(*) from babynames.yob2000'

הפלט הבא מוחזר מהשאילתה:

BigQuery error in query operation: VPC Service Controls: Request is
prohibited by organization's policy. Operation ID:
33643962-6a0f-4091-9283-bcdf7e9271f0

נוצרת הרשומה הבאה ביומן הביקורת:

{
 insertId:  "1ei551d2pdq"
 logName:  "projects/corp-resources-protected/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "714877721106-compute@developer.s3ns-system.iam.gserviceaccount.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/1004338142803"
   ]
   violationReason:  "NETWORK_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "bigquery.googleapis.com/bigquery.jobs.create"
  requestMetadata: {
   callerIp:  "10.105.0.2"
   callerNetwork:  "//compute.googleapis.com/projects/ameet-dataflow/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/1004338142803"
  serviceName:  "bigquery.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-28T23:06:13.579882505Z"
 resource: {
  labels: {
   method:  "bigquery.googleapis.com/bigquery.jobs.create"
   project_id:  "corp-resources-protected"
   service:  "bigquery.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-28T23:06:12.799656975Z"
}

בדוגמה הזו, הערך של violationReason הוא NETWORK_NOT_IN_SAME_SERVICE_PERIMETER. ‫callerNetwork כלול בנוסף לcallerIp. כתובת ה-IP פרטית והרשת מסופקת כדי להבחין בינה לבין כתובות אחרות. המשאבים הרלוונטיים שקשורים לבעיה הזו מפורטים בשני מקומות: VpcServiceControlAuditMetadata.resourceNames ו-requestMetadata.callerNetwork (הפרויקט שבבעלותו הרשת).

הבעיה היא שהפרויקט corp-resources-protected נמצא בתוך היקף שירות, אבל הפרויקט data-collector, שכולל את הרשת שהמכונה הווירטואלית שייכת לה, לא נמצא בתוך היקף שירות. במקרה כזה, הגישה נדחית כמו שצריך.

שאילתת BigQuery חוצת פרויקטים

בדוגמה הזו, מכונה וירטואלית ששייכת לפרויקט perimeter-network מנסה להריץ שאילתה על מופעי BigQuery של שני פרויקטים שונים: corp-resources-protected, שנמצא באותם גבולות גזרה לשירות כמו perimeter-network, ו-corp-resources-public, שלא נמצא באותם גבולות גזרה לשירות.

מכונת ה-VM משתמשת בפקודה הבאה:

bq query --use_legacy_sql=false \
    'select count(priv.name),count(pub.name) from \
    `corp-resources-protected.babynames.yob2000` as priv, \
    `corp-resources-public.babynames.yob2000` as pub'

הפלט הבא מוחזר מהשאילתה:

BigQuery error in query operation: Error processing job
'example:bqjob_r211e6f6eec928ffb_000001675c996aa8_1': VPC Service Controls:
Request is prohibited by organization's policy. Operation ID:
dc4fc177-4850-4fc5-b2e7-8c33f302149a

נוצרת הרשומה הבאה ביומן הביקורת:

{
 insertId:  "17kg4exd24ag"
 logName:  "projects/perimeter-network/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/117961063178"
    1:  "projects/690885588241"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "bigquery.googleapis.com/bigquery.tables.getData"
  requestMetadata: {
   callerIp:  "130.211.225.66"
   callerNetwork:  "//compute.googleapis.com/projects/perimeter-network/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/927005422713"
  serviceName:  "bigquery.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-28T20:48:51.384237810Z"
 resource: {
  labels: {
   method:  "bigquery.googleapis.com/bigquery.tables.getData"
   project_id:  "perimeter-network"
   service:  "bigquery.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-28T20:48:50.561884949Z"
}

אם מסתכלים על callerNetwork ועל VpcServiceControlAuditMetadata.resourceNames, אפשר לראות שלושה פרויקטים: perimeter-network,‏ 117961063178 (corp-resources-public) ו-690885588241 (corp-resources-protected). כדאי לזכור ש-corp-resources-public לא נמצא באותם גבולות גזרה לשירות כמו perimeter-network ו-corp-resources-protected.

הערך violationReason, RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER מציין שחלק מהמשאבים בבקשה נמצאים מחוץ לגבולות הגזרה שחלים על הבקשה. במקרה הזה, המשאב הוא corp-resources-public.

העברת קובץ Cloud Storage בתוך ההיקף

בדוגמה הזו, מכונה וירטואלית בפרויקט perimeter-network משתמשת בפקודה כדי להעביר קובץ מקטגוריה אחת של Cloud Storage, שנמצאת בפרויקט corp-resources-protected, לקטגוריה אחרת, שנמצאת בפרויקט corp-resources-public.

מכונת ה-VM משתמשת בפקודה הבאה:

gcloud storage mv gs://corp-resources-private-1/yob2000.txt gs://corp-resources-public-1/babynames/

הפקודה מחזירה את הפלט הבא:

Copying gs://corp-resources-private-1/yob2000.txt [Content-Type=text/plain]...
AccessDeniedException: 403 Request violates VPC Service Controls.

נוצרת הרשומה הבאה ביומן הביקורת:

{
 insertId:  "1xxnssmd2hqo"
 logName:  "projects/perimeter-network/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "storage-accessing@example.s3ns.iam.gserviceaccount.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/_/buckets/corp-resources-public-1"
   ]
   violationReason:  "NETWORK_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "google.storage.BillingRequiredRead"
  requestMetadata: {
   callerIp:  "130.211.225.66"
   callerNetwork:  "//compute.googleapis.com/projects/perimeter-network/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/927005422713"
  serviceName:  "storage.googleapis.com"
  status: {}
 }
 receiveTimestamp:  "2018-11-28T00:45:31.531623485Z"
 resource: {
  labels: {
   method:  "google.storage.BillingRequiredRead"
   project_id:  "perimeter-network"
   service:  "storage.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-28T00:45:31.351140381Z"
}

במקרה הזה, היומן פחות ברור כי השיטה שמופיעה בו היא BillingRequiredRead והפעולה שבוצעה היא move. זו מגבלה של הפונקציונליות הנוכחית של יומן הביקורת ב-VPC Service Controls.

הסיבה פחות ברורה, אבל רשומת יומן הביקורת הזו מציינת שחלק מהמשאבים בבקשה נמצאים מחוץ לגבולות גזרה שחלים על הבקשה. במקרה הזה, המשאב הוא corp-resources-public.

העברת קובץ Cloud Storage מחוץ להיקף

בדוגמה הזו, מכונה וירטואלית בפרויקט public-network משתמשת בפקודה כדי להעביר קובץ מקטגוריה אחת של Cloud Storage, שנמצאת בפרויקט corp-resources-protected, לקטגוריה אחרת, שנמצאת בפרויקט corp-resources-public.

הפרויקט corp-resources-protected מוגן על ידי גבולות גזרה לשירות. הפרויקטים public-network ו-corp-resources-public קיימים מחוץ לגבולות גזרה.

מכונת ה-VM משתמשת בפקודה הבאה:

gcloud storage mv gs://corp-resources-private-1/yob2000.txt gs://corp-resources-public-1/babynames/

הפקודה מחזירה את הפלט הבא:

Copying gs://corp-resources-private-1/yob2000.txt [Content-Type=text/plain]...
AccessDeniedException: 403 Request violates VPC Service Controls.

נוצרת הרשומה הבאה ביומן הביקורת:

{
 insertId:  "10moqhsch9v"
 logName:  "projects/corp-resources-private/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "user@example.biz"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/_/buckets/corp-resources-private-1/objects/yob2000.txt"
    1:  "projects/_/buckets/corp-resources-public-1/objects/out.txt"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "google.storage.Write"
  requestMetadata: {
   callerIp:  "2620:15c:2c4:203:63d6:5eb8:418d:c034"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/1004338142803"
  serviceName:  "storage.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-30T16:34:46.948010626Z"
 resource: {
  labels: {
   method:  "google.storage.Write"
   project_id:  "corp-resources-private"
   service:  "storage.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-30T16:34:46.898098978Z"
}

בדוגמה הזו, יומן הביקורת מציין שאי אפשר להעתיק נתונים מעבר לגבולות גזרה לשירות (שני המשאבים נמצאים ברשומה ביומן הביקורת). חשוב לזכור שהבקשה מגיעה מחוץ לגבולות גזרה (המכונה הווירטואלית ב-public-network), ואחד ממאגרי המידע נמצא מחוץ לגבולות גזרה (corp-resources-public-1).

מחוץ להיקף, אפשר לכתוב ל-bucket‏ corp-resources-public-1, ולכן הבדיקה שנכשלה בדוגמה הקודמת עוברת. עם זאת, הבדיקה הבאה שנועדה להעתיק את הנתונים נכשלת.

בדוגמה הזו אפשר לראות איך לפעמים פעולת משתמש אחת מובילה לכמה פעולות פנימיות שצריכות לעבור את האכיפה של VPC Service Controls.

העתקה של מערך נתונים ב-BigQuery ממכונה וירטואלית בתוך ההיקף

בדוגמה הזו, מכונה וירטואלית בפרויקט 927005422713 (perimeter-network) מנסה להעתיק קבוצת נתונים של BigQuery מפרויקט corp-resources-private אל corp-resources-public (117961063178). הפרויקטים perimeter-network ו-corp-resources-private חולקים גבולות גזרה, אבל corp-resources-public נמצא מחוץ לגבולות הגזרה.

מכונת ה-VM משתמשת בפקודה הבאה:

bq cp corp-resources-private:babynames.yob2000 \
    corp-resources-public:babynames.yob2000

הפקודה מחזירה את הפלט הבא:

BigQuery error in cp operation: VPC Service Controls: Request is prohibited by
organization's policy. Operation ID: c00dbc44-460f-4bd0-9d09-cda98ac800f9

נוצרת הרשומה הבאה ביומן הביקורת:

{
 insertId:  "146o5fd2hbp"
 logName:  "projects/perimeter-network/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/117961063178"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "bigquery.googleapis.com/bigquery.tables.get"
  requestMetadata: {
   callerIp:  "131.201.221.16"
   callerNetwork:  "//compute.googleapis.com/projects/perimeter-network/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/927005422713"
  serviceName:  "bigquery.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-28T00:27:05.688803777Z"
 resource: {
  labels: {
   method:  "bigquery.googleapis.com/bigquery.tables.get"
   project_id:  "perimeter-network"
   service:  "bigquery.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-28T00:27:05.378584819Z"
}

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

הרשומה ביומן הביקורת מציינת שהפעולה נכשלה כי כדי להעתיק את הנתונים, ל-BigQuery צריכה להיות גישה לפרויקט היעד (corp-resources-public) באמצעות הרשת בפרויקט perimeter-network (מקור הבקשה). זוכרים ש-corp-resources-public נמצא מחוץ לגבולות שמגנים על perimeter-network? הבקשה נדחתה כי זו נראית כמו ניסיון להעביר נתונים אל corp-resources-public.

הדוגמה הזו ממחישה שאותה פעולה קונספטואלית, כמו העתקת נתונים, יכולה להפעיל כמה ניסיונות לגשת לנתונים ממערכות אחסון שונות, כמו Cloud Storage,‏ BigQuery ו-Bigtable. בהתאם לאופן הביצוע של הפעולה, רשומת יומן הביקורת שנוצרת שונה מהפקודה המקורית של המשתמש. בנוסף, כשמתבצעות כמה בדיקות בשירות מסוים, והן עלולות להיכשל, רשומת יומן הביקורת שנוצרת נראית שונה מהפקודה המקורית של המשתמש.

קריאת משימות של Managed Service for Apache Spark מפרויקט

בדוגמה הזו נסביר איך לנפות באגים בשגיאות עקיפות של VPC Service Controls שמתרחשות כשמשתמשים בשירותים לעיבוד נתונים כמו Managed Service for Apache Spark.

בדוגמה הזו, אשכול של Managed Service for Apache Spark פועל בפרויקט שמוגן על ידי VPC Service Controls. ‫Hello-world.py היא משימת PySpark שמנסה לגשת לנתונים מקטגוריה של Cloud Storage בתוך גבולות הגזרה ואז לכתוב אותם לקטגוריה אחרת שנמצאת מחוץ לגבולות הגזרה. ‫VPC Service Controls חוסם את הפעולה שכותבת נתונים לדלי מחוץ לגבולות הגזרה.

הפקודה הבאה משמשת להפעלת Hello-world.py:

gcloud dataproc jobs submit pyspark hello-world.py --cluster test-cluster-new2

הפקודה מחזירה את הפלט הבא:

Job [50f16ca8-5102-442b-a545-eed5e4f5f5da] submitted.
Waiting for job output...
18/11/29 00:31:34 INFO org.spark_project.jetty.util.log: Logging initialized @2552ms
18/11/29 00:31:34 INFO org.spark_project.jetty.server.Server: jetty-9.3.z-SNAPSHOT
18/11/29 00:31:34 INFO org.spark_project.jetty.server.Server: Started @2640ms
18/11/29 00:31:34 INFO org.spark_project.jetty.server.AbstractConnector: Started ServerConnector@1f1c18ec{HTTP/1.1,[http/1.1]}{0.0.0.0:4040}
18/11/29 00:31:34 INFO com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystemBase: GHFS version: 1.6.4-hadoop2
18/11/29 00:31:35 INFO org.apache.hadoop.yarn.client.RMProxy: Connecting to ResourceManager at test-cluster-new2-m/10.246.0.3:8032
18/11/29 00:31:37 INFO org.apache.hadoop.yarn.client.api.impl.YarnClientImpl: Submitted application application_1522454176466_0005
Traceback (most recent call last):
  File "/tmp/50f16ca8-5102-442b-a545-eed5e4f5f5da/hello-world.py", line 8, in <module>
    lear.saveAsTextFile("gs://corp-resources-public-1/out.txt")
  File "/usr/lib/spark/python/lib/pyspark.zip/pyspark/rdd.py", line 1553, in saveAsTextFile
  File "/usr/lib/spark/python/lib/py4j-0.10.4-src.zip/py4j/java_gateway.py", line 1133, in __call__
  File "/usr/lib/spark/python/lib/py4j-0.10.4-src.zip/py4j/protocol.py", line 319, in get_return_value
py4j.protocol.Py4JJavaError: An error occurred while calling o49.saveAsTextFile.
: java.io.IOException: Error accessing: bucket: corp-resources-public-1, object: out.txt
    at com.google.cloud.hadoop.gcsio.GoogleCloudStorageImpl.wrapException(GoogleCloudStorageImpl.java:1767)
$sp(PairRDDFunctions.scala:961)

 (truncated)

Caused by: com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
  "code" : 403,
  "errors" : [ {
    "domain" : "global",
    "message" : "Request violates VPC Service Controls.",
    "reason" : "vpcServiceControls"
  } ],
  "message" : "Request violates VPC Service Controls."
}
    at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:145)

 (truncated)

18/11/29 00:31:43 INFO org.spark_project.jetty.server.AbstractConnector: Stopped Spark@1f1c18ec{HTTP/1.1,[http/1.1]}{0.0.0.0:4040}
ERROR: (gcloud.dataproc.jobs.submit.pyspark) Job [50f16ca8-5102-442b-a545-eed5e4f5f5da] entered state [ERROR] while waiting for [DONE].

שימו לב לחריגת ה-IO שמתרחשת כשקוראים לשיטה saveAsTextFile. ‫Cloud Storage מחזיר שגיאה 403 עם ההודעה Request violates VPC Service Controls. השגיאה מציינת שצריך לבדוק את הפעולה ביומן הביקורת של Cloud Storage.

ביומני הביקורת של פרויקט perimeter-network, שבו בוצעה הפקודה, יש רשומה ביומן הביקורת של הפעולה saveAsTextFile:

{
 insertId:  "qdj1o9d1run"
 logName:  "projects/corp-resources-private/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "1004338142803-compute@developer.s3ns-system.iam.gserviceaccount.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/_/buckets/corp-resources-public-1/objects/out.txt"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "google.storage.BillingRequiredRead"
  requestMetadata: {
   callerIp:  "10.246.0.3"
   callerNetwork:  "//compute.googleapis.com/projects/corp-resources-private/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/1004338142803"
  serviceName:  "storage.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-29T00:31:43.666227930Z"
 resource: {
  labels: {
   method:  "google.storage.BillingRequiredRead"
   project_id:  "corp-resources-private"
   service:  "storage.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-29T00:31:43.608250320Z"
}

בגלל מגבלות ביומן הביקורת, הפעולה methodName ב-Cloud Storage מופיעה כ-Read, למרות שהיא למעשה פעולה מסוג write. הרשומה ביומן הביקורת מציינת שהפעולה נכשלה כי רשת בפרויקט corp-resources-private ניסתה לגשת לנתונים (במקרה הזה, לכתוב) של משאב בקטגוריה corp-resources-public-1. בגלל המגבלות של יומן הביקורת של Cloud Storage, לא ברור לאיזה פרויקט שייכת קטגוריית corp-resources-public-1.

כדי לזהות את הפרויקט שמכיל את corp-resources-public-1, משתמשים בפקודה הבאה:

gcloud storage ls gs://corp-resources-public-1 --buckets --log-http 2>&1 | grep projectNumber

הפקודה מחזירה את הפלט הבא: "projectNumber": "117961063178",

117961063178 הוא פרויקט corp-resources-public, שנמצא מחוץ להיקף. לכן, השגיאה צפויה.

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

חלק מהשירותים של Cloud de Confiance תלויים בשירותים אחרים של Cloud de Confiance כחלק מההטמעה שלהם. אם נעשה שימוש בשירות לא נתמך כמו App Engine בתוך פרויקט שמוגן על ידי גבול גזרה, יכול להיות שלא תהיה גישה למשאבים של השירות.

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

שירות לא נתמך עם כתובת VIP מוגבלת

ניסיון לגשת ל-API שלא נתמך על ידי ה-VIP המוגבל של VPC Service Controls יוביל לשגיאה 403. לדוגמה, VPC Service Controls לא תומך ב-App Engine, ולכן App Engine Admin API לא זמין כשמשתמשים ב-VIP המוגבל.

לדוגמה, נניח שהפקודה הבאה משמשת לרישום כל שירותי App Engine בתוך גבולות גזרה לשירות:

gcloud app services list

הפקודה מחזירה את אחד מהפלט הבאים:

ERROR: (gcloud.app.services.list) User [***] does not have permission to access apps instance [***] (or it may not exist): <!DOCTYPE html>
<html lang=en>
  <meta charset=utf-8>
  <meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
  <title>Error 403 (Forbidden)!!1</title>
  <style>
    *{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}@media only screen and (min-resolution:192dpi){ #logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){ #logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px}
  </style>
  <a href=//www.google.com/><span id=logo aria-label=Google></span></a>
  <p><b>403.</b> <ins>That's an error.</ins>
  <p>Your client does not have permission to get URL <code>/v1/apps/***/services</code> from this server.  <ins>That's all we know.</ins>
The service that you're trying to access isn't available on Google's Restricted VIPs. For a list of services that support VPC Service Controls, see https://cloud.google.com/vpc-service-controls/docs/supported-products.

סוג השגיאה הזה צפוי בשירותים שלא נתמכים על ידי VPC Service Controls ושלא זמינים ב-VIP המוגבל. אם השגיאה הזו מתרחשת בשירות ש-VPC Service Controls תומך בו, מומלץ לבדוק את המגבלות הידועות של השירות כדי לראות אם מדובר במגבלה מוכרת. אחרת, צריך לדווח על הבעיה.

ייצוא יומנים לפרויקט מחוץ לגבולות גזרה

בדוגמה הזו, ייצוא יומן נחסם על ידי VPC Service Controls. יעד הייצוא, פרויקט corp-resources-public, נמצא מחוץ לגבולות הגזרה של VPC Service Controls, בעוד שמאגר הנתונים נוצר בפרויקט perimeter-network, שנמצא בתוך גבולות הגזרה.

לדוגמה, נניח שמשתמשים בפקודה הבאה:

gcloud logging sinks describe example-sink

הפקודה מחזירה את הפלט הבא:

destination: bigquery.googleapis.com/projects/corp-resources-public/datasets/logs
filter: |-
  resource.type="audited_resource"
  resource.labels.service="bigquery.googleapis.com"
name: example-sink
outputVersionFormat: V2
writerIdentity: serviceAccount:p927005422713-439672@gcp-sa-logging.s3ns-system.iam.gserviceaccount.com

נוצרת הרשומה הבאה ביומן הביקורת:

{
 insertId:  "e5i2i8cbqw"
 logName:  "projects/perimeter-network/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "p927005422713-439672@gcp-sa-logging.s3ns-system.iam.gserviceaccount.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "corp-resources-public"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "google.cloud.bigquery.v2.TableDataService.InsertAll"
  requestMetadata: {
   callerIp:  "2002:a49:8c51::"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/927005422713"
  serviceName:  "bigquery.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-29T17:32:19.287138882Z"
 resource: {
  labels: {
   method:  "google.cloud.bigquery.v2.TableDataService.InsertAll"
   project_id:  "perimeter-network"
   service:  "bigquery.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-29T17:32:19.054662413Z"
}

רשומת יומן הביקורת נוצרת עבור BigQuery, ולא עבור Logging. הסיבה לכך היא ש-BigQuery הוא שירות היעד שאליו שירות Logging מנסה לכתוב.

הייצוא נכשל כי corp-resources-public נמצא מחוץ לגבולות גזרה שמגנים על perimeter-network.

בדוגמה הזו אפשר לראות שבמקרים שבהם שירות אחד Cloud de Confiance קורא לשירות אחר באמצעות חשבון שירות מנוהל שהוא פנימי ל- Cloud de Confiance, כמו p927005422713-439672@gcp-sa-logging.s3ns-system.iam.gserviceaccount.com, 'פרויקט הרשת' (במקרה הזה, perimeter-network) של הבקשה נגזר מהזהות הזו. אותו זהות מייצגת את משאב ייצוא היומן עצמו.

התבנית הזו נפוצה ב- Cloud de Confiance והיא חלה על מקרים רבים של אינטראקציה בין שירותים.

שליפת נתונים מ-BigQuery ל-Cloud Storage

בדוגמה הזו מוסבר איך לנפות באגים בחילוצים שנכשלו מ-BigQuery ל-Cloud Storage.

בדוגמה הזו, corp-resources-private ו-perimeter-network הם פרויקטים שמוגנים על ידי גבולות גזרה לשירות. corp-resources-public הוא פרויקט שנמצא מחוץ לגבולות הארגון.

נניח שהשתמשתם בפקודה הבאה:

bq extract babynames.yob2000

הפקודה מחזירה את הפלט הבא:

gs://corp-resources-public-1/export.txt
Waiting on bqjob_r47ee34109d02b41_000001676b27157c_1 ... (1s) Current status: DONE
BigQuery error in extract operation: Error processing job 'corp-resources-private:bqjob_r47ee34109d02b41_000001676b27157c_1': Access
Denied: BigQuery BigQuery: Permission denied while writing data.

במקרה הזה, השגיאה לא קשורה באופן ספציפי ל-VPC Service Controls. שגיאה דומה מוצגת אם יש כשל בניהול הזהויות והרשאות הגישה.

נוצרת הרשומה הבאה ביומן הביקורת:

{
 insertId:  "4gbh6pe8jld7"
 logName:  "projects/corp-resources-private/logs/cloudaudit.googleapis.com%2Fdata_access"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "storage-accessing@example.s3ns.iam.gserviceaccount.com"
  }
  methodName:  "jobservice.jobcompleted"
  requestMetadata: {
   callerIp:  "10.5.0.4"
   callerNetwork:  "//compute.googleapis.com/projects/perimeter-network/global/networks/__unknown__"
   callerSuppliedUserAgent:  "google-api-python-client/1.6.5 (gzip),gzip(gfe)"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/corp-resources-private/jobs/bqjob_r47ee34109d02b41_000001676b27157c_1"
  serviceData: {
   @type:  "type.googleapis.com/google.cloud.bigquery.logging.v1.AuditData"
   jobCompletedEvent: {
    eventName:  "extract_job_completed"
    job: {
     jobConfiguration: {
      extract: {
       destinationUris: [
        0:  "gs://corp-resources-public-1/export.txt"
       ]
       sourceTable: {
        datasetId:  "babynames"
        projectId:  "corp-resources-private"
        tableId:  "yob2000"
       }
      }
     }
     jobName: {
      jobId:  "bqjob_r47ee34109d02b41_000001676b27157c_1"
      location:  "US"
      projectId:  "corp-resources-private"
     }
     jobStatistics: {
      createTime:  "2018-12-01T19:03:03.908Z"
      endTime:  "2018-12-01T19:03:05.494Z"
      startTime:  "2018-12-01T19:03:04.013Z"
     }
     jobStatus: {
      additionalErrors: [
       0: {
        code:  7
        message:  "Access Denied: BigQuery BigQuery: Permission denied while writing data."
       }
      ]
      error: {
       code:  7
       message:  "Access Denied: BigQuery BigQuery: Permission denied while writing data."
      }
      state:  "DONE"
     }
    }
   }
  }
  serviceName:  "bigquery.googleapis.com"
  status: {
   code:  7
   message:  "Access Denied: BigQuery BigQuery: Permission denied while writing data."
  }
 }
 receiveTimestamp:  "2018-12-01T19:03:05.532169998Z"
 resource: {
  labels: {
   project_id:  "corp-resources-private"
  }
  type:  "bigquery_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-12-01T19:03:05.503Z"
}

ברשומה הזו ביומן הביקורת, storage-accessing@example.s3ns.iam.gserviceaccount.com מזוהה כזהות שמנסה להריץ את הפעולה. בדוגמה הזו, נניח שלמשתמש storage-accessing@example.s3ns.iam.gserviceaccount.com יש את הרשאות ה-IAM הנדרשות להפעלת הפקודה.

הרשאות IAM לא גורמות לבעיה, ולכן השלב הבא הוא לבדוק אם יש כשלים ב-VPC Service Controls.

רשומת יומן הביקורת של שירות היעד (Cloud Storage) מכילה סיבות מפורטות לכישלון:

{
 insertId:  "1bq397kcfj1"
 logName:  "projects/corp-resources-private/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "storage-accessing@example.s3ns.iam.gserviceaccount.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/1004338142803"
    1:  "projects/_/buckets/corp-resources-public-1"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "google.storage.BillingRequiredRead"
  requestMetadata: {
   callerIp:  "10.5.0.4"
   callerNetwork:  "//compute.googleapis.com/projects/perimeter-network/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/1004338142803"
  serviceName:  "storage.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-12-01T19:03:05.617451586Z"
 resource: {
  labels: {
   method:  "google.storage.BillingRequiredRead"
   project_id:  "corp-resources-private"
   service:  "storage.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-12-01T19:03:05.420005215Z"
}

מהיומן הזה ברור ששני הפרויקטים 1004338142803(corp-resources-private-1) ו-corp-resources-public משמשים להשלמת הפקודה. מכיוון שהפרויקטים האלה לא חולקים גבולות גזרה, עבודת החילוץ נכשלת.

בדוגמה הזו אפשר לראות שבפעולות מורכבות שכוללות כמה שירותים, יומני הביקורת של שירותי המקור והיעד עשויים להכיל נתונים שימושיים לניפוי באגים.

גישה להיקף האבטחה דרך שער Cloud NAT

בדוגמה הזו, נניח שפרויקט א' מארגון א' לא מוגדר באף היקף. פרויקט ב' מאובטח על ידי גבולות גזרה בארגון אחר. משאבים פרטיים בפרויקט א' משתמשים בשער Cloud NAT כדי להגיע לאינטרנט ולשירותים ול-Google APIs. רמת גישה מוגדרת בפרויקט ב' כדי לאפשר גישה על סמך כתובות ה-IP של השער החיצוני של פרויקט א'.

מכונה וירטואלית ששייכת לפרויקט א' (יכול להיות שזה צומת של Google Kubernetes Engine) מנסה לגשת למשאב מוגן בפרויקט ב', אבל החיבור נכשל, ונוצרת רשומת יומן הביקורת הבאה בפרויקט ב':

{
  "protoPayload": {
    "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
    "status": {
      "code": 7,
      "message": "Request is prohibited by organization's policy. vpcServiceControlsUniqueIdentifier: kmpY9Fgfuhgi2NE90lURjFWuiS1nGRqxCw4L12HdW8h46Un__-_LZw",
      "details": [
        {
          "@type": "type.googleapis.com/google.rpc.PreconditionFailure",
          "violations": [
            {
              "type": "VPC_SERVICE_CONTROLS",
              "description": "kmpY9Fgfuhgi2NE90lURjFWuiS1nGRqxCw4L12HdW8h46Un__-_LZw"
            }
          ]
        }
      ]
    },
    "authenticationInfo": {
      "principalEmail": "my-user@example.s3ns.iam.gserviceaccount.com",
      "serviceAccountKeyName": "//iam.googleapis.com/projects/my-project/serviceAccounts/my-user@example.s3ns.iam.gserviceaccount.com/keys/<code><var>ACCOUNT_KEY</var></code>"
    },
    "requestMetadata": {
      "callerIp": "gce-internal-ip",
      "requestAttributes": {},
      "destinationAttributes": {}
    },
    "serviceName": "cloudfunctions.googleapis.com",
    "methodName": "google.cloud.functions.v1.CloudFunctionsService.ListFunctions",
    "resourceName": "<code><var>PROJECT_ID_1</var></code>",
    "metadata": {
      "violationReason": "NETWORK_NOT_IN_SAME_SERVICE_PERIMETER",
      "resourceNames": [
        "projects/<code><var>PROJECT_ID_2</var></code>/locations/-"
      ],
      "securityPolicyInfo": {
        "servicePerimeterName": "accessPolicies/<code><var>ACCESS_POLICY</var></code>/servicePerimeters/us_sandbox",
        "organizationId": "<code><var>ORGANIZATION_ID</var></code>"
      },
      "deviceState": "Unknown",
      "vpcServiceControlsUniqueId": "kmpY9Fgfuhgi2NE90lURjFWuiS1nGRqxCw4L12HdW8h46Un__-_LZw",
      "ingressViolations": [
        {
          "targetResource": "projects/<code><var>PROJECT_ID_1</var></code>",
          "servicePerimeter": "accessPolicies/<code><var>ACCESS_POLICY</var></code>/servicePerimeters/<code><var>PERIMETER_NAME</var></code>",
          "source": "<code><var>PROJECT_ID_2</var></code>"
        }
      ],
      "@type": "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
    }
  },
  "insertId": "tzf7fd103i",
  "resource": {
    "type": "audited_resource",
    "labels": {
      "service": "cloudfunctions.googleapis.com",
      "method": "google.cloud.functions.v1.CloudFunctionsService.ListFunctions",
      "project_id": "<code><var>PROJECT_ID_2</var></code>"
    }
  },
  "timestamp": "2024-04-02T19:56:10.770681816Z",
  "severity": "ERROR",
  "logName": "projects/<code><var>PROJECT_ID_2</var></code>/logs/cloudaudit.googleapis.com%2Fpolicy",
  "receiveTimestamp": "2024-04-02T19:56:11.463811603Z"
}

במשאב callerIp לא מתועדת כתובת IP חיצונית. במקום כתובת ה-IP החיצונית של שער Cloud NAT, במשאב callerIp מוצגת כתובת ה-IP gce-internal-ip.

השדה callerIp מוסתר ומוצג כ-gce-internal-ip כשהבקשות מגיעות מפרויקט או מארגון אחרים, ולמכונה הווירטואלית של Compute Engine שממנה מגיעות הבקשות אין כתובת IP חיצונית.

ל-Cloud NAT יש שילוב עם גישה פרטית ל-Google, שמאפשר באופן אוטומטי גישה פרטית ל-Google ברשת המשנה של המשאב, ושומר על התנועה לממשקי Google APIs ולשירותים של Google כפנימית, במקום לנתב אותה לאינטרנט באמצעות כתובת ה-IP החיצונית של שער Cloud NAT.

במקרה הזה, מכיוון שתעבורת הנתונים מנותבת בתוך הרשת הפנימית של Google, השדה RequestMetadata.caller_ip של האובייקט AuditLog מצונזר ל-gce-internal-ip. כדי לפתור את הבעיה, במקום להשתמש בכתובת ה-IP החיצונית של שער Cloud NAT ברמת הגישה של רשימת ההיתרים מבוססת-IP, צריך להגדיר כלל תעבורת נתונים נכנסת (ingress) כדי לאפשר גישה מהפרויקט או מחשבון השירות.

המאמרים הבאים