排解常見問題

本頁列出您在設定 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:使用者可自然閱讀的存取權政策標題。

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

共用虛擬私有雲

使用共用虛擬私有雲時,如果服務範圍包含屬於共用虛擬私有雲網路的專案,則也必須包含「主控」該網路的專案。如果屬於共用虛擬私有雲網路的專案與主專案不在同一安全防護範圍內,服務可能無法正常運作,或完全遭到封鎖。

確認共用虛擬私有雲網路主機與連線至該網路的專案位於同一個服務範圍。

無法新增 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)

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

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

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

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

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

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

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

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

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

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

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

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

請務必詳閱在服務範圍中使用 VPC 網路的相關限制

周邊裝置間的要求

一般來說,存取層級用於允許服務範圍外的要求,存取範圍內的受保護資源。

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

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

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

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

  • 使用重疊範圍。 重疊範圍可讓不同範圍內的兩個以上專案,向這些專案中的任何服務提出要求。即使服務受到各自的邊界保護,仍可提出這些要求。

  • 請確保要求服務和目標資源都不受範圍保護。在這種情況下,作業會成功,因為服務未受保護。

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

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

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

  1. 匯出所有安全防護範圍。 下列範例指令會以 YAML 格式匯出服務安全防護範圍清單:

    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. 大量取代所有服務範圍

違反輸入和輸出規則

稽核記錄包含有關連入和連出規則違規的資訊,有助於瞭解周邊違規情形。

違反輸入規則

如果發生輸入規則違規情形,表示範圍外的 API 用戶端嘗試存取範圍內的資源。由於沒有相符的連入規則或存取層級,服務範圍會拒絕要求。

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

  • 發生 Ingress 規則違規事件的範圍名稱。
  • 範圍外的 API 用戶端嘗試存取的範圍內資源。

在下列違規的 Ingress 規則範例中,周邊以外的 API 用戶端嘗試存取周邊 prod-perimeter 內的 Cloud Storage 值區 prod-protected-storage-bucket

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

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

違反輸出規則

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

  • 範圍內的 API 用戶端嘗試存取範圍外的資源。
  • API 要求涉及安全範圍內的資源和安全範圍外的資源。舉例來說,如果 Cloud Storage 用戶端呼叫複製指令,但其中一個值區位於範圍內,另一個值區位於範圍外,就會發生這種情況。

服務範圍沒有相符的輸出規則,因此拒絕要求。稽核記錄中的輸出規則違規事項包含下列詳細資料:

  • 來源類型,例如網路或資源。
  • 來源 (資源或網路),其周邊遇到輸出違規情形。
  • 發生輸出違規行為的邊界。
  • 要求嘗試存取的服務範圍外目標資源。

在下列輸出規則違規範例中,API 要求包含來自 projects/5678 的資源 (位於服務範圍 prod-perimeter 內),以及來自 Cloud Storage 值區 external-storage-bucket 的物件 (位於服務範圍外)。

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 時可能會出現的 violationReason 值。

NETWORK_NOT_IN_SAME_SERVICE_PERIMETER

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

  • 服務範圍內的虛擬私有雲網路用戶端嘗試存取不在同一範圍內的專案。這項要求會導致外送違規。 建立輸出規則即可修正這個問題。
  • 虛擬私有雲網路中的用戶端位於服務範圍外,並嘗試存取受服務範圍保護的專案。這項要求會導致入口違規。建立 Ingress 規則即可修正這個問題。

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

下圖顯示當服務範圍內的虛擬私有雲網路用戶端,嘗試存取範圍外的專案時,會發生輸出違規行為:

因 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> 是保存虛擬私有雲網路的 Trusted Cloud by S3NS 專案專案號碼。
  • <RESOURCE_PROJECT_NUMBER> 是包含資源的 Trusted Cloud 專案專案號碼。

下圖顯示當範圍外的用戶端嘗試存取範圍內的專案時,會發生輸入違規情形:

因 NETWORK_NOT_IN_SAME_SERVICE_PERIMETER 而違反 Ingress 規定。

以下是 Ingress 違規的範例:

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

其中:

  • <RESOURCE_PROJECT_NUMBER> 是包含資源的 Trusted Cloud 專案專案號碼。
  • <NETWORK_PROJECT_NUMBER> 是保存虛擬私有雲網路的 Trusted Cloud 專案專案號碼。
  • <POLICY_NAME> 是存取權政策的數字名稱
  • <PERIMETER_NAME> 是服務範圍的名稱。

解決方法

如要解決這項錯誤,請為安全防護範圍建立 Ingress 或 Egress 規則

RESOURCES_NOT_IN_SAME_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> 是服務範圍的名稱。
  • <RESOURCE_PROJECT_INSIDE_THIS_PERIMETER> 是 Trusted Cloud 範圍內的專案編號。
  • <RESOURCE_PROJECT_OUTSIDE_THIS_PERIMETER> 是範圍外的專案編號。 Trusted Cloud

解決方法

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

NO_MATCHING_ACCESS_LEVEL

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

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

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

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

因 NO_MATCHING_ACCESS_LEVEL 發生進入違規。

以下是 Ingress 違規的範例:

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

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

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

  • <RESOURCE_PROJECT_NUMBER> 是包含資源的 Trusted Cloud 專案專案號碼。

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

  • <PERIMETER_NAME> 是服務範圍的名稱。

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

SERVICE_NOT_ALLOWED_FROM_VPC

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

如要修正這個問題,請確認服務範圍的 VPC 可存取服務設定允許呼叫服務。

範例情境

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

來自內部部署環境的 Cloud Storage 存取要求

在這個例子中,VPC Service Controls 封鎖了員工工作站 (以 callerIp 做為識別依據) 向專案 corp-storage 中的 Cloud 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」包含在某個服務範圍內。員工工作站並非該範圍內任何網路的一部分。由於員工工作站不在該範圍內,因此其發出的要求會遭到封鎖。

來自專案外部 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.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"
}

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

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

跨專案的 BigQuery 查詢

在這個例子中,某個屬於 perimeter-network 專案的 VM 嘗試查詢以下兩項不同專案的 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"
}

查看 callerNetworkVpcServiceControlAuditMetadata.resourceNames,會發現當中有三項專案:perimeter-network117961063178 (corp-resources-public) 和 690885588241 (corp-resources-protected)。請注意,corp-resources-publicperimeter-networkcorp-resources-protected 不在同一個服務範圍內。

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

將 Cloud Storage 檔案移至範圍內

在這個例子中,專案 perimeter-network 中的 VM 使用指令將檔案從某個 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-system.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 中的 VM 使用指令將檔案從某個 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 中的 VM) 的要求,且其中一個值區也位在範圍之外 (corp-resources-public-1)。

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

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

從範圍內的 VM 複製 BigQuery 資料集

在這個例子中,專案 927005422713 (perimeter-network) 中的 VM 嘗試將專案 corp-resources-private 的 BigQuery 資料集複製到 corp-resources-public (117961063178)。perimeter-networkcorp-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"
}

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

從稽核記錄檔記錄可以得知,為了複製資料,BigQuery 必須使用專案 perimeter-network (要求的來源) 中的網路存取目標專案 (corp-resources-public),因此導致作業失敗。請回想一下,corp-resources-public 位於保護 perimeter-network 的範圍之外。系統判定這項要求企圖將資料竊取至 corp-resources-public,因此予以拒絕。

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

從專案讀取 Dataproc 工作

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

在這個例子中,Dataproc 叢集正在執行由 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].

請注意,如果呼叫 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.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"
}

Cloud Storage 的 methodName 其實應為 write 作業,但因稽核記錄的限制,在這裡會列為 Read。從稽核記錄檔記錄可得知這項作業失敗,原因是專案 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,位於範圍之外。因此這項作業預計會失敗。

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

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

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

不支援的服務與受限 VIP

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

舉例來說,假設我們使用以下指令,列出服務範圍內的所有 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,建議您查看該服務的已知服務限制,確認是否為已知限制。否則,請回報這個問題

將記錄匯出到範圍外的專案

在這個例子中,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 的範圍之外。

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

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

BigQuery 擷取至 Cloud Storage

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

在這個例子中,corp-resources-privateperimeter-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。如果 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.s3ns-system.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-system.iam.gserviceaccount.com 識別為嘗試執行作業的身分。在這個例子中,我們假設 storage-accessing@example.s3ns-system.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-system.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 閘道存取邊界

在本範例中,假設機構 A 的專案 A 未在任何範圍內設定。專案 B 受不同機構的範圍保護。專案 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.s3ns-system.iam.gserviceaccount.com",
      "serviceAccountKeyName": "//iam.googleapis.com/projects/my-project/serviceAccounts/my-user@example.s3ns-system.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私人 Google 存取權整合後,會自動在資源的子網路上啟用私人 Google 存取權,並將 Google API 和服務的流量保留在內部,而不是使用 Cloud NAT 閘道的外部 IP 位址將流量傳送到網際網路。

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

後續步驟