疑難排解常見問題

本頁面列出您在設定 VPC Service Controls 時可能會遇到的各種問題。

未預期的範圍政策行為

您可能會發現一些未預期的 VPC Service Controls 違規事項,但範圍政策應允許這些事項。如果沒有組織層級的存取權政策,您可能會遇到一些與範圍存取權政策相關的未預期問題,這是已知問題。

如要解決這個問題,請使用下列指令,在組織層級建立存取權政策:

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

更改下列內容:

  • ORGANIZATION_ID:組織 ID。
  • POLICY_TITLE:存取權政策的人類可讀標題。

詳情請參閱「建立存取權政策」。

Shared VPC

使用 Shared VPC 時,如果 service perimeter 包含屬於 Shared VPC 網路的專案,則也必須包含「代管」該網路的專案。如果屬於 Shared VPC 網路的專案與主專案不在相同 perimeter 內,服務可能無法正常運作,或完全遭到封鎖。

確認 Shared VPC 網路主機與連線至該網路的專案位於相同 service perimeter。

無法新增虛擬私有雲網路

嘗試將虛擬私有雲網路新增至 service perimeter 時,可能會發生下列錯誤:

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)

發生這項錯誤的原因如下:

  • 虛擬私有雲網路不存在。
  • 虛擬私有雲網路存在,但沒有子網路。
  • 呼叫端沒有必要權限。

如要解決這個問題,請完成下列步驟:

  1. 查看專案中的網路,確認錯誤訊息中指定的虛擬私有雲網路是否存在。

    • 驗證虛擬私有雲網路前,請先完成下列步驟,確保與 API 呼叫相關聯的專案已啟用 Compute Engine API:

      1. 在 Google Cloud 控制台中,前往「APIs & Services」(API 與服務) 頁面。
        前往「APIs & Services」(API 與服務)

      2. 在「APIs & Services」(API 與服務) 頁面中,確認 Compute Engine API 是否列出。

      3. 如果缺少 Compute Engine API,請啟用該 API。
        啟用 API

  2. 查看子網路,確認虛擬私有雲網路中至少有一個子網路。如果沒有子網路,請新增子網路至虛擬私有雲網路。

  3. 檢查呼叫端是否具備虛擬私有雲網路主專案的下列權限:compute.networks.get。這項權限可讓您查看專案中的虛擬私有雲網路。

    • 請虛擬私有雲網路主專案所屬組織的管理員,在主專案中授予呼叫端具有 compute.networks.get 權限的 IAM 角色。例如,Compute 網路檢視者角色。

      如要進一步瞭解如何授予角色,請參閱「管理存取權」。

請務必詳閱在 service perimeter 中使用虛擬私有雲網路的相關限制

Perimeter 間的要求

一般來說,存取層級用於允許 service perimeter 外部的要求,存取 perimeter 內部的受保護資源。

不過,即使存取層級通常允許要求,如果 perimeter 內的專案要求另一個 perimeter 內的受保護資源,系統仍會拒絕。

例如,假設 Perimeter 1 中的專案 A 向專案 B 要求資源。專案 B 中的資源受 Perimeter 2 保護。由於專案 A 位於 perimeter 內,即使 Perimeter 2 的存取層級通常允許受保護資源的要求,系統仍會拒絕該要求。

請使用下列其中一種方法,在 perimeter 之間傳送要求:

  • 使用輸出政策和輸入政策。如要允許另一個 perimeter 的要求存取 perimeter 內的受保護資源,其他 perimeter 必須使用輸出政策,且您必須在 perimeter 內設定輸入政策。

  • 使用 perimeter bridge。橋接設定可讓不同 perimeter 內的兩個或多個專案,向這些專案中的任何服務提出要求。即使服務受到各自的 perimeter 保護,仍可提出這些要求。

  • 請確保要求服務和目標資源都不受 perimeter 保護。在這個情境中,作業會成功,因為服務未受保護。

電子郵件地址無效或不存在

更新含有已刪除主體的 perimeter 時,可能會遇到 The email address is invalid or non-existent 錯誤。

如要修正這個問題,請從所有 perimeter 中移除無效電子郵件地址:

  1. 匯出所有 perimeter。下列範例指令會以 YAML 格式匯出 service perimeter 清單:

    gcloud access-context-manager perimeters list \
        --policy=POLICY_NAME \
        --format="json(name,title,description,perimeterType,status,spec,useExplicitDryRunSpec)" \
        > my-perimeters.yaml
  2. my-perimeters.yaml 檔案中移除無效電子郵件地址,然後儲存為 my-perimeters-updated.yaml

  3. 大量取代所有 perimeter

輸入和輸出規則違規事項

稽核記錄包含有關輸入和輸出規則違規事項的資訊,有助於瞭解 perimeter 違規事項。

輸入規則違規事項

如果發生輸入規則違規事項,表示 perimeter 外部的 API 用戶端嘗試存取 perimeter 內部的資源。由於沒有相符的輸入規則或存取層級,service perimeter 會拒絕要求。

稽核記錄中的輸入規則違規事項包含下列詳細資料:

  • 發生輸入規則違規事項的 perimeter 名稱。
  • Perimeter 外部的 API 用戶端嘗試存取的 perimeter 內部資源。

在下列輸入規則違規事項範例中,perimeter 外部的 API 用戶端嘗試存取 perimeter prod-perimeter 內部的 Cloud Storage bucket prod-protected-storage-bucket

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

如要解決這個問題,請為 perimeter 建立輸入規則。如要進一步瞭解輸入規則,請參閱「輸入規則參考資料」。

輸出規則違規事項

稽核記錄中的輸出規則違規事項表示發生下列其中一個事件:

  • Perimeter 內部的 API 用戶端嘗試存取 perimeter 外部的資源。
  • API 要求涉及 perimeter 內部的資源和 perimeter 外部的資源。例如,如果 Cloud Storage 用戶端呼叫複製指令,但其中一個 bucket 位於 perimeter 內,其他 bucket 位於 perimeter 外部,就會發生這種情況。

由於沒有相符的輸出規則,service perimeter 會拒絕要求。稽核記錄中的輸出規則違規事項包含下列詳細資料:

  • 來源類型,例如網路或資源。
  • 來源 (資源或網路),其 perimeter 發生輸出違規事項。
  • 發生輸出違規事項的 perimeter。
  • 要求嘗試存取的 perimeter 外部目標資源。

在下列輸出規則違規事項範例中,API 要求包含來自專案/5678 的資源 (位於 perimeter prod-perimeter 內部),以及來自 Cloud Storage bucket external-storage-bucket 的物件 (位於 perimeter 外部)。

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

如要解決這個問題,請為 perimeter 建立輸出規則。如要進一步瞭解輸出規則,請參閱「輸出規則參考資料」。

對 VPC Service Controls 封鎖的要求進行偵錯

VPC Service Controls 稽核記錄是針對 VPC Service Controls 封鎖的要求進行偵錯的主要工具。

如果系統存取時意外遭到封鎖,請查看受 service perimeter 保護的專案中的稽核記錄。這些記錄包含要求資源的相關重要資料,以及要求遭拒的原因。如要瞭解如何診斷稽核記錄,請參閱「存取違規分析工具」。

下列各節列出使用 VPC Service Controls 時可能會出現的 violationReason 值。

NETWORK_NOT_IN_SAME_SERVICE_PERIMETER

這個問題的原因可能是下列其中一項:

  • Service perimeter 內的虛擬私有雲網路用戶端嘗試存取不在相同 perimeter 內的專案。這項要求會導致輸出違規事項。建立輸出規則即可修正這個問題。
  • 虛擬私有雲網路中的用戶端位於 service perimeter 外部,並嘗試存取受 service perimeter 保護的專案。這項要求會導致輸入違規事項。建立輸入規則即可修正這個問題。

用戶端可能會從 Compute Engine 或 Google Kubernetes Engine VM 傳送要求,也可能透過 Cloud Interconnect 或使用虛擬私有雲網路設定的 VPN,從地端部署網路傳送要求。

下圖顯示當 service perimeter 內的虛擬私有雲網路用戶端,嘗試存取 perimeter 外部的專案時,就會發生輸出違規事項:

因 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> 是 service perimeter 的名稱。
  • <NETWORK_PROJECT_NUMBER> 是 Google Cloud 專案的專案編號,可保存虛擬私有雲網路。
  • <RESOURCE_PROJECT_NUMBER> 是 Google Cloud 專案的專案編號,可包含資源。

下圖顯示當 perimeter 外部的用戶端嘗試存取 perimeter 內部的專案時,會發生輸入違規事項:

因 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> 是 Google Cloud 專案的專案編號,可包含資源。
  • <NETWORK_PROJECT_NUMBER> 是 Google Cloud 專案的專案編號,可保存虛擬私有雲網路。
  • <POLICY_NAME> 是存取權政策的數字名稱
  • <PERIMETER_NAME> 是 service perimeter 的名稱。

解決方法

如要解決這項錯誤,請為 perimeter 建立輸入或輸出規則

RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER

如果單一要求存取多個資源,但這些資源不在相同 service perimeter 內,就會發生這個問題。無論用戶端位於何處,以及用戶端是否可存取資源,都會發生這個問題。

下圖顯示用戶端存取 perimeter 外部專案和 service perimeter 內專案的資源:

因用戶端從 perimeter 外部的專案存取資源,導致輸出違規事項。

下圖顯示用戶端從專案存取資源,這些專案位於兩個不同的 service perimeter,但 perimeter 之間不會相互通訊:

因用戶端從兩個不同 service perimeter 的專案存取資源,導致輸出違規事項。

以下是輸出違規事項的範例:

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> 是 service perimeter 的名稱。
  • <RESOURCE_PROJECT_INSIDE_THIS_PERIMETER> 是 perimeter 內 Google Cloud 專案的專案編號。
  • <RESOURCE_PROJECT_OUTSIDE_THIS_PERIMETER> 是 perimeter 外部 Google Cloud 專案的專案編號。

解決方法

如要解決這個問題,請為 perimeter 建立輸出規則

NO_MATCHING_ACCESS_LEVEL

如果 IP 位址、裝置需求或使用者身分與指派給 perimeter 的任何輸入規則或存取層級不符,就會發生這個問題。也就是說,不屬於 Google Cloud 網路的用戶端嘗試從 perimeter 外部存取 Google Cloud 網路資源。例如,稽核記錄的 callerIp 欄位所對應的 IP 位址,不符合 service perimeter 存取層級中定義的任何 CIDR 範圍。

如果缺少呼叫端 IP 位址,或顯示為內部 IP 位址,則這項違規事項可能是因 Google Cloud 服務未與 VPC Service Controls 整合所致。原因可能是Google Cloud 服務嘗試存取受保護的服務,並如預期一樣失敗。

如要修正這個問題,建議建立輸入規則,而非存取層級,因為輸入規則可提供精細的存取控管機制。

下圖顯示用戶端嘗試從 perimeter 外部存取資源:

因 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> 是服務帳戶或已驗證使用者的電子郵件地址。

    如果您使用 VPC Service Controls 不支援的 Google Cloud 服務,系統會將屬於 google.com 網域的電子郵件地址遮蓋,並替換為 google-internalgoogle-internal 是指內部 Google 自有身分。

  • <PUBLIC_IP_ADDRESS> 是呼叫端的 IP 位址。如果是來自網際網路的呼叫端,這會是公開 IPv4 或 IPv6 位址。

  • <RESOURCE_PROJECT_NUMBER> 是 Google Cloud 專案的專案編號,可包含資源。

  • <POLICY_NAME> 是存取權政策的數字名稱

  • <PERIMETER_NAME> 是 service perimeter 的名稱。

請注意,在這種情況下,metadata.accessLevels 可能仍會存在,因為違規的 perimeter 可能未指定這些存取層級。

SERVICE_NOT_ALLOWED_FROM_VPC

當用戶端嘗試存取虛擬私有雲網路中的 Google Cloud 資源時,就會發生這個問題。用戶端可能會從 Compute Engine 或 Google Kubernetes Engine VM 傳送要求,也可能透過 Cloud Interconnect 或使用虛擬私有雲網路設定的 VPN,從地端部署網路傳送要求。

如要修正這個問題,請確認 service perimeter 的可透過虛擬私有雲存取的服務設定允許呼叫服務。

範例情境

以下列舉您在使用 VPC Service Controls 時可能會遇到的各種問題。

來自地端部署的 Cloud Storage 存取

在本範例中,VPC Service Controls 封鎖員工工作站 (以 callerIp 識別) 向專案 corp-storage 中的 Cloud Storage bucket 發出的要求。

這項要求會產生以下的稽核記錄檔記錄:

{
 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 專案包含在某個 service perimeter 內。員工工作站並非該 perimeter 內任何網路的一部分。由於員工工作站不在該範圍內,因此其發出的要求會遭到封鎖。

來自專案外部 VM 的 BigQuery 存取

在本範例中,某個屬於專案 458854174376 (data-collector) 的 VM 嘗試對專案 798816221974 (corp-resources-protected) 中的資料集執行 BigQuery 查詢,但這項要求遭到拒絕。

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.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"
}

在本範例中,violationReasonNETWORK_NOT_IN_SAME_SERVICE_PERIMETER。除了 callerIp 外,還包含 callerNetwork。這個 IP 位址屬於私人 IP,系統在記錄中提供了網路資料,協助您區分這些資訊。本範例中有爭議的相關資源分別列於以下兩處:VpcServiceControlAuditMetadata.resourceNamesrequestMetadata.callerNetwork (擁有網路的專案)。

問題所在是,corp-resources-protected 專案位於 service perimeter 內部,但包含 VM 所屬網路的 data-collector 專案不在該 service perimeter 內部。在這個情況下,存取要求會遭到拒絕。

跨專案的 BigQuery 查詢

在本範例中,某個屬於 perimeter-network 專案的 VM 嘗試查詢以下兩項不同專案的 BigQuery 執行個體:corp-resources-protected (與 perimeter-network 在相同 service perimeter 內) 和 corp-resources-public (不在相同 service perimeter 內)。

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"
}

查看 callerNetworkVpcServiceControlAuditMetadata.resourceNames 時,會發現有三項專案:perimeter-network117961063178 (corp-resources-public) 和 690885588241 (corp-resources-protected)。請注意,corp-resources-publicperimeter-networkcorp-resources-protected 不在相同 service perimeter 內。

violationReasonRESOURCES_NOT_IN_SAME_SERVICE_PERIMETER,表示這項要求的某些資源不在其所套用的 perimeter 內。在本案例中,該資源為 corp-resources-public

將 Cloud Storage 檔案移至 perimeter 內部

在本範例中,專案 perimeter-network 中的 VM 使用指令將檔案從某個 Cloud Storage bucket (位於專案 corp-resources-protected 中) 移到另一個 bucket (位於專案 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.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 目前稽核記錄檔功能的限制。

雖然原因不甚清楚,但從這個稽核記錄檔記錄中可得知,這項要求的某些資源是在該要求所套用的 perimeter 外部。在本案例中,該資源為 corp-resources-public

將 Cloud Storage 檔案移至 perimeter 外部

在本範例中,專案 public-network 中的 VM 使用指令將檔案從某個 Cloud Storage bucket (位於專案 corp-resources-protected 中) 移到另一個 bucket (位於專案 corp-resources-public 中)。

corp-resources-protected 專案受到 service perimeter 保護。public-networkcorp-resources-public 專案位於 perimeter 外部。

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"
}

在本範例中,從稽核記錄檔記錄可以得知,其中一項資源無法跨 service perimeter 邊界複製資料 (可以在稽核記錄檔記錄中找到這兩項資源)。提醒您,這是一項源自 perimeter 外部 (位於 public-network 中的 VM) 的要求,且其中一個 bucket 也位在 perimeter 外部 (corp-resources-public-1)。

在 perimeter 外部,我們可以寫入 bucket corp-resources-public-1。如此一來,上一個範例中無法過關的檢查項目將可順利通過。然而,後續對複製資料的檢查項目卻仍無法通過。

我們可以從這個例子看出,有時單一使用者作業會導致多重內部作業,而這些作業需要通過 VPC Service Controls 強制執行。

從 perimeter 內部的 VM 複製 BigQuery 資料集

在本範例中,專案 927005422713 (perimeter-network) 中的 VM 嘗試將專案 corp-resources-private 的 BigQuery 資料集複製到 corp-resources-public (117961063178)。perimeter-networkcorp-resources-private 共用 perimeter,而 corp-resources-public 位於 perimeter 外部。

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"
}

在本範例中,由於記錄機制和 BigQuery 分散式架構的限制,因此沒有任何單一基礎 API 動作可顯示這項要求正在使用的所有資源。

從稽核記錄檔記錄可以得知,為了複製資料,BigQuery 必須使用專案 perimeter-network (要求的來源) 中的網路存取目標專案 (corp-resources-public),因此導致作業失敗。提醒您,corp-resources-public 位於保護 perimeter-network 的 perimeter 外部。系統判定這項要求嘗試將資料竊取至 corp-resources-public,因此遭到拒絕。

本範例說明概念性作業 (例如複製資料) 可能會觸發從多個不同儲存系統 (例如 Cloud Storage、BigQuery 和 Bigtable) 嘗試存取資料的作業。根據作業的執行方式,產生的稽核記錄檔記錄會與原始使用者指令的記錄不同。此外,如果針對指定服務進行多次檢查仍有可能會失敗,產生的稽核記錄檔記錄會與原始使用者指令的記錄不同。

從專案讀取 Dataproc 工作

本範例顯示如何針對使用資料處理服務 (例如 Dataproc) 時所發生的間接 VPC Service Controls 錯誤進行偵錯。

在本範例中,Dataproc 叢集正在執行由 VPC Service Controls 保護的專案。Hello-world.py 是一個 pyspark 工作,會嘗試從 perimeter 內部的 Cloud Storage bucket 存取資料,然後將資料寫入位於 perimeter 外部的另一個 bucket。VPC Service Controls 會封鎖將資料寫入 perimeter 外部 bucket 的作業。

使用下列指令執行 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].

請注意,如果呼叫 saveAsTextFile 方法,就會發生 IO 例外狀況。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.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"
}

Cloud Storage 的 methodName 其實應為 write 作業,但因稽核記錄檔的限制,在這裡會列為 Read。從稽核記錄檔記錄可得知這項作業失敗,原因是專案 corp-resources-private 中的網路嘗試存取 (在本案例中是指寫入) bucket corp-resources-public-1 中某個資源的資料。由於 Cloud Storage 稽核記錄檔的限制,無法明確得知 corp-resources-public-1 屬於哪個專案 bucket。

如要找出包含 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,位於 perimeter 外部。因此這項作業預計會失敗。

因不支援的服務而發生錯誤

部分 Google Cloud 服務在實作過程中會使用其他 Google Cloud 服務。如果在受 perimeter 保護的專案中使用不支援的服務 (例如 App Engine),可能無法存取該服務的資源。

如要進一步瞭解已知問題案例,請參閱「已知的服務限制」。

不支援的服務與受限制 VIP

嘗試存取 VPC Service Controls 受限制 VIP 不支援的 API 時,將導致 403 錯誤。例如,VPC Service Controls 不支援 App Engine,因此使用受限制 VIP 時無法使用 App Engine Admin API。

例如,假設使用下列指令,列出 service perimeter 內的所有 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>

如果服務不支援 VPC Service Controls,且無法透過受限制 VIP 使用,就會發生這類錯誤。如果發生這個錯誤的服務支援 VPC Service Controls,建議查看該服務的已知服務限制,確認是否為已知限制。否則,請回報這個問題

將記錄檔匯出到 perimeter 外部的專案

在本範例中,VPC Service Controls 封鎖記錄檔匯出功能。匯出目的地為專案 corp-resources-public,其位於 VPC Service Controls perimeter 外部,而接收器則是建立在 perimeter 內部的專案 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.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.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 的 perimeter 外部。

本範例顯示,如果某項 Google Cloud 服務使用 Google Cloud內部代管服務帳戶呼叫另一項服務 (例如 p927005422713-439672@gcp-sa-logging.iam.gserviceaccount.com),則要求的「網路專案」(在本案例中為 perimeter-network) 會衍生自該身分。相同的身分代表記錄檔匯出資源本身。

這種模式在 Google Cloud 中十分常見,且適用於許多服務對服務的互動情況。

BigQuery 擷取至 Cloud Storage

本範例說明如何針對無法將 BigQuery 擷取至 Cloud Storage 的問題進行偵錯。

在本範例中,corp-resources-privateperimeter-network 是受 service perimeter 保護的專案,corp-resources-public 是位於 perimeter 外部的專案。

假設使用了以下指令:

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。如果 Identity and Access Management 發生錯誤,也會顯示類似的錯誤。

系統產生的稽核記錄檔記錄如下:

{
 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.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.iam.gserviceaccount.com 識別為嘗試執行作業的身分。在本範例中,假設 storage-accessing@example.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.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 來完成指令。由於這些專案並未共用 perimeter,因此擷取工作失敗。

本範例說明在複雜的多服務作業中,來源和目的地服務的稽核記錄檔可能包含有用的偵錯資料。

透過 Cloud NAT 閘道存取 perimeter

在本範例中,假設組織 A 的專案 A 未在任何 perimeter 內設定。專案 B 受不同組織的 perimeter 保護。專案 A 中的私人資源會使用 Cloud NAT 閘道連上網際網路,以及存取 Google API 和服務。在專案 B 中設定存取層級,根據專案 A 的外部閘道 IP 位址允許存取。

屬於專案 A 的 VM (可以是 Google Kubernetes Engine 節點) 嘗試存取專案 B 中的受保護資源,但連線失敗,且專案 B 中會產生下列稽核記錄檔記錄:

{
  "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.iam.gserviceaccount.com",
      "serviceAccountKeyName": "//iam.googleapis.com/projects/my-project/serviceAccounts/my-user@example.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 位址。callerIp 資源會顯示 gce-internal-ip,而不是 Cloud NAT 閘道外部 IP 位址。

如果要求來自其他專案或機構組織,且來源 Compute Engine VM 沒有外部 IP 位址,系統會將 callerIp 欄位遮蓋為 gce-internal-ip

Cloud NAT 已與 Private Google Access 整合,可自動為資源的子網路啟用 Private Google Access,並將 Google API 和服務的流量保留在內部,而不是使用 Cloud NAT 閘道的外部 IP 位址將流量轉送到網際網路。

在本範例中,由於流量是在內部 Google 網路轉送,AuditLog 物件的 RequestMetadata.caller_ip 欄位會遮蓋為 gce-internal-ip。如要修正這個問題,請設定輸入規則,允許來自專案或服務帳戶的流量,而不要在 IP 位址許可清單存取層級中,使用 Cloud NAT 閘道外部 IP 位址。

後續步驟