1. 简介
在此实验中,我们将学习如何在将数据从 Cloud Storage 转移到 BigQuery 数据集时,使用 VPC Service Controls 保护 BigQuery Data Transfer Service。然后,我们保护 Cloud Storage,并重复该流程,将数据从 Cloud Storage 转移到 BigQuery。Cloud Storage 的保护机制会导致 VPC Service Controls 违规,需要修正此问题才能成功转移。最后,我们还会保护 BigQuery,然后尝试在项目之间复制数据集,这也会导致违规,需要修正。
在本实验中,我们将了解如何分别使用入站和出站规则来修正入站和出站违规问题。我们还将使用访问权限级别来修正 BigQuery 数据传输 入站流量 违规问题。此 Codelab 的目标如下:
- 了解如何在不同服务(尤其是 Cloud Storage、BigQuery 和 BigQuery Data Transfer Service)上分别使用入站流量规则和出站流量规则来修正入站流量和出站流量违规问题。
- 了解发生特定违规行为的原因。
2. 资源设置和要求
准备工作
在此 Codelab 中,我们假设您已了解以下内容:
- 如何创建文件夹
- 如何在文件夹中创建项目或将现有项目移动到文件夹中
- 如何创建范围限定的访问权限政策
- 如何通过 Google Cloud 控制台创建和配置服务边界
- 如何从审核日志中查找违规日志
设置
我们的初始设置如下:
- Google Cloud 组织。
- 组织下的文件夹。在此 Codelab 中,我们将此变量命名为
codelab-folder。 - 文件夹
codelab-folder中的两个 Google Cloud 项目。在此 Codelab 中,我们将项目称为project-1和project-2。- 如果您尚未创建文件夹和项目,请在 Google Cloud 控制台中,在组织下创建一个文件夹并创建两个新项目。
- 所需权限:用于管理文件夹的 IAM 角色、用于管理项目的 IAM 角色、配置 VPC Service Controls 所需的 IAM 角色、用于管理 BigQuery 的 IAM 角色和用于管理 Cloud Storage 的 IAM 角色。
- 项目
project-1和project-2的结算账号。
创建范围限定的政策和常规服务边界
在此 Codelab 中,我们将使用保护 project-2 的常规服务边界。
- 创建范围限定的访问权限政策,其范围限定在文件夹
codelab-folder级别。在此 Codelab 中,我们假设创建的访问权限政策的 ID 为987654321。 - 创建常规边界(我们将其称为
perimeter-2),并添加项目project-2。
在边界 perimeter-2 中,限制 BigQuery Data Transfer API。

创建 Cloud Storage 存储分区和 BigQuery 数据集
就本 Codelab 而言,任何 CSV 文件都足够了,无论其中包含什么内容。主要限制与合设要求有关,该要求规定:
- 如果您的 BigQuery 数据集位于多区域,则包含您要转移的数据的 Cloud Storage 存储分区必须位于同一多区域或该多区域内的位置
- 如果您的数据集位于某个区域,则 Cloud Storage 存储分区必须位于同一区域。
因此,在本 Codelab 中,我们将确保 Cloud Storage 存储分区和 BigQuery 数据集位于同一区域或多区域中。
在项目 project-1 中创建新的 Cloud Storage 存储分区
如需创建新的 Cloud Storage 存储分区,请按照创建新存储分区的文档化步骤操作。
- 对于存储分区的名称,请输入符合存储分区名称要求的名称。在此 Codelab 中,我们将此存储分区命名为
codelab-bqtransfer-bucket。 - 对于数据存储位置(即存储分区位置),请选择将永久存储存储分区数据的位置类型和位置。在本 Codelab 中,我们将使用 us(美国的多个区域)。

创建 CSV 文件
在本地机器上或使用 Cloud Shell,我们可以使用 echo 命令通过以下命令创建示例 CSV 文件 codelab-test-file.csv:
echo "name,age" > codelab-test-file.csv; \
echo "Alice,10" >> codelab-test-file.csv; \
echo "Bob,20" >> codelab-test-file.csv; \
echo "Carol,30" >> codelab-test-file.csv; \
echo "Dan,40" >> codelab-test-file.csv; \
echo "Eve,50" >> codelab-test-file.csv; \
echo "Frank,60" >> codelab-test-file.csv; \
echo "Grace,70" >> codelab-test-file.csv; \
echo "Heidi,80" >> codelab-test-file.csv;
将 CSV 文件上传到 Cloud Storage 存储分区
创建 CSV 文件后,运行以下命令以将文件对象上传到创建的存储分区:
gcloud storage cp codelab-test-file.csv gs://codelab-bqtransfer-bucket

您可以通过列出存储分区中的对象或运行以下命令来验证文件是否已上传到创建的存储分区:
gcloud storage ls --recursive gs://codelab-bqtransfer-bucket/**
在 project-2 中创建 BigQuery 数据集和表
- 按照这些步骤在项目
project-2中创建一个 BigQuery 数据集。 - 按照这些步骤在创建的数据集
codelab_bqtransfer_dataset下创建 BigQuery 表。- 在来源部分,在基于以下数据源创建表列表中选择空表。
- 在表字段中,输入您要创建的表的名称。在此 Codelab 中,我们使用的名称为:
codelab-bqtransfer-table。 - 验证表类型字段是否设置为原生表
- 在架构部分,输入架构定义。您可以点击以文本形式修改来输入架构信息,然后输入以下符合所创建 CSV 文件格式的架构。
[{ "name": "name", "type": "STRING", "mode": "NULLABLE", "description": "The name" }, { "name": "age", "type": "INTEGER", "mode": "NULLABLE", "description": "The age" }]
费用
您需要在项目 project-2 和 project-1 中启用结算功能,才能使用 Cloud 资源/API。我们建议您关停已使用的资源,以免产生超出本 Codelab 范围的费用。
产生费用的资源是 BigQuery 和 Cloud Storage。您可以在 BigQuery 价格计算器和 Cloud Storage 计算器中找到估算费用。
3. 配置从 Cloud Storage 对象到 BigQuery 表的数据传输
现在,我们将尝试创建一个 Data Transfer Service(位于 project-2 中),以将数据从 Cloud Storage(位于 project-1 中)转移到 BigQuery(位于 project-2 中),同时让 VPC Service Controls 保护 project-2 中的 BigQuery Data Transfer Service。仅保护 BigQuery Data Transfer Service(而不保护 BigQuery 和 Cloud Storage)会限制正文只能创建和管理数据传输(例如手动启动数据传输)。
设置从 Cloud Storage 迁移数据
如需创建数据传输,请按以下步骤操作:
- 在
project-2的 Google Cloud 控制台中前往 BigQuery 页面。 - 点击数据传输。

在访问“数据转移作业”页面时调查违规行为
在 Google Cloud 控制台中,我们可以看到 VPC Service Controls 唯一标识符。使用相同的标识符过滤日志并确定违规详情(将 OBSERVED_VPCSC_DENIAL_UNIQUE_ID 替换为观察到的拒绝 ID):
protoPayload.metadata.@type="type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
protoPayload.metadata.vpcServiceControlsUniqueId="OBSERVED_VPCSC_DENIAL_UNIQUE_ID"
观察到的违规行为是 NO_MATCHING_ACCESS_LEVEL,即入站流量违规行为,详细信息如下所示:
ingressViolations: [
0: {
servicePerimeter: "accessPolicies/987654321/servicePerimeters/perimeter-2"
targetResource: "projects/[PROJECT2_NUMBER]"
}]
violationReason: "NO_MATCHING_ACCESS_LEVEL"
callerIp: "USER_PUBLIC_IP_ADDRESS"
resource: {
labels: {
method: "google.cloud.bigquery.datatransfer.v1.DataTransferService.ListTransferConfigs"
project_id: "project-2"
service: "bigquerydatatransfer.googleapis.com"
}
type: "audited_resource"
}
访问“数据传输作业”页面会尝试列出所有已配置的数据传输作业;因此,这违反了 ListTransferConfigs 方法。
解决 bigquerydatatransfer.googleapis.com 服务的违规问题
您可以使用访问权限级别或入站流量规则来修正入站流量违规问题。在此 Codelab 中,我们使用配置了被拒绝的用户身份的入站流量规则,该规则允许访问 bigquerydatatransfer.googleapis.com 服务和所有方法。

入站规则生效后,您应该可以顺利访问数据传输页面。
继续设置从 Cloud Storage 迁移数据
在之前的步骤中,当您位于“数据转移”页面(点击“数据转移”后)时,请继续执行以下步骤:
- 点击 + 创建转移作业。
- 在来源类型部分的来源中,选择 Google Cloud Storage。
- 在转移配置名称部分的显示名称中,输入转移作业的名称,例如
Codelab Transfer。 - 在时间表选项部分,执行以下操作:
- 选择重复频率,例如 15 分钟。
- 请务必选择立即开始;否则,数据传输将仅在配置的重复频率之后开始
- 在目标设置部分的目标数据集中,选择您创建用来存储数据的数据集:
codelab_bqtransfer_dataset - 在数据源详细信息部分,执行以下操作:
- 对于 Destination table,输入目标表的名称。目标表必须遵循表命名规则。在此 Codelab 中,我们将使用之前创建的表:
codelab-bqtransfer-table - 在 Cloud Storage URI 字段中,输入 Cloud Storage URI。在此 Codelab 中,我们将使用创建的存储分区和文件:
codelab-bqtransfer-bucket/codelab-test-file.csv - 在写入偏好设置部分,保留
APPEND(或选择MIRROR)。 - 请勿选择在转移后删除文件(因为我们会多次重复使用同一文件。不过,您可以转移多个文件,并在转移后删除源文件)
- 在文件格式部分,选择 CSV
- 在转移选项中的 CSV 下,输入英文逗号 (“,”) 作为字段定界符。
- 对于 Destination table,输入目标表的名称。目标表必须遵循表命名规则。在此 Codelab 中,我们将使用之前创建的表:
- 在服务账号菜单中,从与您的 Google Cloud 项目关联的服务账号中选择一个服务账号
- 所选服务账号必须具有 Cloud Storage 的必需权限,才能访问托管存储分区的项目;
project-1在此 Codelab 中。 - 在此 Codelab 中,我们将使用在
project-2中创建的服务账号作为codelab-sa@project-2.iam.gserviceaccount.com。
- 所选服务账号必须具有 Cloud Storage 的必需权限,才能访问托管存储分区的项目;
- 点击保存。
由于我们选择了立即开始作为时间表选项,因此选择保存后,系统会立即开始第一次转移。
验证数据转移服务状态
如需验证配置的数据传输的状态,请执行以下操作:
- 在 Google Cloud 控制台中前往 BigQuery 页面
- 点击数据传输。
- 系统会显示已配置的转移作业的列表

点击Codelab Transfer(在“显示名称”下方),系统会显示迄今为止执行的所有跑步活动的列表。

数据传输运行应成功完成,无论是手动触发的数据传输还是预定数据传输,都不应出现 VPC Service Controls 违规情况。请注意,只有手动触发的转移需要入站规则来允许访问手动发起转移的正文。
4. 手动触发的数据传输的 IP 地址限制
当前配置的入站规则允许配置的身份从任何 IP 地址手动触发数据传输。
借助访问权限级别,VPC Service Controls 可以根据特定的 API 请求属性来限制允许的访问权限,这些属性包括:
- IP 子网:检查请求是否来自特定 IP 地址。
- 地区:检查请求是否来自特定地区,该地区由 IP 地址的地理位置确定。
- 主账号:检查请求是否来自特定账号。
- 设备政策:检查请求是否来自符合特定要求的设备。
为了强制执行对这些属性的验证以及已配置的入站流量规则,我们必须创建一个允许所需属性的访问权限级别,然后将创建的访问权限级别添加为入站流量规则中的来源。
此图展示了两个正文(
user@example.com 和 user2@example.com)在三种场景下发起的访问,演示了 VPC Service Controls 如何将来源(入站访问权限级别)和身份属性作为 AND 条件进行评估,即两者都必须匹配。
- 当用户 user@example.com 尝试通过访问权限级别允许的 IP 地址进行访问时,系统会允许其访问,因为其 IP 地址和用户账号与入站规则中的配置相符。
- 当用户 user@example.com 的 IP 地址与允许的 IP 地址不匹配时,即使其账号是入站流量规则中配置的账号,也会被阻止访问。
- 用户 user2@example.com 尝试从允许的 IP 地址进行访问,但由于其账号未获得入站规则的许可,因此被阻止访问。
创建访问权限级别
如需创建按 IP 地址限制访问权限的访问权限级别,请执行以下操作:
- 在 Google Cloud 控制台中,打开 Access Context Manager 页面。
- 如果系统提示,请选择文件夹
codelab-folder。
- 如果系统提示,请选择文件夹
- 在 Access Context Manager 页面的顶部,点击创建访问权限级别。
- 在新建访问权限级别窗格中,为新访问权限级别指定标题。在此 Codelab 中,我们将此变量命名为
project_2_al。 - 在条件部分中,点击 IP 子网前面的 +。
- 在 IP 子网框中,选择公共 IP
- 或者,您也可以选择使用专用 IP 地址,以便在访问权限级别中使用内部 IP 地址。不过,在此 Codelab 中,我们使用的是公共 IP。
- 输入一个或多个格式为 CIDR 地址块的 IPv4 或 IPv6 范围。
在入站流量规则中添加访问权限级别
在入站流量规则中,访问权限级别在 sources 字段下引用,该字段是必需字段,如入站流量规则参考中所述。如需允许面向资源的入站流量,VPC Service Controls 会将 sources 和 identityType 属性评估为 AND 条件。入站规则使用手动触发数据传输的正文的身份,而不是数据传输配置中指定的服务账号。

重新运行转移,并使用按 IP 地址限制访问权限的配置
如需评估所应用配置的有效性,请使用以下场景再次触发转移:
- 使用入站流量规则所引用访问权限级别中允许范围内的 IP 地址。
- 使用配置不允许的 IP 地址
从允许的 IP 地址进行访问应会成功,而从不允许的 IP 地址进行访问应会失败,并导致 VPC Service Controls 违规。
使用其他 IP 地址进行测试的一种简单方法是,允许在使用 Google Cloud 控制台时分配 IP 地址,然后在 Cloud Shell 中进行测试。
在 Cloud Shell 中,运行以下命令以手动触发转移,同时替换 RUN_TIME 和 RESOURCE_NAME:
bq mk \
--transfer_run \
--run_time='RUN_TIME' \
RESOURCE_NAME
例如,以下示例命令会立即运行项目 1234567890 中的转移作业配置 12345678-90ab-cdef-ghij-klmnopqrstuv。
NOW=$(TZ=GMT date +"%Y-%m-%dT%H:%M:%SZ");
bq mk \
--transfer_run \
--run_time=$NOW \
projects/1234567890/locations/us/transferConfigs/12345678-90ab-cdef-ghij-klmnopqrstuv
观测到的输出显示了 VPC Service Controls 违规情况,这是预期行为,因为该 IP 地址是不允许的。

观察到的违规行为发生在 DataTransferService.StartManualTransferRuns 方法中。
ingressViolations: [
0: {
servicePerimeter: "accessPolicies/987654321/servicePerimeters/perimeter-2"
targetResource: "projects/[PROJECT2_NUMBER]"
targetResourcePermissions: [0: "vpcsc.permissions.unavailable"]
}]
violationReason: "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
resource: {
labels: {
method: "google.cloud.bigquery.datatransfer.v1.DataTransferService.StartManualTransferRuns"
project_id: "project-2"
service: "bigquerydatatransfer.googleapis.com"
}
type: "audited_resource"
}
severity: "ERROR"
5. 在保护 Cloud Storage 服务的同时开始数据传输
由于我们要执行从 Cloud Storage 到 BigQuery 的转移,因此我们不妨将 Cloud Storage 添加到受 VPC Service Controls 保护的服务中,看看转移是否仍然成功。
在 perimeter-2 配置中,将 Cloud Storage API 和 BigQuery Data Transfer API 一起添加为受限服务。

确保 Cloud Storage API 安全无虞后,请等待下一次预定的数据传输,或按照以下步骤手动触发传输:
- 转到 Google Cloud 控制台中的 BigQuery 页面。
- 点击数据传输。
- 从列表中选择您的转移作业:在此 Codelab 中,我们将使用 Codelab Transfer 转移作业
- 点击立即运行转移作业
- 点击确定。
系统将启动另一项转移。您可能需要刷新页面才能看到。这次,转移将因违反 VPC Service Controls 而失败。

调查 Cloud Storage VPC Service Controls 违规情况
使用 vpcServiceControlsUniqueIdentifier 过滤审核日志,如转移摘要中所示。
观察到的违规行为是 RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER 出站流量违规行为,详细信息如下:
- 正文是在 Data Transfer Service 中配置的服务账号(无论是手动触发还是运行预定数据传输,被拒绝的正文都将是同一个)。
- 受影响的服务是 Cloud Storage
- 请求的来源是配置了 Data Transfer Service 的项目:
project-2 - 目标项目是 Cloud Storage 对象所在的项目:
project-1
principalEmail: "codelab-sa@project-2.iam.gserviceaccount.com"
egressViolations: [
0: {
servicePerimeter: "accessPolicies/987654321/servicePerimeters/perimeter-2"
source: "projects/[PROJECT2_NUMBER]"
sourceType: "Resource"
targetResource: "projects/[PROJECT1_NUMBER]"
targetResourcePermissions: [0: "storage.objects.get"]
}]
labels: {
method: "google.storage.objects.get"
project_id: "project-2"
service: "storage.googleapis.com"
}
修正 Cloud Storage 出站流量违规问题
如需修正出站流量违规问题,我们必须使用一项出站流量规则,该规则允许从被拒绝的服务账号向包含 Cloud Storage 对象的项目发送流量。

修改服务边界 perimeter-2 后,重复上述流程以再次触发转移。转移不会显示错误。

6. 将 BigQuery 数据集从 project-2 复制到 project-1
确认我们可以将数据从 project-1 中的 Cloud Storage 存储分区转移到 project-2 中的 BigQuery 数据集后,我们来将 BigQuery 数据集从 project-2 复制到 project-1;同时,BigQuery API 受 VPC Service Controls 保护。
如需创建和复制数据集,我们将使用 bq mk 命令,该命令使用 bq 工具。
在 project-1 中创建目标数据集
在复制数据集之前,必须先创建目标数据集。如需创建目标数据集,我们可以运行以下命令,该命令会在项目 project-1 中创建一个名为 copied_dataset 的数据集,并将位置设为 us。
bq mk \
--dataset \
--location=us \
project-1:copied_dataset
使用 VPC Service Controls 保护 project-2 中的 BigQuery 服务
修改边界 perimeter-2 的配置,并添加 BigQuery API 作为受保护的服务,同时添加 BigQuery 数据传输 和 Cloud Storage 服务。

启动数据集复制
如需复制数据集,请运行以下 bq mk 命令,该命令会将项目 project-2 中的数据集 codelab_bqtransfer_dataset 复制到 project-1 中的数据集 copied_dataset,并覆盖数据集内容(如有)。
bq mk \
--transfer_config \
--project_id=project-1 \
--target_dataset=copied_dataset \
--data_source=cross_region_copy \
--display_name='Dataset from project-2 to project-1' \
--params='{
"source_dataset_id":"codelab_bqtransfer_dataset",
"source_project_id":"project-2",
"overwrite_destination_table":"true"
}'
该命令将成功运行;与此同时,系统会成功创建转移配置,以开始复制数据集的操作。复制数据集本身会失败,并显示 VPC Service Controls 违规消息。
如需查找相应的 VPC Service Controls 违规详情,请使用以下日志查询检查 project-2(源数据集项目)中的日志。日志查询会根据要复制的数据集的 BigQuery 服务和资源名称 (codelab_bqtransfer_dataset) 过滤日志。
resource.labels.service="bigquery.googleapis.com"
protoPayload.metadata.resourceNames:"datasets/codelab_bqtransfer_dataset"
观察到的 VPC Service Controls 违规是从 project-2 到 project-1 的出站流量违规。
egressViolations: [
0: {
servicePerimeter: "accessPolicies/987654321/servicePerimeters/perimeter-2"
source: "projects/[PROJECT-2-NUMBER]"
sourceType: "Resource"
targetResource: "projects/[PROJECT-1-NUMBER]"
targetResourcePermissions: [
0: "bigquery.transfers.update"
1: "bigquery.transfers.get"
2: "bigquery.jobs.create"
]
}
]
method: "bigquery.tables.getData"
service: "bigquery.googleapis.com"
修正所有 BigQuery 违规问题,然后重新开始复制数据集
如需修正出站违规问题,我们需要创建允许被拒绝的正文的出站规则。被拒绝的主账号是运行 mk 命令的主账号。

出口规则生效后,在边界 perimeter-2 上运行相同的命令来复制数据集。这次,它应该会成功复制数据集,而不会违反 VPC Service Controls。
7. 清理
虽然在不使用 VPC Service Controls 时无需另行付费,但最好清理本实验中使用的设置。您还可以删除虚拟机实例和/或 Cloud 项目,以避免产生费用。删除云项目后,系统即会停止对该项目中使用的所有资源计费。
- 如需删除 Cloud Storage 存储分区,请完成以下步骤:
- 在 Google Cloud 控制台中,进入 Cloud Storage 存储分区页面。
- 选中要删除的存储分区对应的复选框,然后点击删除。
- 在出现的叠加窗口中,确认要删除存储分区及其内容。

- 如需删除 BigQuery 数据集,请完成以下步骤:
- 在 Google Cloud 控制台中,前往 BigQuery 页面。
- 在浏览器窗格中,展开您的项目,然后选择数据集。
- 展开三点状菜单,然后点击删除。
- 在删除数据集对话框中,在字段中输入
delete,然后点击删除。
- 如需删除服务边界,请完成以下步骤:
- 在 Google Cloud 控制台中,选择安全,然后在访问权限政策的范围限定级别(在本例中为文件夹级别)选择 VPC Service Controls。
- 在 VPC Service Controls 页面上,在与要删除的边界相对应的表格行中,选择
Delete Icon。
- 如需删除访问权限级别,请完成以下步骤:
- 在 Google Cloud 控制台中,打开文件夹级层范围的 Access Context Manager 页面。
- 在网格中,找到您要删除的访问权限级别所对应的行,选择三点状菜单,然后选择删除。
- 如需关闭项目,请完成以下步骤:
- 在 Google Cloud 控制台中,前往要删除的项目对应的 IAM 和管理设置页面。
- 在“IAM 和管理设置”页面上,选择关停。
- 输入项目 ID,然后选择仍要关停。
8. 恭喜!
在此 Codelab 中,您创建了 VPC Service Controls 边界、强制执行了该边界并对其进行了问题排查。
了解详情
您还可以探索以下场景:
- 在另一个也保护 BigQuery、BigQuery Data Transfer Service 和 Cloud Storage 的安全边界中添加
project-1。 - 从其他支持的来源执行 BigQuery 数据传输。
- 根据位置或设备政策等其他属性限制用户访问权限。
许可
此作品已获得 Creative Commons Attribution 2.0 通用许可授权。
