VPC Service Controls 基本教程 II - 排查出站流量违规问题

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 设置。

dbec101f41102ca2.png

资源设置

  1. 按照 VPC Service Controls 基本教程 I 的“资源设置”部分中的说明设置资源
  2. 验证您是否拥有管理 Cloud Storage 所需的权限
  3. 在本教程中,我们将开始使用 CLI 而不是 Cloud 控制台。在以下开发环境之一中,设置 gcloud CLI:
  • Cloud Shell:如需使用已设置 gcloud CLI 的在线终端,请激活 Cloud Shell。

点击云控制台右上角的图标,激活 Cloud Shell。该会话可能需要几秒钟来完成初始化。如需了解详情,请参阅 Cloud Shell 指南

a0ceb29950db4eac.png

  • 本地 shell:如需使用本地开发环境,请安装初始化 gcloud CLI。

费用

您需要在 Cloud 控制台中启用结算功能,才能使用 Cloud 资源/API。运行此 Codelab 应该不会产生太多的费用(如果有的话)。若要关闭资源以避免产生超出本教程范围的结算费用,您可以删除自己创建的资源或删除项目。Google Cloud 新用户符合参与 300 美元免费试用计划的条件。

唯一会产生费用的资源是虚拟机实例和 Cloud Storage 对象。您可以在价格计算器中找到虚拟机实例的估算费用。如需了解 Cloud Storage 的估算费用,请参阅此价格表

3. 创建存储分区和对象

如前所述,我们将重复使用在上一个教程中创建的资源。因此,我们将继续创建 Cloud Storage 存储分区。在本教程中,我们将开始使用 gcloud CLI 而不是控制台。

  1. 在 Google 控制台中,选择 ProjectX。在此项目中,我们将创建存储分区和对象。
  2. 运行以下命令,确保您已将 Cloud Shell 设置为使用 ProjectX:
gcloud config set project PROJECT_ID
  1. 在开发环境中,运行以下命令:
gcloud storage buckets create gs://BUCKET_NAME --location=us-central1
  1. 创建一个存储对象,以便我们可以从位于 ProjectZ 中的虚拟机实例读取该对象。我们将创建一个 .txt 文件。
nano hello.txt 

在文本文件中添加任何所需内容。

  1. 将对象上传到存储分区。
gcloud storage cp /home/${USER}/hello.txt gs://BUCKET_NAME
  1. 通过列出对象来验证对象是否已上传到存储分区中。
gcloud storage ls gs://BUCKET_NAME

您必须在控制台中看到列出的 hello.txt 文件。

4. 保护 Cloud Storage API

在上一个 Codelab 中,我们创建了一个边界并保护了 Compute Engine API。在此 Codelab 中,我们将修改试运行模式的边界并添加 Cloud Storage。这有助于我们确定边界保护的影响,因为审核日志中会显示 VPC Service Controls 违规情况,但在我们强制执行边界之前,资源仍可访问。

  1. 在 Google 控制台中,选择您的组织; 访问 VPC Service Controls。确保您位于组织范围内。
  2. 打开 Cloud Shell 并更新在上一个实验中创建的试运行边界“SuperProtection”:
gcloud access-context-manager perimeters dry-run update SuperProtection --policy=POLICY --add-restricted-services=storage.googleapis.com
  1. 通过描述安全边界来验证 Cloud Storage API 是否已更新
gcloud access-context-manager perimeters dry-run describe SuperProtection --policy=POLICY 

在输出中,您会看到 Cloud Storage API 列在受限服务下方

以及 Compute Engine API,但带有“-vpcAccessibleServices: {}"”标签:

2025ddc01a2e9a81.png

5. 验证 Cloud Storage API 是否已受到保护

在试运行模式下,通过列出从 ProjectZ 中创建的虚拟机实例到托管存储分区的 ProjectX 的对象,验证“SuperProtection”边界是否显示拒绝

  1. 在 Cloud 控制台中,前往项目选择器并选择 ProjectZ,然后依次前往 Compute Engine > 虚拟机实例
  2. 点击“SSH”按钮以连接到虚拟机实例并访问其命令行。

5ca02149b78c11f9.png

  1. 列出我们之前上传的 hello.txt 文件。
gcloud storage ls gs://BUCKET_NAME

由于 Cloud Storage API 在试运行模式下受到保护,因此您应该能够列出资源,但必须在 ProjectZ 审核日志中看到错误消息。

  1. 前往 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"
  1. 由于我们已验证对 Cloud Storage 的 API 调用会生成 VPC Service Controls 违规行为,因此我们将使用新配置强制执行边界。打开 Cloud Shell 并强制执行试运行边界:
gcloud access-context-manager perimeters dry-run enforce SuperProtection --policy=POLICY --async
  1. 使用 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。

  1. 前往项目选择器,然后选择 ProjectZ。
  2. 在 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"
  1. 点击 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 与服务通信,并在服务边界之间共享数据。

  1. 激活 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
  1. 更新用于保护 ProjectZ 的入站政策。
gcloud access-context-manager perimeters update SuperProtection --set-egress-policies=egresstorage.yaml --policy=POLICY 

现在,我们可以再次尝试从虚拟机实例访问该存储分区。

  1. 在 Cloud 控制台中,前往项目选择器并选择 ProjectZ,然后依次前往 Compute Engine > 虚拟机实例
  2. 点击“SSH”按钮以连接到虚拟机实例并访问其命令行。
  3. 进入虚拟机 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).
  1. 我们需要向 Compute Engine 服务账号授予对象读取者权限,以便能够列出存储分区中的对象。
gcloud storage buckets add-iam-policy-binding gs://BUCKET_NAME --member=serviceAccount:PROJECT_ID-compute@developer.gserviceaccount.com --role=roles/storage.objectViewer
  1. 我们再次尝试从虚拟机实例的 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 项目后,系统即会停止对该项目中使用的所有资源计费。

  1. 如需删除虚拟机实例,请选中虚拟机实例名称左侧的复选框,然后点击删除

da0abf0894fe03cd.png

  1. 如需删除安全边界,请完成以下步骤:
  • 在 Google Cloud 控制台中,点击安全,然后在组织范围内点击 VPC Service Controls
  • 在 VPC Service Controls 页面上,点击要删除的边界对应的表格行中的“删除图标”
  1. 如需删除访问权限级别,请完成以下步骤:
  • 在 Google Cloud 控制台中,打开文件夹级层范围的 Access Context Manager 页面。
  • 在网格中,针对您要删除的访问权限级别所对应行,点击“删除图标”,然后点击删除
  1. 如需删除 Storage 对象和存储分区,请完成以下步骤:
  • 在 Google Cloud 控制台中,打开 Cloud Storage 存储分区页面
  • 选中所创建存储分区旁边的复选框。
  • 点击删除
  • 在随即打开的窗口中,确认您要删除相应存储分区。
  • 点击删除
  1. 如需关闭项目,请完成以下步骤:
  • 在 Google Cloud 控制台中,前往要删除的项目对应的 IAM 和管理设置页面。
  • 在“IAM 和管理”设置页面上,点击关停
  • 输入项目 ID,然后点击仍要关停

8. 恭喜!

在此 Codelab 中,您更新了 VPC Service Controls 试运行边界,强制执行了该边界,并对其进行了问题排查。

了解详情

许可

此作品已获得 Creative Commons Attribution 2.0 通用许可授权。