本页列出了您在配置 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
使用共享 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 网络存在,但没有子网。
- 调用方没有所需的权限。
如需解决此问题,请完成以下步骤:
通过查看项目中的网络,验证错误消息中指定的 VPC 网络是否存在。
在验证 VPC 网络之前,请完成以下步骤,确保在与 API 调用关联的项目中启用了 Compute Engine API:
在 Google Cloud Console 中,转到 API 和服务页面。
前往“API 和服务”在 API 和服务页面上,验证是否列出了 Compute Engine API。
如果缺少 Compute Engine API,请启用该 API。
启用 API
检查调用方是否对 VPC 网络的宿主项目拥有以下权限:
compute.networks.get
。借助此权限,您可以查看项目中的 VPC 网络。请 VPC 网络宿主项目所属组织的管理员向调用方授予对宿主项目具有
compute.networks.get
权限的 IAM 角色。例如,Compute Network Viewer 角色。如需详细了解如何授予角色,请参阅管理访问权限。
请务必阅读与在服务边界中使用 VPC 网络相关的限制。
边界之间的请求
通常情况下,访问权限级别用于允许从服务边界外请求边界内受保护资源的服务边界。
但是,系统将拒绝从一个边界中的项目请求另一个边界中的受保护资源,即使访问权限级别通常允许该请求也是如此。
例如,假设边界 1 内的项目 A 请求项目 B 内的资源。项目 B 内的资源受边界 2 保护。由于项目 A 在边界内,因此即使边界 2 的访问权限级别通常允许请求受保护的资源,该请求也会被拒绝。
可以通过以下方法之一支持边界之间的请求:
使用出站流量政策和入站流量政策。要允许从另一个边界向您的边界中的受保护资源发送请求,另一个边界必须使用出站流量政策,并且您必须在您的边界中设置入站政策。
使用边界网桥。 网桥允许不同边界内的两个或更多个项目向这些项目中的任何服务发出请求。即使这些服务受相应边界保护,也允许这些请求。
确保发出请求的服务和目标资源均不受边界的保护。在这种情况下,操作会成功,因为服务不会受到保护。
电子邮件地址无效或不存在
更新包含已删除主账号的边界时,您可能会遇到 The email address is invalid or non-existent
错误消息。
如需解决此问题,您可以执行以下任务之一:
从边界中移除无效的电子邮件地址,其中包括访问权限级别以及入站和出站规则。
您可以使用 Google Cloud 控制台或 Google Cloud CLI。
如果电子邮件地址同时存在于试运行和实施边界中,则执行批量操作(仅限 Google Cloud CLI)。
- 获取所有边界:
gcloud access-context-manager perimeters list --format=list \ --policy=<POLICY_NAME> > my-perimeters.yaml
从
my-perimeters.yaml
文件中移除无效的电子邮件地址并将其另存为my-perimeters-updated.yaml
。替换所有边界:
gcloud access-context-manager perimeters replace-all --format=list \ --source-file=my-perimeters-updated.yaml \ --policy=<POLICY_NAME>
违反入站流量和出站流量规则
审核日志包含有关违反入站流量和出站流量规则的信息,可帮助您了解边界违规行为。
违反入站流量规则
违反入站流量规则表明边界外的 API 客户端尝试访问边界内的资源。由于没有匹配的入站流量规则或访问权限级别,因此服务边界会拒绝请求。
审核日志中的入站流量规则违规行为包含以下详细信息:
- 发生入站流量规则违规行为的边界的名称。
- 边界外的 API 客户端尝试访问的边界内资源。
在以下入站流量规则违规示例中,边界外的 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 请求包含来自边界 prod-perimeter
内的 projects/5678 的资源,以及来自边界外的 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
此问题可能是由以下某种原因造成的:
- 服务边界内的 VPC 网络中的客户端尝试访问不在同一边界内的项目。此请求会导致出站流量违规。如需解决此问题,请创建出站流量规则。
- 位于服务边界外的 VPC 网络中的客户端尝试访问受该服务边界保护的项目。此请求会导致入站流量违规。如需解决此问题,请创建入站流量规则。
客户端可能会从 Compute Engine 或 Google Kubernetes Engine 虚拟机发送请求,或者通过 Cloud Interconnect 或使用 VPC 网络配置的 VPN 从本地网络发送请求。
下图显示当服务边界内的 VPC 网络中的客户端尝试访问边界外的项目时发生出站流量违规:
以下是出站流量违规的示例:
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>
是您的 VPC 网络所在的 Google Cloud 项目的编号。<RESOURCE_PROJECT_NUMBER>
是包含资源的 Google Cloud 项目的编号。
下图显示当边界外的客户端尝试访问边界内的项目时发生入站流量违规:
以下是入站流量违规的示例:
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>
是您的 VPC 网络所在的 Google Cloud 项目的编号。<POLICY_NAME>
是访问权限政策的数字名称。<PERIMETER_NAME>
是服务边界的名称。
解决方法
如需解决此错误,请为边界创建入站或出站规则。
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>
是边界内的 Google Cloud 项目的编号。<RESOURCE_PROJECT_OUTSIDE_THIS_PERIMETER>
是边界外的 Google Cloud 项目的编号。
解决方法
如需解决此问题,请为边界创建出站规则。
NO_MATCHING_ACCESS_LEVEL
如果 IP 地址、设备要求或用户身份与分配给边界的任何入站流量规则或访问权限级别都不匹配,就会出现此问题。这意味着,不属于 Google Cloud 网络的客户端尝试从边界外访问 Google Cloud 网络资源。例如,与审核记录的 callerIp
字段对应的 IP 地址与服务边界的访问权限级别中定义的任何 CIDR 范围都不匹配。
如果调用方 IP 地址缺失或者看似内部 IP 地址,则此违规可能是未与 VPC Service Controls 集成的 Google Cloud 服务造成的。原因可能是 Google Cloud 服务尝试访问受保护服务,并且如预期一样失败。
如需解决此问题,我们建议您创建入站流量规则而不是访问权限级别,因为入站流量规则可提供精细的访问权限控制。
下图显示了一个客户端尝试从边界外访问资源:
以下是入站流量违规的示例:
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>
是服务账号或经过身份验证的用户的电子邮件地址。如果您使用的 Google Cloud 服务不受 VPC Service Controls 支持,则系统会隐去属于网域
google.com
的电子邮件地址,并将其替换为google-internal
。google-internal
是指 Google 自有的内部身份。<PUBLIC_IP_ADDRESS>
是调用方的 IP 地址。对于互联网调用方,这将是公共 IPv4 或 IPv6 地址。<RESOURCE_PROJECT_NUMBER>
是包含资源的 Google Cloud 项目的编号。<POLICY_NAME>
是访问权限政策的数字名称。<PERIMETER_NAME>
是服务边界的名称。
请注意,在这种情况下,metadata.accessLevels
可能仍然存在,因为这些访问权限级别可能未在违规的边界中指定。
SERVICE_NOT_ALLOWED_FROM_VPC
当客户端尝试从 VPC 网络访问 Google Cloud 资源时,会发生此问题。客户端可能会从 Compute Engine 或 Google Kubernetes Engine 虚拟机发送请求,或者通过 Cloud Interconnect 或使用 VPC 网络配置的 VPN 从本地网络发送请求。
如需解决此问题,请确保服务边界的 VPC 可访问服务配置允许被调用的服务。
场景示例
以下示例涵盖您在使用 VPC Service Controls 时可能会遇到的问题。
- 从本地访问 Cloud Storage
- 从项目外的虚拟机访问 BigQuery
- 跨项目 BigQuery 查询
- 将 Cloud Storage 文件移动到边界内
- 将 Cloud Storage 文件移动到边界外
- 从边界内的虚拟机复制 BigQuery 数据集
- 从项目中读取 Dataproc 作业
- 带有受限 VIP 的不支持的服务
- 日志导出到边界外的项目
- BigQuery 提取到 Cloud Storage
从本地访问 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
项目包含在服务边界内。员工工作站不属于该边界内的任何网络。由于员工工作站位于边界外,因此请求被阻止。
从项目外的虚拟机访问 BigQuery
在本示例中,属于项目 458854174376
(data-collector
) 的一个虚拟机尝试对项目 798816221974
(corp-resources-protected
) 中的一个数据集运行 BigQuery 查询,但遭到拒绝。
该虚拟机使用以下查询:
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"
}
在此示例中,violationReason
为 NETWORK_NOT_IN_SAME_SERVICE_PERIMETER
。除 callerIp
之外,还包含 callerNetwork
。该 IP 地址是专用地址,并且提供了网络以消除歧义。此处涉及的相关资源列在两个位置:VpcServiceControlAuditMetadata.resourceNames
和 requestMetadata.callerNetwork
(拥有该网络的项目)。
问题在于,corp-resources-protected
项目在服务边界内,而 data-collector
(包含虚拟机所属网络的项目)不在服务边界内。在这种情况下,访问会遭到拒绝。
跨项目 BigQuery 查询
在本示例中,属于 perimeter-network
项目的一个虚拟机尝试对两个不同项目的 BigQuery 实例进行查询:与 perimeter-network
位于同一服务边界内的 corp-resources-protected
,以及位于该边界外的 corp-resources-public
。
该虚拟机使用以下命令:
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
中的一个虚拟机使用命令移动文件:从位于项目 corp-resources-protected
中的一个 Cloud Storage 存储分区移动到另一个位于项目 corp-resources-public
中的存储分区。
该虚拟机使用以下命令:
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 现有审核日志功能的局限性。
虽然原因不是很清楚,但该审核日志记录指出请求中的某个资源位于该请求所适用的边界外。在本例中,该资源是 corp-resources-public
。
将 Cloud Storage 文件移动到边界外
在本示例中,项目 public-network
中的一个虚拟机使用命令移动文件:从位于项目 corp-resources-protected
中的一个 Cloud Storage 存储分区移动到另一个位于项目 corp-resources-public
中的存储分区。
corp-resources-protected
项目受服务边界保护。public-network
和 corp-resources-public
项目位于边界外。
该虚拟机使用以下命令:
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
)。
用户可以从边界外写入存储分区 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
位于该边界外。
该虚拟机使用以下命令:
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 返回 Request violates VPC Service Controls
错误并显示消息 403
。该错误指出必须检查 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
被列为 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
。因此,失败符合预期。
由于服务不受支持而出错
一些 Google Cloud 服务的实施依赖于其他 Google 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.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
的边界外。
本示例显示,如果一个 Google Cloud 服务使用 Google Cloud 内部的代管式服务账号(如 p927005422713-439672@gcp-sa-logging.iam.gserviceaccount.com
)来调用另一个 Google Cloud 服务,则该请求的“网络项目”(在本例中为 perimeter-network
)将从该身份推导。同一身份代表日志导出资源本身。
这种模式在 Google Cloud 中很常见,适用于服务间交互的众多情况。
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。如果发生 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
这两个项目。由于这些项目不在同一边界内,因此提取作业失败。
本示例说明,在复杂的多服务操作中,来源服务和目标位置服务的审核日志都有可能包含有用的调试数据。
通过 Cloud NAT 网关进行边界访问
在此示例中,假设 Org A 中的项目 A 未在任何边界中配置。项目 B 由其他组织中的边界保护。项目 A 上的专用资源使用 Cloud NAT 网关访问互联网以及 Google API 和服务。在项目 B 上配置了访问权限级别,以允许根据项目 A 的外部网关 IP 地址进行访问。
属于项目 A 的虚拟机(可以是 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 虚拟机没有外部 IP 地址,callerIp
字段会隐去为 gce-internal-ip
。
Cloud NAT 与专用 Google 访问通道集成,可自动在资源的子网上启用专用 Google 访问通道,并将流量保留在内部(而非使用 Cloud NAT 网关外部 IP 地址将其路由到互联网)以访问 Google API 和服务。
在这种情况下,由于流量在 Google 内部网络中进行路由,因此 AuditLog
对象的 RequestMetadata.caller_ip
字段会隐去为 gce-internal-ip
。要解决此问题,请在基于 IP 的许可名单的访问权限级别中使用 Cloud NAT 网关外部 IP 地址,而不是配置入站规则以允许从项目或服务账号进行访问。