AWS 工程师的 GCP 指南:您的 AWS 直觉如何转化(以及何时失效)
您已经知道如何在 AWS 中组织账户、分配权限和引导状态。本文将介绍如何在 Google Cloud 中完成同样的事情 - 哪些概念可以顺利转换,以及您的 AWS 肌肉记忆会在哪四个地方积极误导您。
如果您精通 AWS,现在正面对 Google Cloud,好消息是您约 80% 的直觉可以直接迁移:这里有组织事物的层级结构、基于角色的访问授权方式、用于无密钥 CI 的 OIDC 方案,以及“冷启动您的状态后端”引导流程。坏消息是另外 20% - 它集中在几个高频区域,在这些地方,按照 AWS 的做法会导致令人困惑的拒绝,而不是明显的错误。本文是翻译层:您在 AWS 中完成的相同工作,在 GCP 中如何完成,并指出其中的陷阱。
如果您只读一段话,简而言之:GCP 的层级结构(organization -> folder -> project -> resource)可以清晰地映射到 AWS Organizations -> OU -> account -> resource,但有三件事会打破您的肌肉记忆。IAM 是一种仅允许的策略,绑定到资源树并向下继承 - 没有策略附加到用户。项目的服务 API 默认都是关闭的,在您启用每个 API 之前,什么都无法工作。而且您不承担角色(assume roles),而是模拟服务账户(impersonate service accounts),服务账户本身是具有自己访问策略的资源。 下文将详细阐述这些内容。
最大的转变:权限存在于树上,而非身份上
在 AWS 中,心智模型是“将策略附加到身份”。您创建一个用户或角色,将 JSON 附加到它,权限就会随主体一起移动。资源策略确实存在,但身份附加策略是重心。
GCP 则颠倒了这一点。一个 IAM 策略是一组绑定 - (member, role) 对 - 附加到资源层级结构中的一个节点(organization、folder、project 或单个 resource)。策略存在于被访问的事物上,而不是执行访问的身份上。您在任何时候的有效访问权限是从根节点向下继承到该节点的所有绑定的并集。 在 folder 级别向一个组授予 roles/compute.admin,该 folder 下的所有 project 都会继承它。
如果您接触过 Azure RBAC,这会感觉很熟悉 - 它是带有向下继承的范围角色。这条规则可以帮助您:
当 GCP 拒绝某项操作时,不要再寻找“用户上的策略”。寻找 org、folder、project 或 resource 上的绑定 - 并记住它会向下继承,因此重要的授权可能在三级以上。
与 AWS 不同的几个具体细节:
- 角色分为三类。 Primitive 角色(
roles/owner、roles/editor、roles/viewer)是粗粒度的传统三件套 - 在实际环境中应避免使用。Predefined 角色是您应该实际使用的细粒度服务级角色(roles/storage.objectViewer、roles/compute.instanceAdmin.v1等)。当预定义角色集过于宽泛时,您可以编写 Custom 角色。 - 基本模型是累加的,且仅允许。 不像 AWS 那样,每个策略中都没有嵌入
Effect: Deny语句。有效访问权限只是允许的并集。 - 拒绝是一个单独的层。 当您确实需要一个硬性“无论如何都不能”时,您会编写一个 IAM deny policy - 一个附加到 org/folder/project 的独立对象,它在允许之前进行评估。这是最接近内联
Deny语句的东西,但它是故意脱离常规的。 - 防护措施是第三种机制:Organization Policy Service。 像
constraints/compute.vmExternalIpAccess或constraints/iam.disableServiceAccountKeyCreation这样的约束是 GCP 中 SCP 的对应物。它们附加在 org/folder/project 级别,向下继承,并限制可以存在或配置什么,而不是谁可以调用什么。将其视为“SCP 形态的防护措施”,而不是“IAM 角色”。
因此,AWS 在 IAM 内部提供了一种允许/拒绝语法,而 GCP 则将这项工作分散到允许绑定、拒绝策略和组织策略约束中。结果相同,机制有三种。
一切皆 project - 且其 API 默认关闭
project 是 GCP 的基本单元。它大致相当于 AWS account:一个隔离边界、一个 IAM 范围和一个计费目标,三者合一。但 project 比 account 轻量得多 - 创建成本低,易于删除,旨在大量创建。典型的模式是每个工作负载每个环境一个 project(app-qa、app-prod),而不是少数几个通过标签划分的共享 account。
关于 project 的三件事在 AWS 中没有清晰的对应物:
- 一个 project 有三个标识符,它们的区别很关键。 project ID 是一个全球唯一、人工选择的不可变字符串(
acme-app-prod-7f3a)- 几乎所有命令和资源路径中都会用到它。project number 是 GCP 分配的一个全球唯一整数。display name 是可变的,用于显示。请仔细选择 ID;您永远无法更改它。 - 服务 API 默认是关闭的。 这是最常见的首次使用时遇到的问题。在您创建 VM 之前,您需要启用
compute.googleapis.com;在创建 bucket 之前,需要启用storage.googleapis.com;依此类推,每个 project 都是如此。您在 GCP 上遇到的第一个“拒绝”通常根本不是缺少 IAM 角色 - 而是API [compute.googleapis.com] not enabled on project。在 AWS 中,服务是现成的;在 GCP 中,每个 project 都是一张白纸,您需要精确地开启您打算使用的功能。(在 Terraform 中,这是google_project_service;在 CLI 中,是gcloud services enable。) - project 是自然的爆炸半径和配额边界。 配额、预算和大多数默认设置都是按 project 计算的,因此为实验启动一个新的 project 是正常的、廉价的操作 - 而不是 AWS account 那样的繁琐仪式。
服务账户:您模拟,而非承担
在 AWS 中,角色是一组权限,主体通过 STS 承担(assume),并由信任策略(trust policy)进行门控。在 GCP 中,等效的主力是 service account (SA),它的工作方式不同,这会让每个 AWS 工程师感到困惑。
service account 既是身份,也是资源。 它有一个电子邮件地址(deployer@acme-app-prod.iam.gserviceaccount.com),它存在于一个 project 内部,而且 - 至关重要的是 - 它有自己的 IAM 策略来管理谁可以使用它。 后半部分是 AWS 用户没有的反射:
- 要作为 service account 行事,主体需要在 SA 本身上拥有一个角色 -
roles/iam.serviceAccountTokenCreator(用于生成短期令牌并模拟它)或roles/iam.serviceAccountUser(用于将其附加到您正在创建的资源,例如 VM 或 Cloud Run 服务)。这是 AWS 用户容易忘记的双向授权:如果您的 CI 主体无法成为部署 SA,那么赋予它广泛的 project 权限是无用的。 - 您通过请求令牌(
generateAccessToken)来模拟(impersonate)SA,而不是通过信任策略握手来承担角色。模拟权限作为普通的 IAM 绑定存在于 SA 资源上 - 没有单独的信任文档。 - service account 密钥存在,但您应尽量避免使用它们。 下载的 JSON 密钥是长期凭证,也是经典的泄露途径;许多组织通过前面提到的约束在组织范围内禁用密钥创建。无密钥替代方案是您应该选择的。
- 无密钥 CI 是 Workload Identity Federation - 与 AWS 的 OIDC federation 相同的 OIDC 理念。您的 GitHub Actions 或外部工作负载提供一个 OIDC 令牌,工作负载身份池信任颁发者,GCP 返回 SA 的短期凭证。没有存储的秘密。(在 GKE 内部,对应的是 Workload Identity,它将 Kubernetes service account 绑定到 Google service account - 直接对应 AWS 的 IRSA。)
一句话翻译:您通过信任策略承担的 AWS 角色变成了您通过SA 上的令牌创建者绑定模拟的 GCP service account。
身份域:Cloud Identity、Workspace 和 org
GCP 确实将身份与资源分离,但比 Azure 温和得多。organization 节点是针对由 Cloud Identity 或 Google Workspace 账户拥有的已验证域创建的。该目录 - 用户和组 - 在 Admin console(admin.google.com)中管理,这与您管理资源的 Cloud console 是不同的界面。
- 用户和组在目录中创建;访问权限在 IAM 中授予。 您不会像在 AWS 中创建 IAM 用户那样创建“GCP 用户”。人员存在于 Cloud Identity/Workspace 中(或从您的 IdP 联合进来),您在资源树的 IAM 绑定中引用他们 - 理想情况下是作为一个组 - 在 IAM 绑定中。最佳实践是绑定到组,而不是绑定到单个用户。
- 没有像 AWS 那样独立的“IAM users”存储。 外部 IdP(Okta、Entra ID 等)联合到 Cloud Identity;这是员工访问的常态。
- 需要记住的两个“坑”: 特殊成员
allUsers(字面上是互联网上的任何人,未经身份验证)和allAuthenticatedUsers(拥有任何 Google 账户的任何人)。将角色绑定到其中任何一个都会导致 bucket 意外公开。对待它们的方式就像您对待 S3 bucket 策略中的Principal: "*"一样。
粗略的类比:organization 加上其 Cloud Identity 域大致是“一个与 IAM Identity Center 目录融合的 AWS Organization” - 但日常资源工作是通过树上的 IAM 绑定完成的,而不是通过身份附加策略。
Billing 是一个独立对象,您将其链接到 project
GCP 中的 billing account 是它自己的资源 - 它不是 org -> folder -> project 层级结构中的一个节点。project 链接到一个 billing account(每个 project 恰好链接到一个),一个 billing account 可以为多个 project 提供资金。
- 它有自己的 IAM。
roles/billing.admin、roles/billing.user、roles/billing.creator存在于 billing account 上,与您的资源角色分开。特别是,要将一个新 project 附加到 billing account,您需要在该 billing account 上拥有roles/billing.user- 仅仅拥有广泛的 project 权限是不够的。 - “我可以部署”并不能说明“我可以创建一个可计费的 project”。 要建立一个可以产生费用的 project,您需要同时拥有
resourcemanager.projectCreator(在 org/folder 级别)和billing.user(在 billing account 上)。如果缺少第二个,project 创建会半成功,但该 project 实际上无法运行任何东西。
这比 Azure 严格的商业平面墙要柔和 - GCP billing 确实与 Cloud IAM 连接,因此它显示在相同的 gcloud 和 Terraform 界面中,而不是一个完全独立的世界。但它仍然是一个具有不同角色的独立对象,它是继未启用 API 之后第二常见的“但我是一个管理员”的意外。
名称、ID 和一个网络意外
每个 GCP 资源都有一个相对资源名称,例如 projects/acme-app-prod/zones/us-central1-a/instances/web-1(以及一个完全限定的 //compute.googleapis.com/... 形式)。project ID 随每个日志行和 API 调用一起传输 - 就像 AWS 中 ARN 的 account 所做的工作一样 - 因此,与 Azure 类似,您的资源名称可以省略 project 已经编码的内容。相同的短名称可以在您的 -dev、-qa 和 -prod project 中安全地重复。
值得提前指出的网络陷阱,因为它悄悄地违反了 AWS 的直觉:GCP 中的 VPC network 是一个全球资源,其 subnets 是区域性的。 在 AWS 中,VPC 范围限定在一个区域;在 GCP 中,一个 VPC 跨越所有区域,您可以在其中划分区域性 subnets。一个带有区域性 subnets 的单一全球 VPC 是默认设置,而不是一种奇特的多区域设置 - 不要为了 subnet 已经提供给您的功能而寻求 VPC peering。
AWS -> GCP 快速映射
第一个月请将此放在手边:
- Organization -> organization。概念相同,但 GCP org 绑定到您的 Cloud Identity/Workspace 域。
- Organizational Unit (OU) -> folder。可嵌套的分组节点;folder 可以包含 folder。
- Account -> project。隔离、IAM 和计费单元 - 但轻量且可一次性使用,可大量创建。
- SCP (guardrail) -> Organization Policy constraint 在 org/folder/project 范围 - 限制可以存在或配置什么,向下继承。
- IAM identity-attached policy -> IAM binding
(member, role)在树节点上。 用户上没有策略;授权存在于资源上并向下继承。 - 您承担的 IAM 角色(通过 STS + trust policy) -> 您模拟的 service account(通过 SA 上的 token-creator binding)。记住双向授权。
- 显式
Deny语句 -> IAM deny policy - 一个独立对象,在允许之前进行评估。 - IRSA (IAM Roles for Service Accounts) -> Workload Identity (GKE) / Workload Identity Federation (外部 CI) - 相同的 OIDC 理念,无密钥。
- “服务随时可用” -> 首先为每个 project 启用其 API(
google_project_service)。AWS 没有对应物。 - 日志中的 ARN -> 资源名称(
projects/<id>/...);project 上下文是结构化的,而不是名称编码的。
引导 Terraform 状态,翻译
这里是您的 AWS 运行手册几乎有效,但在第一步就失效的地方。
您所知的 AWS 引导流程:在管理账户中冷启动一个状态后端(本地状态,然后将后端迁移到自身),将每个 OU 后端的状态保存在该根后端中,并使用其自己的后端创建成员账户。使其清晰的不变性是您始终可以从管理账户引导,因为它始终存在并且可以容纳一个 S3 bucket。
GCP 在初始阶段打破了这种不变性,就像 Azure 一样:始终存在的对象是 organization,但 org 节点不能容纳资源。GCS bucket 存在于一个 project 中,而 project 需要一个父级,以及(要真正做任何事情)一个计费链接和启用的 API。因此,GCP 的“根账户”是您有意识地加冕的种子 project - 惯用名称类似于 prj-bootstrap 或 Cloud Foundation Toolkit 种子 project。
当 org 和 billing account 已经存在时(常见情况)的翻译流程:
- 一次性冷启动: 命令式地创建种子 project(
gcloud projects create),在其上启用引导 API(cloudresourcemanager、cloudbilling、serviceusage、iam、storage),链接计费,并使用本地 Terraform 状态创建 GCS 状态 bucket - 然后init -migrate-state到该 bucket 中。 - 一个具有 org 级别角色的引导 service account: 在 organization 节点上授予它
resourcemanager.projectCreator、billing.user以及您的 org-policy/IAM 管理角色,以便它可以创建和管理所有下游 project。 - 其余一切都是正常的 apply: 额外的 project、folder 及其资源由 Terraform 模拟该引导 SA 创建,每个 project 的状态都存在于一个 GCS 后端中的
prefix下。
从零开始,顺序是强制的 - 种子 project 优先,状态 bucket 次之 - 因为后端就是一个 GCS bucket,而 bucket 需要一个 project 才能存在。并且有一个小的鸡生蛋、蛋生鸡的问题,就像 Azure 一样:google provider 需要一个 project 和启用的 API 才能做任何事情,所以您需要通过命令式 gcloud 调用创建第一个 project 并启用其 API,然后将其纳入 Terraform。(terraform-google-modules/bootstrap 模块正是封装了这种种子 project 加 SA 的流程。)
而这正是 GCP 比 AWS 肌肉记忆更简单的地方:种子 project 中的后端加上成员中的资源不需要 AWS 的任何中心辐射式信任机制 - 没有后端 role_arn,没有 provider assume_role,也没有双向信任策略。一个具有正确角色的 org 级别 service account 在整个组织中都有效,因为 IAM 向下继承;provider 通过简单地设置 project 在 project 之间“跳转”;并通过设置 impersonate_service_account 成为部署者身份。跨 project 是一个参数,而不是信任协商。(您稍后会通过自定义角色、每个 project 的 SA 和专用 CI 身份来收紧这一点 - 但即使如此,它也是范围内的角色绑定,而不是信任策略握手。)如果您想深入了解如何编码任一方,HashiCorp Terraform Authoring & Operations Pro 考试正是围绕这些状态和 provider 模式构建的。
您的 AWS 直觉会在哪四个地方积极误导您
如果您忘记了所有其他内容,请记住以下几点:
- 用户上没有策略。 不要再寻找附加到身份的 JSON。权限是 org、folder、project 或 resource 上的
(member, role)绑定,它们会向下继承。您可能需要的授权在三级以上。 - 在您启用 API 之前,什么都无法工作。 您在新 project 上遇到的第一个 403 通常是
API not enabled,而不是缺少角色。每个服务在您为每个 project 开启它之前都是关闭的。 - 您模拟 service account,而不是承担角色。 SA 是一种具有自己访问策略的资源 - 如果没有在 SA 上的 token-creator 绑定,赋予您的主体广泛的 project 权限是无用的。
- Billing 是一个独立的对象。 “我可以部署任何东西”并不能说明“我可以创建一个可计费的 project 或链接一个 billing account”。不同的资源,不同的角色 -
billing.user在 billing account 上,而不是 project 管理员。
哪些认证涵盖了双方
云治理 - 层级结构、身份、防护措施和状态 - 是两种云上架构和管理考试的支柱,因此学习它们也是让上述概念牢固掌握的最快方法。如果您已经拥有 AWS 证书,那么同一行的 Google Cloud 证书是您的自然下一步。
在 AWS 方面(您正在从中翻译的知识):
- AWS Certified Cloud Practitioner (CLF-C02) - 账户、IAM 和 Organizations 的基础。
- AWS Certified Solutions Architect - Associate (SAA-C03) - IAM、多账户结构和核心架构。
- AWS Certified Solutions Architect - Professional (SAP-C02) - 大规模多账户 Organizations、SCPs 和跨账户访问。
- AWS Certified Security - Specialty (SCS-C03) - IAM 深度、SCPs 和密钥管理。
在 Google Cloud 方面(您正在翻译到的知识):
- Google Cloud Digital Leader - 组织、project、IAM 和计费的基础知识。
- Google Cloud Associate Cloud Engineer - 日常操作层面:project、IAM 绑定、service account 和
gcloud。 - Google Cloud Professional Cloud Architect - org/folder/project 层级结构、着陆区设计和大规模治理。
- Google Cloud Professional Cloud Security Engineer - IAM 深度、org 策略、service account 安全和密钥管理。
如果您今天已获得 AWS 认证,一条务实的路径是:从 Cloud Digital Leader 开始,以映射词汇,然后跳到 Associate Cloud Engineer(它位于您最常用的 project 和 IAM 层面),并根据您的工作偏向架构还是安全,添加 Professional Cloud Architect 或 Professional Cloud Security Engineer。
总结
GCP 并不比 AWS 更难 - 它只是分解方式不同。AWS 将权限附加到身份,为您提供一个所有功能都已开启的重量级账户,并将大部分权限整合到 IAM 中。GCP 将权限挂在向下继承的资源树上,为您提供廉价的一次性 project,它们始于一张白纸,并让您模拟 service account 而不是承担角色。将这些概念翻译一次 - 策略从身份转移到树上,账户变成 API 关闭的 project,角色变成您模拟的 service account,而 billing 是您链接的独立对象 - 其余的都是词汇。通过上述证书进行深入学习,那些感觉像是任意拒绝的部分将开始被理解为一种连贯、深思熟虑的设计。