1. 简介
在此 Codelab 中,您将学习如何使用 VPC Service Controls 保护 BigQuery API。此 Codelab 开始时,没有受服务边界保护的 API 服务,因此可以对公共数据集运行查询,并将结果保存在项目表中。查询在一个项目中运行,而表(用于保存结果)在另一个项目中创建,这模拟了一种设置,即数据可以存储在一个项目中,但需要使用另一个项目进行访问。
接下来,我们将介绍如何使用服务边界来保护数据项目。您将学习如何使用入站流量规则和出站流量规则来修正观察到的违规行为,然后添加访问权限级别以使用内部 IP 地址限制访问。此 Codelab 的目标如下:
- 了解如何分别使用入站流量规则和出站流量规则来修正入站流量和出站流量违规问题。
- 了解发生特定违规行为的原因。
- 分析已应用的违规修正措施的范围。
- 修改修复(入站 / 出站规则),以利用允许 VPC 网络中来自内部 IP 地址的流量的选项(使用访问权限级别)来更改其范围。
2. 资源设置和要求
准备工作
在此 Codelab 中,我们假设您已了解以下内容:
- 运行 BigQuery 查询的基础知识:您可以查看此 Codelab,了解如何在 BigQuery 中查询维基百科数据集
- 如何创建和管理文件夹
- 如何在文件夹中创建项目或将现有项目移动到文件夹中
- 如何创建范围限定的访问权限政策
- 如何创建和配置服务边界
- 如何在日志中查找安全政策违规行为
设置
我们的初始设置如下:
- Google Cloud 组织。
- 组织下的文件夹。在此 Codelab 中,我们将其称为
codelab-folder。 - 放置在同一文件夹
codelab-folder下的两个 Google Cloud 项目。在此 Codelab 中,我们将其称为project-1和project-2- 如果您尚未创建文件夹和项目,请在 Google Cloud 控制台中,在组织下创建一个文件夹,并在该文件夹下创建两个新项目。
- 所需权限:
- 用于管理文件夹的 IAM 角色:在文件夹级层分配
- 用于管理项目的 IAM 角色:在项目级层分配
- 配置 VPC Service Controls 所需的 IAM 角色:在组织级层分配
- 用于管理 BigQuery 的 IAM 角色:在项目级层分配
- 用于管理 Compute Engine 实例的 IAM 角色:在项目级层分配
- 项目
project-2和project-1的结算账号。
创建常规服务边界
在此 Codelab 中,我们将使用保护 project-1 的常规服务边界。
- 创建常规边界
perimeter-1,并添加project-1。
创建 Compute Engine VM
在此 Codelab 中,我们将使用 project-2 中的 1 个 Compute Engine 实例,该实例位于 us-central1 中,并使用名为 default 的默认 VPC 网络。
- 您可以参考相关文档,了解如何通过公共映像创建 Compute Engine 实例。
费用
您需要在 Google Cloud 控制台中启用结算功能,才能使用 Cloud 资源/API。我们建议您关停已使用的资源,以免产生超出本 Codelab 范围的费用。Google Cloud 新用户符合参与 300 美元免费试用计划的条件。
会产生费用的资源是 BigQuery 和 Compute Engine 实例。您可以使用 BigQuery 价格计算器和 Compute Engine 价格计算器估算费用。
3. 不受 VPC Service Controls 限制的 BigQuery 访问权限
查询公共数据集并将结果保存在 project-1 中
- 访问
project-2和project-1,通过访问 BigQuery Studio 页面验证您是否能够访问 BigQuery API。您应该能够这样做,因为即使project-1位于服务边界内,该边界目前也没有保护任何服务。 - 在
project-2中,运行以下查询来查询公共数据集。
SELECT name, SUM(number) AS total
FROM `bigquery-public-data.usa_names.usa_1910_2013`
GROUP BY name
ORDER BY total DESC
LIMIT 10;
运行针对公共数据集的查询后(保持在 project-2 中):
- 点击保存结果,然后选择 BigQuery 表。(请参阅以下屏幕截图)。

- 选择
project-1作为目标项目。 - 将数据集命名为
codelab_dataset。(选择创建新数据集,除非您要使用现有数据集)。
- 将表格命名为:
codelab-table。 - 点击保存。
由于执行了来自 project-2 的查询,公共数据集数据已成功存储在 project-1 中。
查询数据集已从 project-2 保存到 project-1
在 project-2 BigQuery Studio 中,运行以下查询以选择来自以下来源的数据:
- 项目:
project-1 - 数据集:
codelab_dataset - 表:
codelab-table
SELECT name, total
FROM `project-1.codelab_dataset.codelab-table`
ORDER BY total DESC
LIMIT 10;
该查询应能成功运行,因为 project-2 和 project-1 均未被限制使用 BigQuery。只要用户拥有适当的 IAM 权限,就可以随时随地访问 BigQuery。
此图说明了主账号查询 BigQuery 数据集时的流程。每个 BigQuery 查询都会启动一个 BigQuery 作业,然后该作业会执行实际操作(在本场景中为检索数据)。本示例演示了如何从 Compute Engine 实例和互联网访问主账号,同时从公共数据集和单独的 Google Cloud 项目进行查询。查询数据 (
GetData) 的过程成功完成,未被 VPC Service Controls 阻止。
4. 保护源数据集项目中的 BigQuery API
修改边界 perimeter-1 的配置,并限制 BigQuery API 服务以及受保护的资源 project-1。

验证服务边界强制执行
在 project-2 中,按照上一步中的说明在 BigQuery Studio 中运行以下查询:
SELECT name, total
FROM `project-1.codelab_dataset.codelab-table`
ORDER BY total DESC
LIMIT 10;
将发生 VPC Service Controls RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER 违规情况

违规审核日志将位于 project-1 中,因为违规跨越边界的行为发生在该位置。可以使用观测到的 vpcServiceControlsUniqueId 过滤日志(将 VPC_SC_DENIAL_UNIQUE_ID 替换为观测到的唯一 ID)。
severity=ERROR
resource.type="audited_resource"
protoPayload.metadata.@type="type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
protoPayload.metadata.vpcServiceControlsUniqueId="[*VPC_SC_DENIAL_UNIQUE_ID*]"
违规行为是 egressViolations,包含以下内容:
principalEmail:[运行查询的用户账号]callerIp:[运行查询的用户代理的 IP 地址]
"egressViolations": [
{
"targetResource": "projects/project-2",
"sourceType": "Resource",
"source": "projects/project-1",
"servicePerimeter": "accessPolicies/REDACTED/servicePerimeters/perimeter-1",
"targetResourcePermissions": [ "bigquery.jobs.create"]
} ],
5. 修正违规行为以创建 BigQuery 作业
此图展示了当正文从
project-2 针对 project-1 中的数据集运行查询时,由于服务边界 perimeter-1 保护 BigQuery API,因此从运行查询的项目 (project-2) 中的数据集项目 (project-1) 创建 BigQuery 作业的操作因 VPC Service Controls 出站违规而失败。在边界生效后,任何 BigQuery API 请求都无法从 project-1 发起,以访问边界外的资源,也无法从边界外发起,以访问受保护的项目;除非服务边界配置允许这样做。
您可以根据以下信息创建出站规则,以修正出站违规问题:
- 来源 (FROM):即用户电子邮件地址和上下文(例如:调用方 IP 地址、设备状态、位置等)
- 目的地 (TO):即目标资源、服务和方法或权限。
如需修正观察到的出站违规行为,请创建一条出站规则,以允许 BigQuery 服务上运行查询的用户账号 (user@example.com) 通过 bigquery.jobs.create 方法/ 权限访问目标资源 (project-2)。

配置的出站规则的预期行为:
- FROM | 身份:仅允许指定的身份
user@example.com跨越边界。 - TO | projects:只有在目标是指定项目
project-2的情况下,指定身份才能跨越边界。 - TO | 服务:仅当 API 调用针对指定服务和方法时,指定身份才能在边界之外启动流量,并仅针对指定项目。否则,例如,如果他们尝试使用受服务边界保护的其他服务,则操作会被阻止,因为不允许使用其他服务。
测试修复:出站流量规则
设置出站流量规则后,运行相同的查询。
SELECT name, total
FROM `project-1.codelab_dataset.codelab-table`
ORDER BY total DESC
LIMIT 10;
系统会再次违规,这次是 NO_MATCHING_ACCESS_LEVEL 入口违规。新违规行为与第一个违规行为在目标项目和方法方面有所不同。

新违规行为是入站流量违规行为,
principalEmail:[运行查询的用户账号]callerIp:[运行查询的用户代理的 IP 地址]
ingressViolations: [
0: {
servicePerimeter: "accessPolicies/REDACTED/servicePerimeters/perimeter-1"
targetResource: "projects/project-1"
targetResourcePermissions: [0: "bigquery.tables.getData"]}
]
bigquery.tables.getData 方法的违规行为是由于 BigQuery 作业尝试从 BigQuery 表中获取数据而发起的 API 调用所致。
6. 修复违规问题以获取 BigQuery 表数据
入站流量规则可修正入站流量违规问题,同时提供精细的控制,以确定哪些人可以跨越服务边界,以及允许的访问权限的上下文(例如源/ 目标项目以及他们可以访问的 API 方法)。
入站流量违规行为可通过以下配置的入站流量规则来修正:
- 来源 (FROM):即用户电子邮件地址和上下文(例如:调用方 IP 地址、设备状态、位置等)
- 目的地 (TO):即目标资源、服务和方法或权限。
入站流量规则将允许指定用户在指定服务和方法上向 project-1 发送流量。

配置的入站规则的预期行为:
- FROM | 身份:仅允许指定的身份
user@example.com跨越边界。 - TO | projects:只有在目标是指定项目
project-1的情况下,指定身份才能跨越边界。 - TO | 服务:仅当 API 调用是针对 BigQuery API 且指定的方法为
bigquery.tables.getData时,指定身份才能在边界内发起流量。
此后,执行相同的查询应能正常运行,而不会出现 VPC Service Controls 违规情况。
我们已成功在 project-1 中限制了 BigQuery API,使其只能由 user@example.com 使用,而不能由 user2@example.com 使用。
此图展示了两个不同的正文尝试查询同一数据集的方式。VPC Service Controls 会拒绝
user2@example.com(蓝色虚线)的访问,因为服务边界配置不允许它们从 project-1 运行 BigQuery 操作或向 project-1 运行 BigQuery 操作。user@example.com(绿色实线)的访问成功,因为 VPC Service Controls 配置允许他们从 project-1 执行操作以及向 project-1 执行操作。
7. 根据内部 IP 地址限制服务边界允许的流量
当前配置允许指定用户在 project-1 中从任何位置运行 BigQuery 查询;只要用户拥有查询数据的 IAM 权限,并且使用自己的账号,就可以从互联网上的任何位置运行查询。从安全角度来看,这意味着如果账号被盗用,任何获得该账号访问权限的个人都能够不受任何额外限制地访问 BigQuery 数据。
您还可以利用入站流量和出站流量规则中的访问权限级别来指定用户情境,从而实施进一步的限制。例如,您可以允许基于来源 IP 的访问,同时使用之前配置的入口规则(该规则授权通过调用方身份进行访问)。对于公共 IP CIDR 范围,如果用户客户端分配有公共 IP,则可以按来源 IP 进行访问;如果用户客户端在 Google Cloud 项目中运行,则可以采用内部 IP 地址。
创建具有内部 IP 地址访问权限条件的访问权限级别
在同一范围的访问权限政策文件夹下,打开 Access Context Manager 页面以创建访问权限级别。
- 在 Access Context Manager 页面上,选择创建访问权限级别。
- 在“新建访问权限级别”窗格中:
- 提供标题:您可以使用
codelab-al。 - 在“条件”部分中,点击 IP 子网。
- 选择专用 IP 标签页,然后点击选择 VPC 网络。
- 在添加 VPC 网络窗格中,您可以浏览并找到
default网络,也可以手动输入完整网络名称(格式为//compute.googleapis.com/projects/project-2/global/networks/default)。 - 点击添加 VPC 网络。
- 点击选择 IP 子网。
- 选择虚拟机实例所在的区域。在此 Codelab 中,该值为
us-central1。 - 点击保存。
- 提供标题:您可以使用
我们创建了一个访问权限级别,但该级别尚未在任何边界或入站/出站流量政策中强制执行。

向入站流量规则添加访问权限级别
为了强制要求入站流量规则允许的用户也通过访问权限级别验证,需要在入站流量规则中配置访问权限级别。授权访问查询数据的入站规则位于 perimeter-1 中。更改入站规则,将来源定义为访问权限级别 codelab-al。

测试新配置
在入站流量规则中添加访问权限级别后,除非从项目 project-2 的 VPC 网络 default 中的客户端执行,否则同一 BigQuery 查询将失败。如需验证此行为,请在端点设备连接到互联网时,通过 Google Cloud 控制台执行查询。查询将以失败告终,并显示入口违规情况。
您也可以从位于 project-2 中的 VPC 网络 default 运行相同的查询。同样,从位于 project-2 且使用 VPC 网络 default 的 Compute Engine 实例执行相同的 BigQuery 查询也会失败。这是因为入站规则仍配置为仅允许主账号 user@example.com。不过,虚拟机使用的是 Compute Engine 默认服务账号。
如需在 project-2 中从 Compute Engine 实例成功运行同一命令,请确保:
- 虚拟机具有使用 BigQuery API 的访问范围。为此,您可以选择授予对所有 Cloud API 的完整访问权限作为虚拟机的访问权限范围。
- 附加到虚拟机的服务账号需要具有以下 IAM 权限:
- 在
project-2中创建 BigQuery 作业 - 从位于
project-1中的 BigQuery 表获取 BigQuery 数据
- 在
- 默认 Compute Engine 服务账号需要获得入站和出站规则的许可。
现在,我们需要在入站规则中添加 Compute Engine 默认服务账号(以允许从 BigQuery 表获取数据),并在出站规则中添加该账号(以允许创建 BigQuery 作业)。

在 default VPC 网络中 project-2 的 Compute Engine 实例中,运行以下 bq 查询命令:
bq query --nouse_legacy_sql \
'SELECT name, total
FROM `project-1.codelab_dataset.codelab-table`
ORDER BY total DESC
LIMIT 10;'
在当前配置下,只有在以下情况下,BigQuery 命令才会成功:
- 在
project-2中使用默认 VPC 网络在虚拟机上运行,以及 - 位于指定的
us-central1区域(IP 子网),并且 - 使用服务边界中配置的默认 Compute Engine 服务账号运行。
如果从其他任何位置(包括以下位置)运行 BigQuery 命令查询,该查询都会失败:
- 如果在
project-2中使用默认 VPC 网络的虚拟机上运行,但该虚拟机位于与访问权限级别中添加的子网不同的区域,或者 - 如果由用户
user@example.com通过互联网上的用户客户端运行。
此图展示了同一正文
user@example.com 从两个不同位置(互联网和 Compute Engine 实例)发起的访问。VPC Service Controls 会阻止直接从互联网访问 BigQuery(蓝色虚线),但允许从虚拟机(绿色实线)访问 BigQuery(在模拟 Compute Engine 默认服务账号时)。之所以允许访问,是因为服务边界已配置为允许通过内部 IP 地址访问受保护的资源。
8. 清理
虽然在不使用 VPC Service Controls 时无需另行付费,但最好清理本实验中使用的设置。您还可以删除虚拟机实例和 BigQuery 数据集或 Google Cloud 项目,以避免产生费用。删除 Cloud 项目后,系统即会停止对该项目中使用的所有资源计费。
- 如需删除虚拟机实例,请完成以下步骤:
- 在 Google Cloud 控制台中,转到虚拟机实例页面。
- 选中虚拟机实例名称左侧的复选框,然后依次选择删除和删除以进行确认。

- 如需删除服务边界,请完成以下步骤:
- 在 Google Cloud 控制台中,选择安全,然后在访问权限政策的范围限定级别(在本例中为文件夹级别)选择 VPC Service Controls。
- 在 VPC Service Controls 页面上,点击与要删除的边界相对应的表行中的删除。
- 如需删除访问权限级别,请完成以下步骤:
- 在 Google Cloud 控制台中,打开文件夹级层范围的 Access Context Manager 页面。
- 在网格中,找到您要删除的访问权限级别所对应的行,选择三点状菜单,然后选择删除。
- 如需关闭项目,请完成以下步骤:
- 在 Google Cloud 控制台中,前往要删除的项目对应的 IAM 和管理设置页面。
- 在“IAM 和管理设置”页面上,选择关停。
- 输入项目 ID,然后选择仍要关停。
9. 恭喜!
在此 Codelab 中,您创建了 VPC Service Controls 边界、强制执行了该边界并对其进行了问题排查。
了解详情
您还可以探索以下场景:
- 在项目受到 VPC Service Controls 保护后,对公共数据集运行相同的查询。
- 在与
project-1相同的边界内添加project-2。 - 将
project-2添加到其自己的边界,并将project-1保留在当前边界中。 - 运行查询以更新表中的数据,而不仅仅是检索数据。
许可
此作品已获得 Creative Commons Attribution 2.0 通用许可授权。