使用服务帐号的最佳实践

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

服务帐号代表非人类用户。它们旨在用于工作负载(例如自定义应用)在没有最终用户参与的情况下访问资源或执行操作的场景。

服务帐号与普通用户帐号存在以下区别:

  • 服务帐号没有密码,不能用于基于浏览器的登录。
  • 服务帐号作为属于 Google Cloud 项目的资源创建和管理。相比之下,用户在 Cloud Identity 或 Google Workspace 帐号中进行管理。
  • 这些帐号专用于 Google Cloud。相比之下,在 Cloud Identity 或 Google Workspace 中管理的用户可跨多个 Google 产品和服务开展工作。
  • 它们即是资源,又是主帐号
    • 作为主帐号,服务帐号可以被授予对资源(例如 Cloud Storage 存储桶)的访问权限。
    • 作为资源,服务帐号可以被访问,并且可能会被其他主帐号(例如用户或群组)模拟

虽然服务帐号是一种有用的工具,但服务帐号也可能被滥用,主要有以下几种方式:

  • 提升权限:不法分子可能会通过模拟服务帐号而访问他们无权访问的资源。
  • 仿冒:不法分子可能会使用服务帐号模拟来模糊其身份。
  • 不可否认性:不法分子可能会使用服务帐号代表其执行操作,以此来隐藏其身份和操作。在某些情况下,可能无法跟踪不法分子的这些操作。
  • 信息披露:不法分子可能会从存在的某些服务帐号派生有关基础架构、应用或进程的信息。

为帮助保护服务帐号,请考虑其双重性质:

  • 由于服务帐号是主帐号,因此您必须限制其权限,以降低被盗用服务帐号可能造成的潜在危害。
  • 由于服务帐号是一种资源,因此您必须防止它被盗用。

本指南介绍管理、使用和保护服务帐号的最佳实践。

选择何时使用服务帐号

服务帐号可为无人参与的应用(例如批量作业、分派队列中的消息的工作器进程或资源监控代理)提供身份。通过使用服务帐号,您可以允许这些应用在没有用户交互的情况下运行。此外,如果应用访问资源,您可以使用 Cloud Audit Logs 将访问追溯到应用使用的服务帐号。

对于用户使用自定义身份验证方案进行身份验证,然后间接访问 Google Cloud 应用的应用,服务帐号也适用。这些应用可以确认用户已经过身份验证和授权,然后使用服务帐号向 Google Cloud 服务和资源进行身份验证。为了帮助将访问追溯到用户,应用可以在每次用户访问资源时写入自定义日志条目,并且您可以将自定义日志条目与 Cloud Audit Logs 关联。

与用户不同,服务帐号无法通过使用密码或单点登录 (SSO) 进行登录来验证身份。服务帐号支持一组不同的身份验证方法。以下部分介绍了如何在二者之间进行选择。您还可以使用下图来帮助您选择身份验证方法:

如何使用服务帐号

以下部分介绍了选择在何时及如何使用服务帐号的最佳做法。

尽量使用关联的服务帐号

如需允许部署在 Google Cloud 上的应用使用服务帐号,请将服务帐号关联到底层计算资源。通过关联服务帐号,您可以允许应用获取服务帐号的令牌,并使用这些令牌来访问 Google Cloud API 和资源。

若要获取应用的访问令牌,您可以使用客户端库(如果能够使用的话)。客户端库会使用应用默认凭据 (ADC) 服务自动查找关联的凭据并获取应用的访问令牌。

如果使用客户端库不切实际,请对应用进行调整,以便以编程方式从元数据服务器获取令牌。支持访问元数据服务器的计算资源包括:

如需查看允许您关联服务帐号的计算资源的完整列表,请参阅管理服务帐号模拟

使用 Workload Identity 将服务帐号关联到 Kubernetes pod

如果您使用 Google Kubernetes Engine,则可能会在一个 GKE 集群上同时运行不同应用。各个应用需要访问的资源和 API 可能不同。

如果您将服务帐号关联到 GKE 集群或其某个节点池,则默认情况下,该集群或节点池上运行的所有 pod 都可以模拟服务帐号。在不同应用之间共享一个服务帐号会导致很难为该服务帐号分配一组正确的权限:

  • 如果您只授予所有应用需要的资源的访问权限,则某些应用可能会因为缺少特定资源的访问权限而无法正常运行。
  • 如果您授予任何特定应用需要的所有资源的访问权限,则您可能会过度授予访问权限。

如需管理 GKE 环境中的资源的访问权限,更好的方法是使用 Workload Identity:

  1. 请勿将服务帐号关联到 GKE 集群或节点池。
  2. 为需要 Google API 或资源的访问权限的每个 Kubernetes pod 创建一个专用服务帐号。
  3. 为需要 Google API 或资源的访问权限的每个 Kubernetes pod 创建一个 Kubernetes 服务帐号,并将其关联到 pod。
  4. 使用 Workload Identity 在服务帐号及其对应的 Kubernetes 服务帐号之间创建映射。

使用工作负载身份联合来允许在本地或在其他云提供商上运行的应用使用服务帐号

如果您的应用在本地或其他云服务商上运行,您无法将服务帐号关联到底层计算资源。但是,应用可能有权访问特定于环境的凭据,例如:

  • AWS 临时凭据
  • Azure Active Directory 访问令牌
  • 由本地身份提供商(例如 Active Directory Federation Services (AD FS) 或 KeyCloak)签发的 OpenID 访问令牌或 ID 令牌

如果您的应用有权访问其中一个凭据并且需要访问 Google Cloud API 或资源,则可以使用工作负载身份联合

借助工作负载身份联合,您可以在 Google Cloud 项目与外部身份提供商之间创建单向信任关系。建立信任后,应用便可使用受信任的身份提供商签发的凭据,按照以下三步流程来模拟服务帐号:

  1. 从可信的身份提供商获取凭据,例如 OpenID Connect ID 令牌。
  2. 使用 Security Token Service (STS) API 将凭据换成短期有效的 Google STS 令牌。
  3. 使用 STS 令牌向 IAM Service Account Credentials API 进行身份验证,并获取服务帐号的短期有效的 Google 访问令牌。

当您使用受支持的客户端库或命令行工具访问 Google Cloud 服务时,此过程会自动发生。

通过使用工作负载身份联合,您可以让应用使用外部环境提供的身份验证机制,并且无需存储和管理服务帐号密钥。

使用 IAM Credentials API 代理凭据

有些应用仅在特定时间或在特定情况下需要特定资源的访问权限。例如:

  • 应用在启动期间可能需要配置数据的访问权限,但初始化后可能会不需要此访问权限。
  • 监管者应用可能会定期启动后台作业,其中每个作业都有不同的访问权限要求。

在这种情况下,使用单个服务帐号并授予其对所有资源的访问权限违反了最小权限原则:在任何时间点,应用拥有访问权限的资源数量都可能超过实际所需的。

为帮助确保应用的不同部分仅有权访问所需的资源,请使用 IAM Credentials API 代理短期有效的凭据:

  • 为应用或用例的每个部分创建专用服务帐号,并只授予服务帐号对必要资源的访问权限。
  • 创建另一个充当监管者的服务帐号。向监管者服务帐号授予其他服务帐号的 Service Account Token Creator 角色,以便它可以为这些服务帐号请求短期访问令牌。
  • 拆分应用,使应用的一部分充当令牌代理,并且仅让应用的这一部分使用监管者服务帐号。
  • 使用令牌代理向应用的其他部分签发短期有效的服务帐号。

如果没有可行的替代方案,请使用服务帐号密钥

有时,您可能会遇到无法关联服务帐号,并且使用 Workload Identity工作负载身份联合不是可行方法的情况。例如,您可以使用需要访问 Google Cloud 资源且不支持身份联合的第三方应用。

如果其他身份验证方法不可行,请为该应用创建服务帐号密钥。借助服务帐号密钥,应用可以以服务帐号身份进行身份验证,这类似于用户可使用用户名和密码进行身份验证的方式。服务帐号密钥是一种 Secret 类型,必须免遭未经授权的访问。

应用可能需要敏感或个人用户数据的访问权限。此类数据示例包括用户的邮箱或日历、存储在云端硬盘中的文档或包含敏感数据的 BigQuery 数据集。

如果应用执行无人参与的后台任务(例如编制索引或数据泄露防护 (DLP) 扫描),或者最终用户未使用 Google 身份进行身份验证,则使用服务帐号访问用户数据是合适的做法。在应用代表最终用户执行操作的所有其他场景中,最好避免使用服务帐号。

使用 OAuth 同意流程请求最终用户的同意,而不是使用服务帐号访问用户数据(可能会转换主帐号)。然后,让应用以最终用户的身份进行操作。使用 OAuth(而非服务帐号)有助于确保:

  • 用户可以查看将授予应用对哪些资源的访问权限,并且可以明确表示或拒绝同意。
  • 用户可以随时在我的帐号页面上撤消同意。
  • 您无需拥有一个可以不受限制地访问所有用户数据的服务帐号。

通过允许应用使用最终用户凭据,您可以延迟对 Google Cloud API 的权限检查。这种方法限制了因编码错误(混淆代理问题)而导致意外公开用户不应有权访问的数据的风险。

在开发过程中请勿使用服务帐号

在日常工作中,您可能会使用 Google Cloud CLI、gsutilterraform 等工具。请勿使用服务帐号运行这些工具。而是应该通过运行 gcloud auth login(对于 gcloud CLI 和 gsutil)或 gcloud auth application-default login(对于 terraform 和其他第三方工具)来允许这些工具使用您的凭据。

您可以使用类似的方法来开发和调试计划在 Google Cloud 上部署的应用。部署后,应用可能需要服务帐号,但如果您在本地工作站上运行该应用,则可以让它使用您的个人凭据。

为了帮助确保您的应用同时支持个人凭据和服务帐号凭据,请使用 Cloud 客户端库应用默认凭据

管理服务帐号

服务帐号与普通用户帐号的区别不仅在于使用方法,还在于管理方法。以下部分提供了管理服务帐号的最佳做法。

将服务帐号作为资源管理

常规用户帐号通常根据组织的“joiner-mover-leaver”流程进行管理:员工加入时,系统会为他们创建新的用户帐号。当员工调动部门时,其用户帐号会更新。当员工离开公司时,他们的用户帐号会被暂停或删除。

相比之下,服务帐号不与任何特定员工关联。而是最好将服务帐号视为资源(属于其他资源或是其他资源的一部分),例如特定虚拟机实例或应用。

要有效地管理服务帐号,请不要孤立地看待服务帐号,而应在其关联资源的背景中进行考量,并将服务帐号及其关联资源作为一个整体进行管理:对服务帐号及其关联资源应用相同的进程、相同的生命周期和相同的安全级别,并使用相同的工具进行管理。

创建单一用途的服务帐号

在多个应用之间共享一个服务帐号可能会导致服务帐号的管理复杂化:

  • 这些应用可能有不同的生命周期。如果应用被停用,您可能不清楚服务帐号是否可停用,以及是否仍需要服务帐号。
  • 随着时间的推移,应用的访问权限要求可能会有所不同。如果应用使用同一个服务帐号,您可能需要向服务帐号授予越来越多的资源的访问权限,导致增加总体风险。
  • Cloud Audit Logs 包含执行更改或访问数据的服务帐号的名称,但不会显示使用该服务帐号的应用的名称。如果多个应用共享一个服务帐号,您可能无法将活动追溯到正确的应用。

具体而言,一些 Google Cloud 服务(包括 App Engine 和 Compute Engine)会创建默认具有项目的 Editor 角色 (roles/editor) 的默认服务帐号。当您创建 Compute Engine 虚拟机 (VM) 实例等资源时,如果您未指定服务帐号,则该资源可以自动使用默认服务帐号。虽然默认服务帐号可让您更轻松地上手,但在多个应用之间共享此类有影响力的服务帐号的风险非常高。

您可以采取以下步骤来避免这些情况:

遵循命名和文档惯例

为了帮助跟踪服务与应用或资源之间的关联,请在创建新的服务帐号时遵循命名惯例:

  • 为服务帐号电子邮件地址添加一个前缀,以标识该帐号的使用方式。例如:
    • vm-,表示挂接到虚拟机实例的服务帐号。
    • wi-,表示 Workload Identity 使用的服务帐号。
    • wif-,表示工作负载身份联合使用的服务帐号。
    • onprem-,表示本地应用使用的服务帐号。
  • 如果虚拟机运行差旅费用应用,则在服务帐号电子邮件地址中嵌入该应用的名称,例如 vm-travelexpenses@
  • 使用说明字段添加联系人、指向相关文档的链接或其他说明。

请勿在服务帐号的电子邮件地址中嵌入敏感信息或字词。

识别并停用未使用的服务帐号

如果不再使用某服务帐号,请停用该服务帐号。通过停用未使用的服务帐号,可以降低服务帐号因不法分子水平扩散或权限提升而被滥用的风险。

对于与特定资源(如虚拟机实例)关联的单一用途的服务帐号,请在停用或删除关联资源后,立即停用该服务帐号。

对于用于多种用途或跨多个资源共享的服务帐号,要确定服务帐号是否仍在使用则更为困难。在这种情况下,您可以使用活动分析器来查看服务帐号的最近身份验证活动。

停用未使用的服务帐号,然后再将其删除

如果您删除一个服务帐号,然后创建具有相同名称的新服务帐号,系统会为新服务帐号分配不同的身份。因此,原始 IAM 绑定不会应用于新服务帐号。相反,如果停用并重新启用服务帐号,所有的 IAM 绑定保持不变。

为避免意外丢失 IAM 绑定,最好不要立即删除服务帐号。如果不再需要某个服务帐号,请在过一段时间后再删除。

切勿删除默认服务帐号,例如 App EngineCompute Engine 默认服务帐号。这些服务帐号只能通过停用并重新启用相应 API 来重新创建,这可能会破坏您现有的部署。如果您不使用默认服务帐号,停用它们即可。

限制服务帐号权限

服务帐号是主帐号,可以获得对常规用户帐号等资源的访问权限。但是,服务帐号通常比典型用户具有更大的访问权限,可以访问更多资源。此外,当您向应用添加功能时,其服务帐号往往会随着时间的推移获得越来越多的访问权限。您可能还会忘记撤消不再需要的访问权限。

不对默认服务帐号使用自动角色授予功能

当您首次在 Google Cloud 项目中启用 API 时,某些 Google Cloud 服务会创建默认服务帐号。默认情况下,这些服务帐号会被授予 Cloud 项目的 Editor 角色 (roles/editor),这样他们可以读取和修改 Cloud 项目中的所有资源。授予此角色是为了方便您使用,但这对于服务帐号正常工作并不是必需的:如需访问 Cloud 项目中的资源,Google Cloud 服务使用服务代理,而不是默认服务帐号。

如需防止默认服务帐号自动被授予 Editor 角色,请为您的组织启用停用默认服务帐号的自动 IAM 授权 (constraints/iam.automaticIamGrantsForDefaultServiceAccounts) 限制条件。如需将该限制条件应用于多个 Cloud 项目,请在文件夹或组织节点上配置该限制条件。应用该限制条件不会从现有默认服务帐号中移除 Editor 角色。

如果您应用此限制条件,则新项目中的默认服务帐号将无权访问您的 Google Cloud 资源。您必须为默认服务帐号授予适当的角色,以便对您的资源进行访问。

将服务帐号关联到虚拟机实例时,请勿依赖于访问权限范围

将服务帐号附加到虚拟机实例后,您可以指定一个或多个访问权限范围。通过访问权限范围,您可以限制虚拟机可以访问的服务。除了允许政策外,还会应用这些限制。

访问权限范围的粒度较粗。例如,使用 https://www.googleapis.com/auth/devstorage.read_only 范围,您可以限制对 Cloud Storage 只读操作的访问权限,但不能限制对特定存储分区的访问权限。因此,访问权限范围不是适合精细允许政策的替代项。

创建一个专用服务帐号并使用精细允许政策来限制服务帐号可以访问的资源,而不是依赖于访问权限范围。

避免使用群组向服务帐号授予资源访问权限

在组织中,多个员工履行类似或重叠的工作职责是很常见,因此需要类似的资源访问权限。借助群组,您可以利用这些类似的访问权限来减少管理开销。

服务帐号应供应用使用。多个应用履行相同的职责,因此访问权限要求相同或类似是很少见的情况。相反,应用往往是唯一的,并且每个应用需要访问的资源通常都各不相同。

使用群组为服务帐号授予对资源的访问权限可能会导致一些不良后果:

  • 群组数激增,每个群组只包含一个或几个服务帐号。
  • 权限蔓延:随着时间的推移,群组被授予越来越多的资源的访问权限,但每个群组成员只需要一部分资源的访问权限。

除非群组的用途明确定义,否则最好避免使用群组;而是直接为服务帐号授予所需的资源访问权限。

避免使用全网域授权

全网域授权功能使服务帐号能够模拟 Cloud Identity 或 Google Workspace 帐号中的任何用户。通过全网域授权功能,服务帐号可以在 Google Workspace 和 Cloud Identity 中执行特定管理任务,也可以从 Google Cloud 外部访问不支持服务帐号的 Google API。

全网域授权功能不会限制服务帐号模拟特定用户,但它允许模拟 Cloud Identity 或 Google Workspace 帐号中的任何用户(包括超级用户)。因此,允许服务帐号使用全网域授权功能可能会使服务帐号很容易成为提升权限攻击的目标。

如果您可以直接通过服务帐号或使用 OAuth 同意流程来完成任务,请避免使用全网域授权功能。

如果您无法避免使用全网域授权功能,请限制服务帐号可以使用的 OAuth 范围集。虽然 OAuth 范围不会限制服务帐号可以模拟的用户,但会限制服务帐号可以访问的用户数据类型。

使用凭据访问边界来缩小访问令牌权限范围

Google 访问令牌是不记名令牌,这意味着其使用与任何特定应用都无关。如果您的应用将访问令牌传递给其他应用,则其他应用可以按照与您的应用相同的方式来使用令牌。同样,如果访问令牌泄露给不法分子,则他们可以使用该令牌来获取访问权限。

由于访问令牌是不记名令牌,因此您必须防止它们泄露或显示给未经授权方。您可以限制泄露的访问令牌授予访问权限的资源,从而限制该泄露的访问令牌可能造成的潜在损害。此过程称为缩小权限范围。

每当您将访问令牌传递给其他应用或您的应用的不同组件时,使用凭据访问边界可缩小访问令牌权限范围。设置访问边界,以便令牌能够授予足够的对所需资源的访问权限,但不能授予更多。

使用角色建议来确定未使用的权限

首次部署应用时,您可能不确定该应用实际需要的角色和权限。因此,您为该应用的服务帐号授予的权限可能在数量上会超出其实际需要的权限。

同样,应用的访问权限要求可能会随着时间的推移而变化,并且您可能不需要最初授予的某些角色和权限。

使用角色建议来确定应用实际使用的权限以及可能未使用的权限。调整受影响资源的允许政策,以确保仅授予应用实际需要的访问权限。

使用横向移动数据分析来限制横向移动

横向移动是指一个项目中的服务帐号有权模拟另一个项目中的服务帐号。例如,服务帐号可能是在项目 A 中创建的,但具有在项目 B 中模拟服务帐号的权限。

这些权限可能导致项目之间发生一系列模拟,这些模拟会为主帐号授予对资源的意外访问权限。例如,主帐号可以模拟项目 A 中的服务帐号,然后使用该服务帐号来模拟项目 B 中的服务帐号。如果项目 B 中的服务帐号有权模拟组织中其他项目中的其他服务帐号,则主帐号可以继续使用服务帐号模拟从项目移动到项目,从而在移动时获取权限。

Recommender 提供了横向移动数据分析,可帮助您缓解此问题。横向移动数据分析识别允许一个项目中的服务帐号模拟另一个项目中的服务帐号的角色。如需了解如何直接查看和管理横向移动数据分析,请参阅管理横向移动数据分析

一些横向移动数据分析与角色建议相关联。您可以应用这些建议,以减少项目间的横向移动。如需了解具体方法,请参阅查看和应用建议

防范提权威胁

未被授予任何角色、无法访问任何资源且未与任何防火墙规则关联的服务帐号通常价值有限。为服务帐号授予对资源的访问权限之后,服务帐号的价值会提高:该服务帐号对您更为有用,但它也会更容易成为提升权限攻击的目标。

例如,假设一个对包含敏感信息的 Cloud Storage 存储分区具有完整访问权限的服务帐号。在这种情况下,该服务帐号实际上与 Cloud Storage 存储分区本身一样重要:不法分子可能会尝试控制该服务帐号,而不是试图直接访问存储分区。如果该尝试成功,不法分子可能会通过模拟该服务帐号来提升其权限,进而能够访问存储分区中的敏感信息。

涉及服务帐号的提升权限方法通常分为以下几个类别:

  • 直接模拟:您可能无意中向用户授予模拟服务帐号或为服务帐号创建服务帐号密钥的权限。如果服务帐号比用户本身的权限更高,则用户可以使用该功能提升其权限并获取用户无法访问的资源的访问权限。

  • 间接模拟:如果用户无法直接模拟服务帐号,当 CI/CD 流水线、虚拟机实例或用户可以访问的其他自动化系统使用该服务帐号时,用户可能可以间接执行此操作。因此,如果系统不阻止用户执行此操作,用户可以执行不允许自行执行的操作。

    例如,如果用户具有对 Compute Engine 虚拟机实例的 SSH 访问权限,则可以间接模拟附加到该虚拟机实例的服务帐号,并访问服务帐号可以访问的任何 Google Cloud 资源。

  • 允许政策、群组或自定义角色修改:无权访问特权服务帐号的用户可能仍有权修改服务帐号、所属的 Cloud 项目或文件夹的允许政策。然后,用户可以扩展其中一个允许政策,以向自己授予(直接或间接)模拟服务帐号的权限。

以下部分介绍了保护服务帐号免遭提升权限威胁的最佳做法。

避免让用户模拟权限高于用户自身的服务帐号

通过模拟服务帐号,用户可以获取对服务帐号可访问的部分或全部资源的访问权限。如果服务帐号具有的访问权限比用户广泛,则服务帐号的权限实际上高于用户。

授予用户模拟权限更高的服务帐号的权限是一种特意让用户提升其权限的方式,这类似于在 Linux 上使用 sudo 工具或在 Windows 上使用进程提升。除非您面对必须临时提升权限的情况,否则最好避免让用户模拟权限更高的服务帐号。

使用户能够模拟服务帐号的权限包括:

  • iam.serviceAccounts.getAccessToken
  • iam.serviceAccounts.getOpenIdToken
  • iam.serviceAccounts.actAs
  • iam.serviceAccounts.implicitDelegation
  • iam.serviceAccounts.signBlob
  • iam.serviceAccounts.signJwt
  • iam.serviceAccountKeys.create
  • deploymentmanager.deployments.create
  • cloudbuild.builds.create

具有其中一些权限的角色包括(但不限于):

  • Owner (roles/owner)
  • Editor (roles/editor)
  • Service Account User (roles/iam.serviceAccountUser)
  • Service Account Token Creator (roles/iam.serviceAccountTokenCreator)
  • Service Account Key Admin (roles/iam.serviceAccountKeyAdmin)
  • Service Account Admin (roles/iam.serviceAccountAdmin)
  • Workload Identity User (roles/iam.workloadIdentityUser)
  • Deployment Manager Editor (roles/deploymentmanager.editor)
  • Cloud Build Editor (roles/cloudbuild.builds.editor)

在将上述任何角色分配给用户之前,请先问自己:

  • 用户通过模拟服务帐号可以获取当前 Cloud 项目内部和外部的哪些资源的访问权限?
  • 此访问权限级别是否合理?
  • 是否有足够的保护措施来控制用户在哪些情况下可以模拟服务帐号?

如果无法确认所有问题,请勿分配角色。而是应考虑为用户提供其他权限较低的服务帐号。

避免让用户更改权限更高的服务帐号的允许政策

服务帐号的允许政策会捕获允许使用或模拟服务帐号的用户。拥有特定服务帐号的 iam.serviceAccounts.setIamPolicy 权限的用户可以修改或扩展允许政策。包含该权限的角色包括:

  • Owner (roles/owner)
  • Security Admin (roles/iam.securityAdmin)
  • Service Account Admin (roles/iam.serviceAccountAdmin)

具有 iam.serviceAccounts.setIamPolicy 权限的角色可让用户完全控制服务帐号:

  • 该用户可以授予自己模拟服务帐号的权限,这样便有权访问与服务帐号相同的资源。
  • 该用户可以向其他用户授予相同或类似的对该服务帐号的访问级别:

在将上述任何角色分配给用户之前,请先问自己用户通过模拟服务帐号可以获取当前 Cloud 项目内部和外部的哪些资源的访问权限?如果服务帐号具有的访问权限超出用户,请勿允许用户更改服务帐号的允许政策

不允许用户创建或上传服务帐号密钥。

借助服务帐号密钥,应用或用户可以以服务帐号的身份进行身份验证。与其他形式的服务帐号模拟不同,使用服务帐号密钥不需要以前任何形式的身份验证,即拥有服务帐号密钥的任何人都可以使用该密钥。

使用服务帐号密钥进行身份验证的实际结果与其他模拟形式类似。如果您授予用户对服务帐号密钥的访问权限,或授予其创建新服务帐号密钥的权限,则用户可以模拟服务帐号,并可以访问该服务帐号可访问的所有资源。

创建上传服务帐号密钥需要 iam.serviceAccountKeys.create 权限,Service Account Key Admin (roles/iam.serviceAccountKeyAdmin) 和 Service Account Key Editor (roles/editor) 角色具有此权限。

为用户分配包含 iam.serviceAccountKeys.create 权限的任何角色之前,请考虑这样做之后用户可以通过模拟服务帐号来获取当前 Cloud 项目内部和外部哪些资源的访问权限。不允许用户为比其拥有更多权限的服务帐号创建服务帐号密钥。

如果您的 Cloud 项目完全不需要服务帐号密钥,请对 Cloud 项目或所属文件夹应用停用服务帐号密钥创建功能停用服务帐号密钥上传功能组织政策限制条件。这些限制条件会阻止所有用户创建和上传服务帐号密钥,包括具有服务帐号的 iam.serviceAccountKeys.create 权限的用户。

请勿在 Cloud 项目或文件夹级层向服务帐号授予访问权限

服务帐号属于资源,是资源层次结构的一部分。因此,您可以在以下任何级层管理服务帐号的访问权限:

  • 单个服务帐号
  • 所属的 Cloud 项目
  • Cloud 项目祖先实体中的文件夹
  • 组织节点

在 Cloud 项目级层或资源层次结构的更高级层管理访问权限有助于减少管理开销,但也可能会导致过度授权。例如,如果您为用户授予 Cloud 项目中的 Service Account Token Creator 角色,则用户可以模拟 Cloud 项目中的任何服务帐号。能够模拟任何服务帐号意味着用户可能会获取这些服务帐号可以访问的所有资源的访问权限,包括该 Cloud 项目外部的资源。

为避免此类过度授权,请勿在 Cloud 项目或文件夹级层管理服务帐号的访问权限;而是要分别管理每个服务帐号的访问权限。

请勿从关联了特权服务帐号的计算资源上受保护程度较低的来源运行代码

当您将服务帐号附加到计算资源(例如虚拟机实例或 Cloud Run 应用)后,在该资源上运行的进程可以使用元数据服务器来请求访问令牌和 ID 令牌。这些令牌允许进程模拟服务帐号并代表其访问资源。

默认情况下,并非只有特定进程或用户才能访问元数据服务器。相反,在计算资源上执行的任何代码都可以访问元数据服务器并获取访问令牌。此类代码可能包括:

  • 应用的代码。
  • 由最终用户提交的代码(如果您的应用允许任何服务器端脚本评估)。
  • 从远程源代码库读取的代码(如果计算资源属于 CI/CD 系统)。
  • 由 Cloud Storage 存储分区提供的启动和关停脚本
  • 由虚拟机管理器分配的客机政策

如果代码是由用户提交的,或者是从远程存储位置读取的,则您必须确保它可信,并且远程存储位置至少与关联的服务帐号一样受保护。如果与服务帐号相比,远程存储位置受到妥善保护的效果欠佳,则不法分子可能可以提升其权限。不法分子可以通过将使用服务帐号权限的恶意代码注入到该位置来实现此目的。

限制对关联了特权服务帐号的虚拟机的 shell 访问权限

一些计算资源支持交互式访问,并使用户能够获取对系统的 shell 访问权限。例如:

  • Compute Engine 可让您使用 SSH 或 RDP 登录虚拟机实例。
  • Google Kubernetes Engine 可让您使用 kubectl exec 在 Kubernetes 容器中运行命令或启动 shell。

如果虚拟机实例关联了特权服务帐号,则任何对系统具有 shell 访问权限的用户都可以模拟该特权服务帐号并代表其访问资源。为防止用户滥用此功能来提升其权限,您必须确保 shell 访问权限至少与关联的服务帐号一样受保护。

对于 Linux 实例,您可以使用 OS Login 强制 SSH 访问权限比对关联的服务帐号的访问权限更具限制性:如需连接到启用了 OS Login 的虚拟机实例,用户不仅必须有权使用 OS Login,而且还必须具有对关联的服务帐号的 iam.serviceAccounts.actAs 权限。

相同级别的访问权限控制不适用于使用基于元数据的密钥的虚拟机实例或 Windows 实例:将 SSH 密钥发布到元数据请求 Windows 凭据需要虚拟机实例元数据的访问权限和关联服务帐号的 iam.serviceAccounts.actAs 权限。但是,发布 SSH 密钥或获得 Windows 凭据后,后续登录不需要进行任何其他 IAM 权限检查。

同样,如果虚拟机实例使用自定义 Linux 可插入式身份验证模块进行身份验证,或者虚拟机实例是 Active Directory 网域的成员,则无权模拟服务帐号的用户可能有权登录。

特别是对于不使用 OS Login 的虚拟机实例,请考虑通过 Identity-Aware Proxy 控制 shell 访问权限。仅向应有权模拟关联到虚拟机实例的服务帐号的用户授予 IAP-Secured Tunnel User 角色

将元数据服务器访问权限仅限于所选用户和进程

将服务帐号关联到虚拟机实例后,部署在虚拟机上的工作负载可以访问元数据服务器来请求服务帐号的令牌。默认情况下,对元数据服务器的访问权限不仅限于虚拟机上的任何特定进程或用户:即使是以低权限用户身份运行的进程(例如,Linux 上的 nobody 或 Windows 上的 LocalService),也可以拥有对元数据服务器的完整访问权限,并且可以获取服务帐号的令牌。

如需将元数据服务器访问权限仅限于特定用户,请配置客机操作系统的主机防火墙,以仅允许这些用户打开与元数据服务器的出站连接。

在 Linux 上,您可以使用 --uid-owner--gid-owner 选项来设置仅应用于特定用户或群组的 iptables 规则。在 Windows 上,您可以使用 Set-NetFirewallSecurityFilter 命令来自定义防火墙规则,以将该规则应用于选定的用户或群组。

防范信息泄露威胁

避免在服务帐号电子邮件地址中披露机密信息

如需授予服务帐号对另一个 Cloud 项目中的资源的访问权限,您可以向该资源的允许政策添加角色绑定。与资源本身一样,允许政策是另一个 Cloud 项目的一部分,因此其可见性也由另一个 Cloud 项目控制。

查看允许政策通常不被认为是一种特权操作。许多角色都具有所需的 *.getIamPolicy 权限,包括基本的 Viewer 角色。

可以查看允许政策的用户也可以查看已被授予该资源访问权限的主帐号的电子邮件地址。对于服务帐号,电子邮件地址可向不法分子提供提示。

例如,允许政策可能包含针对电子邮件地址为 jenkins@deployment-project-123.gserviceaccount.com 的服务帐号的绑定。对于不法分子,此电子邮件地址不仅会显示 ID 为 deployment-project-123 的 Cloud 项目,还会显示 Cloud 项目运行 Jenkins 服务器。选择更通用的名称(如 deployer@deployment-project-123.gserviceaccount.com),您可以避免披露有关 deployment-project-123 中运行的软件类型的信息。

如果您向服务帐号授予访问控制不太严格的 Cloud 项目中的资源(例如沙盒或开发 Cloud 项目)的访问权限,请确保服务帐号的电子邮件地址不会披露任何信息。尤其是请勿披露机密信息或可能为攻击者提供提示的信息。

防范不可否认性威胁

每当您发现影响 Google Cloud 中某项资源的可疑活动时,Cloud Audit Logs 是非常重要的信息来源,可了解该活动发生的时间以及参与的用户。

每当 Cloud Audit Logs 指示服务帐号已执行某活动时,仅凭此信息可能不足以重建完整的事件链:您还必须能够了解哪个用户或应用导致服务帐号执行此活动。

此部分包含最佳做法,可帮助您保留不可否的审核跟踪记录。

为 IAM API 启用数据访问日志

为了帮助您识别和了解服务帐号模拟场景,Cloud Engine 等服务在 Cloud Audit Logs 中包含 serviceAccountDelegationInfo 部分。本部分指示了服务帐号是否被模拟以及被哪个用户模拟

并非所有服务都在其 Cloud Audit Logs 中包含模拟详细信息。如需记录所有模拟事件,您还必须为以下 API 启用数据访问日志

  • 包含服务帐号的所有 Cloud 项目中的 Identity and Access Management (IAM) API
  • 包含工作负载身份池的所有 Cloud 项目中的 Security Token Service API

启用这些日志,可确保每次在用户请求服务帐号的访问令牌或 ID 令牌时,都会向 Cloud Audit Logs 中添加一个条目。

确保 CI/CD 历史记录可与 Cloud Audit Logs 相关联

在成功验证代码更改并批准部署后,CI/CD 系统通常会使用服务帐号执行部署。通常,CI/CD 系统会保留进行部署的事件的历史记录。此历史记录可能包含相应代码审核、提交和流水线运行的 ID,以及有关部署批准者的信息。

如果部署修改了 Google Cloud 中的任何资源,则相关资源的 Cloud Audit Logs 会跟踪这些更改。Cloud Audit Logs 包含有关发起更改的用户或服务帐号的信息。但是,在由 CI/CD 系统触发的部署中,服务帐号本身通常不足以重建引起更改的整个事件链。

如需在 CI/CD 系统和 Google Cloud 中建立一致的审核跟踪,您必须确保 Cloud Audit Logs 记录可与 CI/CD 系统历史记录中的事件相关联。如果您在 Cloud Audit Logs 中遇到意外事件,则可以使用这种关联性来确定更改是否确实由 CI/CD 系统执行、为何执行以及由谁批准。

用于建立 Cloud Audit Logs 记录与 CI/CD 系统历史记录中事件之间关联的方法包括:

  • 记录 CI/CD 流水线每次运行时执行的 API 请求。
  • 每当 API 返回操作 ID 时,在 CI/CD 系统日志中记录该 ID。
  • 向 API 请求添加 X-Goog-Request-Reason HTTP 标头并传递 CI/CD 流水线运行的 ID。如果您指定请求原因,Terraform 可以自动添加此标头。

    或者,将信息嵌入到 User-Agent 标头中,以将其捕获到 Cloud Audit Logs 中。

为帮助确保不可否认性,请配置日志文件并提交历史记录,使其是不可变的,并且不法分子无法追溯性地隐藏其跟踪记录。

后续步骤