2. Google Cloud资源层级与IAM治理

在Google Cloud中,资源并不是平铺在一个全局空间里,而是被组织成一棵严格的树形层级:组织(Organization)→ 文件夹(Folder)→ 项目(Project)→ 资源(Resource)。理解这棵树,是理解IAM策略继承、最小权限落地以及服务账号治理的前提。很多权限事故并非策略写错,而是策略被挂在了错误的层级上,导致影响范围远超预期。

组织节点对应一个Cloud Identity或Workspace租户,是整棵树的根,也是唯一可以施加“组织级拒绝策略”的位置。文件夹是可选的分组层,用于按部门、环境(生产/测试)、业务线或合规域切分,可以嵌套多层。项目是资源与计费的基本边界,也是绝大多数API、配额和IAM策略的实际作用单元。资源则是项目内的具体对象,例如Compute Engine实例、Cloud Storage桶、BigQuery数据集、Pub/Sub主题等。层级越靠上,策略影响面越大;层级越靠下,策略越具体。

Google Cloud 资源层级与IAM策略继承 组织 Organization example.com · 拒绝策略唯一挂载点 文件夹:生产环境 folder: prod 文件夹:测试环境 folder: staging 文件夹:共享服务 folder: shared 项目:prod-web project: prod-web-123 项目:staging-app project: staging-app-456 项目:shared-net project: shared-net-789 Compute Engine 实例 vm-web-01 Cloud Storage 桶 gs://staging-assets VPC 网络 vpc-shared-prod IAM 策略继承与拒绝策略作用方向 允许策略(Allow)自上而下继承 ▼ 拒绝策略(Deny)自组织向下覆盖 ▲ 组织级策略影响全部 文件夹级策略影响子树 项目级策略影响本单元

IAM策略继承:允许是并集,拒绝是硬约束

IAM策略继承遵循两条互补规则。第一条是允许策略的并集继承:在组织、文件夹、项目任意层级授予的允许角色,都会向下传递给所有后代资源。例如在组织级给某个组授予 roles/viewer,该组对组织下所有项目都拥有只读权限;在项目级再授予 roles/editor,则该项目内权限是两者的并集。这意味着权限只会越往下越多,不会自动收窄——这正是最小权限难以落地的根本原因。

第二条是拒绝策略的强制覆盖。组织级拒绝策略(Organization Policy / IAM Deny)可以针对特定主体、特定权限或特定资源条件,强制覆盖任何层级的允许授予。拒绝策略只能挂在组织节点上,且优先级高于所有允许策略。例如,可以设置一条拒绝策略:禁止任何主体在组织内删除审计日志桶,即使某项目管理员拥有 storage.objects.delete 权限,该操作仍会被拒绝。拒绝策略是合规治理的“硬底线”,适合用于保护审计、密钥、日志等关键资源。

允许策略做加法,拒绝策略做减法。设计权限时先想清楚“哪些操作绝对不允许”,用拒绝策略锁死底线,再用允许策略按需分配。

最小权限原则的落地方法

最小权限不是一句口号,而是一套可操作的流程。在Google Cloud中,落地路径通常如下:

  • 按职责定义角色,而非按人:先梳理岗位职责(如“生产环境只读审计员”“CI/CD部署机器人”),为每个职责选择预定义角色或自定义角色,避免直接给个人授予宽泛的 roles/editor 或 roles/owner。
  • 优先使用组而非个人:通过Cloud Identity群组授予权限,人员变动时只需调整组成员,策略本身保持稳定,审计也更清晰。
  • 在最低必要层级授予:如果某权限只在一个项目内需要,就不要在文件夹或组织级授予。层级越低,爆炸半径越小。
  • 用自定义角色收窄预定义角色:当预定义角色权限过宽时,创建自定义角色,只包含实际需要的权限列表。例如只允许 compute.instances.get 和 compute.instances.list,而不授予完整的 roles/compute.viewer。
  • 定期用Policy Analyzer和IAM Recommender复核:Policy Analyzer可以回答“谁对某个资源拥有什么权限”,IAM Recommender会基于实际调用历史建议移除未使用的权限。

服务账号与工作负载身份联邦的治理实践

服务账号是给应用、虚拟机、CI/CD流水线使用的非人类身份。治理服务账号的核心原则是:一个工作负载一个服务账号,权限最小化,密钥不落地。

传统做法是创建服务账号并下载JSON密钥,但密钥容易泄露、难以轮换。更安全的做法是使用工作负载身份联邦(Workload Identity Federation),让外部身份(如AWS IAM角色、Azure AD应用、GitHub Actions OIDC令牌、Kubernetes ServiceAccount)直接换取Google Cloud短期访问令牌,无需长期密钥。配置流程大致为:在Google Cloud创建Workload Identity Pool和Provider,配置属性映射(如将GitHub的 sub 声明映射为 google.subject),然后授予外部身份对应的服务账号模拟权限(roles/iam.workloadIdentityUser)。外部工作负载用OIDC令牌调用STS换取短期凭证,再模拟服务账号访问GCP资源。

# 示例:为GitHub Actions创建Workload Identity Provider
gcloud iam workload-identity-pools create "github-pool" \
  --location="global" \
  --display-name="GitHub Actions Pool"

gcloud iam workload-identity-pools providers create-oidc "github-provider" \
  --location="global" \
  --workload-identity-pool="github-pool" \
  --issuer-uri="https://token.actions.githubusercontent.com" \
  --attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository" \
  --attribute-condition="assertion.repository=='my-org/my-repo'"

# 授予外部身份模拟服务账号的权限
gcloud iam service-accounts add-iam-policy-binding \
  "deploy-sa@prod-web-123.iam.gserviceaccount.com" \
  --role="roles/iam.workloadIdentityUser" \
  --member="principalSet://iam.googleapis.com/projects/123456/locations/global/workloadIdentityPools/github-pool/attribute.repository/my-org/my-repo"

上述配置中,attribute-condition 是关键的安全约束:它确保只有来自指定仓库的令牌才能换取凭证,防止其他仓库冒用。服务账号本身只应被授予完成部署所需的最小角色,例如 roles/run.developer 和 roles/artifactregistry.writer,而不是 roles/editor。

服务账号密钥一旦泄露,攻击者可在密钥有效期内持续访问。生产环境应优先使用工作负载身份联邦或附加服务账号(Attached Service Account),并禁用密钥创建权限(通过组织策略 constraints/iam.disableServiceAccountKeyCreation)。

治理检查清单

治理项推荐做法验证方式
组织级拒绝策略对审计日志、KMS密钥设置删除保护检查组织策略列表
权限授予层级项目级优先,避免组织级宽泛授予Policy Analyzer按资源查询
服务账号密钥禁用密钥创建,改用工作负载身份联邦组织策略约束状态
未使用权限定期采纳IAM Recommender建议Recommender报告
组成员管理通过Cloud Identity组授权,定期复核成员组审计日志

资源层级决定了权限的作用范围,IAM继承决定了权限如何流动,拒绝策略提供了不可逾越的底线,而服务账号与工作负载身份联邦则决定了机器身份的安全边界。把这四者结合起来,才能在生产环境中实现既可用又可审计的权限治理。