1. 简介
VPC Service Controls (VPC-SC) 是 Google Cloud 中的一种组织级安全控制措施,可帮助企业客户降低数据渗漏风险。VPC Service Controls 提供对多租户服务的零信任访问模式,让客户端在从互联网和其他服务连接到多租户服务时,能够限制对经过授权的 IP、客户端情境和设备参数的访问,从而减少有意和无意的损失。正如我们在 VPC Service Controls 基本教程 I 中所见,您可以使用 VPC Service Controls 创建边界,该边界可保护您明确指定的服务的资源和数据。
本教程的目标如下:
- 了解 VPC Service Controls 的基础知识
- 更新服务边界并使用试运行模式对其进行测试
- 使用 VPC Service Controls 保护两项服务
- 排查从 Cloud Storage 列出对象时出现的 VPC Service Controls 出站流量违规问题
2. 设置和要求
在本教程中,我们需要满足以下前提条件:
- GCP 组织。
- 组织下的文件夹。
- 同一组织内放置在文件夹下的 2 个 GCP 项目。
- 组织级所需权限。
- 两个项目的结算账号。
- VPC Service Controls 基本教程 I:VPC Service Controls 和 Access Context Manager 设置。

资源设置
- 按照 VPC Service Controls 基本教程 I 的“资源设置”部分中的说明设置资源
- 验证您是否拥有管理 Cloud Storage 所需的权限。
- 在本教程中,我们将开始使用 CLI 而不是 Cloud 控制台。在以下开发环境之一中,设置 gcloud CLI:
- Cloud Shell:如需使用已设置 gcloud CLI 的在线终端,请激活 Cloud Shell。
点击云控制台右上角的图标,激活 Cloud Shell。该会话可能需要几秒钟来完成初始化。如需了解详情,请参阅 Cloud Shell 指南。

费用
您需要在 Cloud 控制台中启用结算功能,才能使用 Cloud 资源/API。运行此 Codelab 应该不会产生太多的费用(如果有的话)。若要关闭资源以避免产生超出本教程范围的结算费用,您可以删除自己创建的资源或删除项目。Google Cloud 新用户符合参与 300 美元免费试用计划的条件。
唯一会产生费用的资源是虚拟机实例和 Cloud Storage 对象。您可以在价格计算器中找到虚拟机实例的估算费用。如需了解 Cloud Storage 的估算费用,请参阅此价格表。
3. 创建存储分区和对象
如前所述,我们将重复使用在上一个教程中创建的资源。因此,我们将继续创建 Cloud Storage 存储分区。在本教程中,我们将开始使用 gcloud CLI 而不是控制台。
- 在 Google 控制台中,选择 ProjectX。在此项目中,我们将创建存储分区和对象。
- 运行以下命令,确保您已将 Cloud Shell 设置为使用 ProjectX:
gcloud config set project PROJECT_ID
- 在开发环境中,运行以下命令:
gcloud storage buckets create gs://BUCKET_NAME --location=us-central1
- 创建一个存储对象,以便我们可以从位于 ProjectZ 中的虚拟机实例读取该对象。我们将创建一个 .txt 文件。
nano hello.txt
在文本文件中添加任何所需内容。
- 将对象上传到存储分区。
gcloud storage cp /home/${USER}/hello.txt gs://BUCKET_NAME
- 通过列出对象来验证对象是否已上传到存储分区中。
gcloud storage ls gs://BUCKET_NAME
您必须在控制台中看到列出的 hello.txt 文件。
4. 保护 Cloud Storage API
在上一个 Codelab 中,我们创建了一个边界并保护了 Compute Engine API。在此 Codelab 中,我们将修改试运行模式的边界并添加 Cloud Storage。这有助于我们确定边界保护的影响,因为审核日志中会显示 VPC Service Controls 违规情况,但在我们强制执行边界之前,资源仍可访问。
- 在 Google 控制台中,选择您的组织; 访问 VPC Service Controls。确保您位于组织范围内。
- 打开 Cloud Shell 并更新在上一个实验中创建的试运行边界“SuperProtection”:
gcloud access-context-manager perimeters dry-run update SuperProtection --policy=POLICY --add-restricted-services=storage.googleapis.com
- 通过描述安全边界来验证 Cloud Storage API 是否已更新
gcloud access-context-manager perimeters dry-run describe SuperProtection --policy=POLICY
在输出中,您会看到 Cloud Storage API 列在受限服务下方
以及 Compute Engine API,但带有“-vpcAccessibleServices: {}"”标签:

5. 验证 Cloud Storage API 是否已受到保护
在试运行模式下,通过列出从 ProjectZ 中创建的虚拟机实例到托管存储分区的 ProjectX 的对象,验证“SuperProtection”边界是否显示拒绝
- 在 Cloud 控制台中,前往项目选择器并选择 ProjectZ,然后依次前往 Compute Engine > 虚拟机实例。
- 点击“SSH”按钮以连接到虚拟机实例并访问其命令行。

- 列出我们之前上传的 hello.txt 文件。
gcloud storage ls gs://BUCKET_NAME
由于 Cloud Storage API 在试运行模式下受到保护,因此您应该能够列出资源,但必须在 ProjectZ 审核日志中看到错误消息。
- 前往 ProjectZ 中的 Logs Explorer API,然后查找 VPC Service Controls 上次错误消息。您可以使用此过滤条件获取我们所需的日志:
protoPayload.status.details.violations.type="VPC_SERVICE_CONTROLS" "(Dry Run Mode) Request is prohibited by organization's policy. vpcServiceControlsUniqueIdentifier:UNIQUE_ID"
此过滤条件将显示在 Cloud Storage 中以预运行模式发生的最后一次违规。以下示例展示了日志的显示方式,我们可以验证,当尝试列出 ProjectX 中存储分区的内容时,违规行为是出站流量违规。
egressViolations: [
0: {
servicePerimeter: "accessPolicies/POLICY/servicePerimeters/SuperProtection"
source: "projects/PROJECTX_ID"
sourceType: "Network"
targetResource: "projects/PROJECTZ_ID"
}
]
resourceNames: [
0: "projects//buckets/BUCKET_NAME"
]
securityPolicyInfo: {
organizationId: "ORGANIZATION_ID"
servicePerimeterName: "accessPolicies/POLICY/servicePerimeters/SuperProtection"
}
violationReason: "NETWORK_NOT_IN_SAME_SERVICE_PERIMETER"
vpcServiceControlsUniqueId: "UNIQUE_ID"
}
methodName: "google.storage.objects.list"
- 由于我们已验证对 Cloud Storage 的 API 调用会生成 VPC Service Controls 违规行为,因此我们将使用新配置强制执行边界。打开 Cloud Shell 并强制执行试运行边界:
gcloud access-context-manager perimeters dry-run enforce SuperProtection --policy=POLICY --async
- 使用 SSH 连接到虚拟机实例,然后再次列出存储分区,以验证是否已正确强制执行试运行边界。
gcloud storage ls gs://BUCKET_NAME
我们将在虚拟机 CLI 中收到 VPC Service Controls 违规消息,而不是存储对象的列表:
ERROR: (gcloud.storage.ls) User [PROJECT_NUMBER-compute@developer.gserviceaccount.com] does not have permission to access b instance [BUCKET_NAME] (or it may not exist): Request is prohibited by organization's policy. vpcServiceControlsUniqueIdentifier:"UNIQUE_ID"
我们已成功使用 VPC Service Controls 阻止从边界外的资源读取数据或将数据复制到边界外的资源,从而防止数据渗漏。
6. 排查列表拒绝问题。
我们将排查从虚拟机实例 CLI 收到的拒绝。我们来检查审核日志,查找 VPC Service Controls 唯一 ID。
- 前往项目选择器,然后选择 ProjectZ。
- 在 Logs Explorer 中使用以下查询,在审核日志中查找 VPC Service Controls 唯一 ID:
resource.type="audited_resource" protoPayload.metadata."@type"="type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
这会显示所有 VPC Service Controls 审核日志。我们将查找最后一个错误日志。由于 API 调用是从虚拟机实例发出的,因此正文必须是 Compute Engine 服务账号“PROJECT_NUMBER-compute@developer.gserviceaccount.com"
由于我们已经有了 VPC Service Controls 唯一 ID,因此可以使用以下过滤条件直接获取所需的日志:
protoPayload.metadata.vpcServiceControlsUniqueId="UNIQUE_ID"
- 点击 VPC Service Controls 标题,然后选择“排查拒绝问题”,系统随即会打开 VPC Service Controls 问题排查工具。
此 API 将在友好的界面中向我们显示违规原因,以及违规行为是入站流量违规还是出站流量违规等其他实用信息。
在本练习中,我们将寻找以下内容:
authenticationInfo: {
principalEmail: "PROJECT_ID-compute@developer.gserviceaccount.com"
egressViolations: [
0: {
servicePerimeter: "accessPolicies/POLICY/servicePerimeters/SuperProtection"
source: "projects/PROJECTZ_ID"
sourceType: "Network"
targetResource: "projects/PROJECTX_ID"
}
violationReason: "NETWORK_NOT_IN_SAME_SERVICE_PERIMETER"
有了这些信息,我们就知道需要创建出站规则,以允许 Compute Engine 服务账号从 ProjectZ 访问 ProjectX 中的存储分区。我们还可以看到,网络不在同一边界内,因此我们需要允许 VPC 与服务通信,并在服务边界之间共享数据。
- 激活 Cloud Shell,然后使用文本编辑器创建包含出站规则的 .yaml 文件。
nano egresstorage.yaml
- egressTo:
operations:
- serviceName: storage.googleapis.com
methodSelectors:
- method: \"*\"
resources:
- projects/PROJECTX_ID
egressFrom:
identities:
- serviceAccount:PROJECT_ID-compute@developer.gserviceaccount.com
- 更新用于保护 ProjectZ 的入站政策。
gcloud access-context-manager perimeters update SuperProtection --set-egress-policies=egresstorage.yaml --policy=POLICY
现在,我们可以再次尝试从虚拟机实例访问该存储分区。
- 在 Cloud 控制台中,前往项目选择器并选择 ProjectZ,然后依次前往 Compute Engine > 虚拟机实例。
- 点击“SSH”按钮以连接到虚拟机实例并访问其命令行。
- 进入虚拟机 CLI 后,尝试列出存储分区中的对象。
gcloud storage ls gs://BUCKET_NAME/
您会收到以下错误消息:
ERROR: (gcloud.storage.ls) User [PROJECT_ID-compute@developer.gserviceaccount.com] does not have permission to access b instance [BUCKET_NAME] (or it may not exist): PROJECT_ID-compute@developer.gserviceaccount.com does not have storage.objects.list access to the Google Cloud Storage bucket. Permission 'storage.objects.list' denied on resource (or it may not exist).
- 我们需要向 Compute Engine 服务账号授予对象读取者权限,以便能够列出存储分区中的对象。
gcloud storage buckets add-iam-policy-binding gs://BUCKET_NAME --member=serviceAccount:PROJECT_ID-compute@developer.gserviceaccount.com --role=roles/storage.objectViewer
- 我们再次尝试从虚拟机实例的 CLI 中列出 hello.txt 文件。
gcloud storage ls gs://BUCKET_NAME/ . . gs://BUCKET_NAME/hello.txt
现在,我们可以在不违反 VPC Service Controls 权限的情况下列出对象,但下载文件又会怎么样呢?我们来试试看
gcloud storage cp gs://BUCKET_NAME/hello.txt /home/${USER}
我们将获得以下输出
Copying gs://BUCKET_NAME/hello.txt to file:///home/${USER}
Completed files 1/1 | 54.0B/54.0B
7. 清理
虽然在不使用 VPC Service Controls 时无需另行付费,但最好清理本实验中使用的设置。您还可以删除虚拟机实例和/或 Cloud 项目,以避免产生费用。删除 Cloud 项目后,系统即会停止对该项目中使用的所有资源计费。
- 如需删除虚拟机实例,请选中虚拟机实例名称左侧的复选框,然后点击删除。

- 如需删除安全边界,请完成以下步骤:
- 在 Google Cloud 控制台中,点击安全,然后在组织范围内点击 VPC Service Controls。
- 在 VPC Service Controls 页面上,点击要删除的边界对应的表格行中的“删除图标”
- 如需删除访问权限级别,请完成以下步骤:
- 在 Google Cloud 控制台中,打开文件夹级层范围的 Access Context Manager 页面。
- 在网格中,针对您要删除的访问权限级别所对应行,点击“删除图标”,然后点击删除。
- 如需删除 Storage 对象和存储分区,请完成以下步骤:
- 在 Google Cloud 控制台中,打开 Cloud Storage 存储分区页面。
- 选中所创建存储分区旁边的复选框。
- 点击删除。
- 在随即打开的窗口中,确认您要删除相应存储分区。
- 点击删除。
- 如需关闭项目,请完成以下步骤:
- 在 Google Cloud 控制台中,前往要删除的项目对应的 IAM 和管理设置页面。
- 在“IAM 和管理”设置页面上,点击关停。
- 输入项目 ID,然后点击仍要关停。
8. 恭喜!
在此 Codelab 中,您更新了 VPC Service Controls 试运行边界,强制执行了该边界,并对其进行了问题排查。
了解详情
- 请参阅 VPC Service Controls 文档。
- 请参阅 Access Context Manager 文档。
- 请参阅 VPC-SC 问题排查工具文档。
- 请参阅入站和出站规则文档。
- 请参阅试运行文档 。
- 请参阅 Cloud Storage 文档。
许可
此作品已获得 Creative Commons Attribution 2.0 通用许可授权。