管理服务账号密钥的最佳实践

与普通用户不同,服务账号没有密码。服务账号改为使用 RSA 密钥对进行身份验证:如果您知道服务账号的密钥对的私钥,则可以使用私钥创建 JWT 不记名令牌并使用不记名令牌请求访问令牌。生成的访问令牌会反映服务账号的身份,您可以使用它来代表服务账号与 Google Cloud API 进行交互。

由于私钥允许您以服务账号身份进行身份验证,因此有权访问私钥类似于知道用户的密码。私钥称为“服务账号密钥”。服务账号使用的密钥对分为两类:Google 管理的密钥对和用户管理的密钥对

如果未谨慎管理,服务账号密钥可能会带来安全风险。 您应尽可能选择更安全的身份验证替代方案。与服务账号密钥相关的主要威胁包括:

  • 凭据泄露:服务账号密钥可能无意中进入不应存储的位置。不法分子可能会使用泄露的服务账号密钥在您的环境中进行身份验证并站稳脚跟。
  • 权限提升:如果不法分子获取了保护程度较低的服务账号密钥的访问权限,他们或许可以使用该密钥来提升其权限。
  • 信息泄露:服务账号密钥可能无意中泄露机密元数据。
  • 不可否认:通过使用服务账号密钥进行身份验证,并让服务账号代表不法分子执行操作,不法分子可能会隐藏其身份和操作。

缓解这些威胁的最佳方式是避免使用用户管理的服务账号密钥,并尽可能使用其他方法对服务账号进行身份验证。您还可以使用 IAM 条件VPC Service Controls 来限制被盗用的服务账号可能访问的资源。

如果您无法使用更安全的服务账号密钥替代方案,可以使用本指南介绍的服务账号密钥管理、使用和保护最佳实践。

防范凭据泄露

与用户名和密码一样,服务账号密钥是一种凭据形式。如果用户可以访问有效的服务账号密钥,则可以使用它对相应服务账号有权访问的资源进行身份验证和访问。

对于不法分子,服务账号密钥可能比泄露的密码更加有用:如果用户账号配置为使用两步验证登录验证,则尝试使用泄露的密码登录不太可能成功。相比之下,使用泄露的服务账号密钥进行身份验证很可能会成功,因为服务账号不需要进行任何额外的登录验证。

不法分子可能会在各个位置查找服务账号密钥,包括:

  • 开源项目的源代码库
  • 公共 Cloud Storage 存储桶
  • 遭破解服务的公共数据转储

除了公共位置外,不法分子还可能会在遭到入侵的非公开位置查找服务账号密钥。例如:

  • 电子邮件收件箱
  • 文件共享
  • 备份存储
  • 临时文件系统目录

为降低服务账号密钥泄露的风险,一种有效的方法是减少流通中的密钥的数量,并抑制新密钥的创建。以下部分介绍了如何限制流通中的服务账号密钥的数量,以及哪些其他措施可以帮助您限制服务账号泄露的风险。

提供创建服务账号密钥的替代方案

确保组织中的用户知道替代方案,并且可以证明使用服务账号密钥的额外风险和管理开销:

  • 向您的开发者提供有关服务账号密钥的更安全替代方案的培训。
  • 建立一个流程,以帮助开发者在创建新服务账号密钥之前,针对其用例确定合适的身份验证方法。
  • 使用组织政策限制条件来防止创建新的服务账号密钥,并仅允许已证明无法使用更安全的替代方案的项目例外情况。

使用组织政策限制条件来限制哪些项目可以创建服务账号密钥

鉴于更安全的服务账号密钥替代方案,最好将使用服务账号密钥视为例外情况,而非常规。

为了防止使用服务账号密钥,请使用组织政策限制条件

修改组织政策限制条件需要 orgpolicy.policy.set 权限。由于 Owner (roles/owner) 和 Editor (roles/editor) 角色均不包含此权限,因此在一些主账号可能具有项目的 Owner 或 Editor 访问权限的非生产环境中,限制条件可能也有效。

不要将服务账号密钥保留在临时位置

使用 Google Cloud 控制台创建服务账号密钥时,大多数浏览器会立即下载新密钥并将其保存到计算机上的下载文件夹中。您应立即将密钥移动到您要存储密钥的位置。请确保您没有意外将副本保留在下载文件夹或计算机的回收站中。

通过使用 Google Cloud CLI,您可以降低意外将服务账号密钥的副本保留在临时位置的风险:通过 gcloud iam service-accounts keys create 命令,您可以将服务账号密钥文件直接写入您需要该文件的位置。此外,在大多数操作系统上,gcloud CLI 会自动调整文件权限,使得只有您才能访问该文件。

不要在用户之间传递服务账号密钥

部署需要服务账号密钥的应用时,您可能无权自行创建服务账号密钥。您可能需要请求其他人员为您创建服务账号密钥。

如果服务账号密钥的创建和部署涉及多个用户,则密钥副本保留在邮箱、聊天记录或其他位置的风险会增加。每当需要在用户之间移交时,上传服务账号密钥可能会更安全:

  1. 以部署应用的用户身份,创建使用目标机器上 RSA 2048 位密钥对的自签名证书。如需创建证书,您可以使用 opensslcertutilNew-SelfSignedCertificate 或其他操作系统工具。
  2. 将证书文件传递给有权上传证书的用户,同时将私钥保留在目标机器上。传递证书时,请确保它不能被替换或篡改,但您不需要保密。
  3. 作为具有管理服务账号密钥所需权限的用户,上传证书以将其与服务账号相关联。

通过执行此过程,您可以避免传递私钥,而只是在用户之间交换公开信息。

不要将服务账号密钥提交到源代码库

服务账号密钥是凭据,必须免遭未经授权的访问。如果您将服务账号密钥提交到源代码库,则未经授权的用户和不法分子可以访问该密钥的风险会增加:

  • 不法分子可能会扫描公共代码库的源代码,查找泄露的密钥。
  • 将来,您可能会决定将私有源代码库转换为公共代码库,而没有先检查其密钥。
  • 其他团队成员可能会在其工作站中存储源代码的副本。

在处理使用服务账号密钥的代码时,请始终将服务账号密钥与源代码分开存储,以降低将该密钥意外提交到源代码库的风险。在许多情况下,您可以通过在开发期间完全不使用服务账号密钥,并使用个人凭据而非服务账号密钥来进一步降低此风险。

此外,设置您的源代码控制系统,使其能够检测到服务账号密钥意外提交情况:

不要将服务账号密钥嵌入程序二进制文件

服务账号密钥是与特定模式匹配的字符串,即使嵌入在其他文件或二进制文件中也可以识别。如果不法分子有权访问二进制文件,则他们可以提取嵌入在二进制文件中的任何服务账号密钥。

服务器端应用的程序二进制文件可能托管在工件代码库中,或者可能复制到开发者工作站进行调试。将服务账号密钥与程序二进制文件分开,有助于确保可以访问二进制文件的用户不会隐式获得对服务账号凭据的访问权限。

  • 对于客户端应用(如工具、桌面程序或移动应用),请勿使用服务账号。而是让用户使用 OAuth 同意流程,通过自己的凭据进行身份验证。
  • 对于服务器端应用,请勿将服务账号密钥嵌入二进制文件。而是将该密钥与应用二进制文件分开。

使用数据分析和指标来识别未使用的服务账号密钥

为了最大限度减少流通中的有效服务账号密钥的数量,最好在不再需要这些密钥时立即将其停用,然后在您确定不再需要这些密钥时将其删除。如果您不确定密钥是否仍在使用,可以使用服务账号数据分析和身份验证指标:

由于服务账号属于 Google Cloud 项目,因此必须为每个项目单独跟踪数据分析和指标。

轮替服务账号密钥以降低泄露的密钥造成的安全风险

虽然您可以降低意外泄露服务账号密钥的可能性,但可能很难完全消除风险。

密钥轮替是指将现有密钥替换为新密钥,然后使已替换的密钥失效的过程。我们建议您定期轮替您管理的所有密钥,包括服务账号密钥。

轮替服务账号密钥有助于降低因密钥泄露或被盗而带来的风险。如果密钥被泄露,不法分子可能需要数天或数周的时间才能发现密钥。如果您定期轮替您的服务账号密钥,那么当不法分子获得泄露的密钥时,这些密钥很有可能已经失效。

如果您怀疑服务账号密钥已遭到破解,那么制定服务账号密钥轮替流程也有助于您快速采取行动。

如果您自行生成公钥/私钥对,请将私钥存储在硬件安全模块 (HSM) 中并将公钥上传到 Google,然后您可能需要定期轮替密钥。另外,如果您认为密钥可能已被破解,您也可以轮替密钥。

使用过期时间让密钥自动失效

默认情况下,您通过 IAM 创建和下载的服务账号密钥没有过期时间,在您删除之前会一直有效。为服务账号密钥设置过期时间可以缩短永久性凭据的生命周期,从而降低安全风险。但是,设置过期时间会带来其他风险。例如,设置过期时间可能会导致工作负载在其密钥过期时失败。

如果您需要对要求提供服务账号密钥的系统进行临时访问,请使用过期时间。例如,在以下情况下请使用过期时间:

  • 在非生产环境中为只能通过服务账号密钥进行身份验证的应用开发代码
  • 使用只能通过服务账号密钥进行身份验证的第三方工具

在以下场景中,避免使用过期时间

  • 生产工作负载。在生产环境中,过期的服务账号密钥可能会导致意外的服务中断。请改为使用不会过期的密钥,并通过密钥轮替管理其生命周期。
  • 需要永久访问权限的非生产工作负载,例如持续集成 (CI) 流水线。
  • 会在指定时间后阻止使用密钥的密钥轮替系统。如需了解建议的密钥轮替策略,请参阅服务账号密钥轮替

为了限制服务账号密钥的有效性,您可以为在项目、文件夹或组织中新创建的密钥配置过期时间。过期时间不适用于现有密钥。

或者,您可以上传服务账号密钥,并在 X.509 证书文件中指定失效日期。在到期日期过后,不能将密钥用于身份验证。但是,它将与服务账号保持关联,直到您删除服务账号为止。

使用组织政策限制条件来自动停用泄露的密钥

即使您遵循了服务账号密钥的所有最佳实践,您的服务账号密钥也可能会发生泄露。

为帮助管理泄露的凭据,请确保将服务账号密钥泄露响应限制条件设置为 DISABLE_KEY。如果您将限制条件设置为此值,Google Cloud 会自动停用其检测到的所有泄露的密钥。

如果密钥因泄露而被停用,则会在密钥的元数据中添加以下字段:

  • "disable_reason": "SERVICE_ACCOUNT_KEY_DISABLE_REASON_EXPOSED":表示密钥因已公开而被停用。
  • "extended_status": "SERVICE_ACCOUNT_KEY_EXTENDED_STATUS_KEY_EXPOSED"表示相应密钥曾被公开过。即使您重新启用密钥,此值也会保留。
  • "extended_status_message": "LINK_TO_EXPOSURE":如果可用,元数据会包含指向检测到密钥的位置的链接,您可以使用该链接进行修复。

如果需要缓解中断情况,可以重新启用这些密钥。不过,我们建议您尽快再次停用这些密钥,因为公开的密钥会带来安全风险,即使最初的公开密钥已被移除也是如此。

如需了解管理被破解的凭据的其他最佳实践,请参阅处理被破解的 Google Cloud 凭据

防范权限提升

如果服务账号密钥受保护程度低于它们授予访问权限的资源,则使用服务账号密钥可能会让您面临权限提升攻击。

举例来说,假设不法分子在您的环境中已经站稳脚跟,现在尝试访问某些 Google Cloud 资源。他们可能仍然缺少访问这些资源的权限,但其权限可能足以访问存储在虚拟机、文件共享或其他受保护程度较低的位置中的服务账号密钥。通过使用该服务账号密钥进行身份验证,不法分子可以获得服务账号的身份。服务账号可能会允许不法分子访问他们之前无权访问的资源,从而提升不法分子的权限。

由于服务账号密钥会间接授予对 Google Cloud 上的资源的访问权限,因此您必须将密钥本身视为与这些资源本身一样重要,一样值得受保护。

以下部分介绍了保护服务账号密钥以及降低未经授权的访问和导致权限提升的风险的最佳做法。

不要将密钥存储在文件系统中

使用 Google Cloud 控制台或 gcloud CLI 创建的服务账号密钥是 JSON 文件,您可以将这些文件复制到需要它们的机器的文件系统中。但是,将服务账号密钥存储为文件系统中的文件可能会让您面临多种风险,包括:

  • 某些文件系统(如 NTFS)默认使用继承的权限。除非停用,否则添加到父级文件夹的权限可能会无意中导致未经授权的用户可更广泛地访问和查看密钥文件。
  • 在虚拟化环境中,不法分子或许可以通过访问底层虚拟磁盘来破坏文件系统的安全性。
  • 系统通常不会将文件系统访问和权限更改记录到审核日志中。如果文件权限被意外更改,且密钥对未经授权的用户可见,则可能很难分析何时以及由谁进行的这些更改。
  • 如果不法分子获得了访问权限,则文件会很容易被复制,从而遭到泄露。

请尽可能避免将服务账号密钥存储在文件系统中。如果无法避免将密钥存储在磁盘上,请务必限制对密钥文件的访问权限、配置文件访问权限审核并加密底层磁盘。

使用 HSM 或 TPM 存储密钥

使用 Google Cloud 控制台或 gcloud CLI 创建服务账号密钥时,Google Cloud 会生成私钥,然后向您显示。与服务账号密钥相关的许多安全风险是由于以明文形式暂时或永久提供私钥导致的,因此很难进行保护。

您可以使用硬件安全模块 (HSM) 或可信平台模块 (TPM) 来创建和管理密钥,而不是让 Google Cloud 生成密钥对:

  1. 使用 HSM 或 TPM 生成 RSA 密钥对。
  2. 使用密钥对创建自签名证书。
  3. 上传证书作为服务账号密钥。
  4. 允许应用使用 HSM 或 TPM 的签名 API 为 JWT 签名,以对服务账号进行身份验证。

HSM 或 TPM 让您无需以明文形式显示私钥即可使用它。因此,使用 HSM 或 TPM 管理服务账号密钥有助于强制执行访问权限控制,同时降低将密钥复制到其他系统的风险。

一些平台提供了抽象功能,让您能够利用 TPM,而无需直接与其交互。例如,Windows 允许您将 CryptoNG API 与 Microsoft Platform Crypto Provider 结合使用,来管理受 TPM 保护的密钥。

由 TPM 管理的服务账号密钥对于物理机器或虚拟机而言是唯一的。您仍然可以通过将每台机器的密钥与一个公用服务账号相关联,让多台机器共用一个服务账号。

使用基于软件的密钥库

如果使用基于硬件的密钥库不可行,则使用基于软件的密钥库来管理服务账号密钥。与基于硬件的选项类似,基于软件的密钥库让用户或应用无需显示私钥即可使用服务账号密钥。基于软件的密钥库解决方案可以帮助您精细控制密钥访问,还可以确保记录每次密钥访问。

基于软件的密钥库的安全性通常取决于其主密钥的保护方式。在使用基于软件的密钥库之前,请务必查看:

  • 如何为主密钥提供静态保护,
  • 解封过程的工作原理以及谁可以启动此过程,
  • 如何防止从内存中提取密钥,
  • 如果不法分子获得了对底层系统的 shell 访问权限或 Hypervisor 访问权限,则如何防止密钥库被破坏。

不要将密钥存储在 Secret Manager 或其他云端密文库中

我们不建议使用 Google Cloud 的 Secret Manager 来存储和轮替服务账号密钥。这是因为,如需访问 Secret Manager 密钥,您的应用需要拥有 Google Cloud 可以识别的身份。如果您的应用已具有 Google Cloud 可以识别的身份,则可以使用该身份向 Google Cloud 进行身份验证,而无需使用服务账号密钥。

其他基于云的 Secret 管理服务(例如 Azure KeyVault 和 AWS Secret Manager)也适用相同的概念。如果应用已具有这些云服务提供商可以识别的身份,则可以使用该身份向 Google Cloud 进行身份验证,而无需使用服务账号密钥。

不要在允许创建或上传服务账号密钥的项目中使用 Editor 角色

Editor (roles/editor) 和 Owner (roles/owner) 基本角色之间的主要区别在于Editor 角色不允许您更改 IAM 政策或角色。因此,使用 Editor 角色无法轻易扩展您自己的访问权限或授予其他用户对项目资源的访问权限。

如果项目包含服务账号,则 Editor 角色的限制可能会受影响。由于 Editor 角色授予创建或上传服务账号密钥的权限,因此不法分子可以为现有服务账号创建新密钥,并使用这些密钥提升自己的访问权限,或将这些密钥移交给其他用户来获取对项目资源的访问权限。

最好使用权限范围较窄的预定义角色,或者创建仅授予必要权限的自定义角色,而不是使用 Editor 角色或任何其他基本角色。

如果您需要使用 Editor 角色,请使用组织政策限制条件来停用服务账号密钥上传功能密钥创建功能,以帮助确保 Editor 角色不能因权限提升而被滥用。

避免使用服务账号密钥进行全网域授权

通过全网域授权,您可以模拟用户,以便您在用户端未进行任何手动授权的情况下也能访问用户的数据。虽然说明使用全网域授权的示例通常建议使用服务账号密钥,但使用服务账号密钥不是执行全网域授权所必需的。

使用全网域授权时,请避免使用服务账号密钥,而是改用 signJwt API

  1. 首先使用附加的服务账号适用于 GKE 的工作负载身份联合工作负载身份联合对服务账号进行身份验证。
  2. 构造 JWT 并使用 sub 声明指定您为其请求委托访问权限的用户的电子邮件地址。
  3. 使用 signJwt API 为 JWT 签名。
  4. 传递已签名的 JWT 给 OAuth2 令牌资源以获取访问令牌。

通过使用此方法,您可以不必管理服务账号密钥,从而可以更轻松地确保设置的安全。

防范信息泄露威胁

避免在上传的 X.509 证书中披露机密信息

对于每个服务账号密钥,IAM 允许您从端点 https://www.googleapis.com/service_accounts/v1/metadata/x509/ACCOUNT_EMAIL 下载 X.509 证书。此端点是公开的,不需要身份验证。

对于使用 Google Cloud 控制台或 gcloud CLI 创建的 Google 管理的密钥和用户管理的密钥,X.509 证书是自动创建的,并且仅包含电子邮件地址是和失效日期等基本元数据。

对于上传的服务账号密钥,由公共端点提供的 X.509 证书与您上传的证书相同。如果您上传的证书包含任何可选特性(例如嵌入在通用名称中的地址或位置信息),则此信息也可以公开访问。不法分子可能会使用此信息来详细了解您的环境。

为避免披露机密信息,请勿将任何可选特性添加到上传的 X.509 证书中,并使用通用 Subject

防范不可否认的威胁

当您发现影响 Google Cloud 资源的可疑活动并且想要分析其来源时,需要数据来重建导致可疑活动的事件链。执行此类分析的主要数据源通常是审核日志。

涉及服务账号时,分析审核日志可能会更加困难:如果活动由某服务账号发起,则日志条目会包含该服务账号的电子邮件地址,但您还需要找出发起时哪个用户或应用正在使用该服务账号。

以下部分介绍了使用服务账号密钥的最佳做法,从而帮助您跟踪其使用情况。

为每个应用使用专用的服务账号

所有审核日志记录都包含 principalEmail 字段,用于标识发起活动的主账号。如果您在多个应用之间共用一个服务账号密钥,则很难识别哪个应用执行了活动,因为审核日志记录包含相同的 principalEmail 值。

您需要为每个应用创建一个专用服务账号,而不是在多个应用之间共用一个密钥。这样,principalEmail 字段可让您识别与服务账号关联的应用,这样可以帮助您重建导致可疑活动的事件链。

为运行应用的每台机器使用专用密钥

如果您在多台机器上运行同一应用的多个副本,则 principalEmail 字段可能会允许您识别应用,但无法识别特定活动源自的机器。

为了帮助您缩小可疑活动的潜在来源的范围,请为应用的每个副本创建单独的密钥。这样,您就可以使用许多服务添加到审核日志记录中的 serviceAccountKeyName 字段来区分活动源自的机器。

后续步骤