管理服务帐号密钥的最佳做法

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

由于私钥允许您以服务帐号身份进行身份验证,因此有权访问私钥类似于知道用户的密码。

服务帐号使用的密钥对分为两类:Google 管理的密钥对和用户管理的密钥对。Google 管理的密钥对和用户管理的密钥对在以下几个方面不同:私钥的存储位置、密钥对如何用于身份验证以及必须如何进行保护:

  • Google 管理的密钥对由 Identity and Access Management 自动生成并完全管理。IAM 会为所有服务帐号维护 Google 管理的密钥对,并定期进行轮替。您可以下载 Google 管理的密钥对的公钥,但无法访问其私钥。

    如需使用 Google 管理的密钥对的私钥,您必须请求 IAM 为您执行操作。例如,您可以调用 signBlobsignJwt 操作来允许 IAM 使用服务帐号的 Google 管理的私钥为您签署一段数据。同样,通过将服务帐号关联到计算资源,您可以授权 IAM 在每次计算资源请求服务帐号凭据时都使用 Google 管理的密钥。

    请求 IAM 为您使用服务帐号的 Google 管理的私钥需要特殊权限。例如,如需调用 signBlob,您必须拥有相应服务帐号的 iam.serviceAccounts.signBlob 权限。同样,如需将服务帐号关联到计算资源,您必须拥有 iam.serviceAccounts.actAs 权限。为了保护服务帐号并防范权限提升威胁,您必须确保只向已获授权的用户授予提供这些权限的角色。

  • 用户管理的密钥对是可以通过上传公钥或让 IAM 为您生成密钥对来与服务帐号关联的附加密钥对。在这两种情况下,IAM 仅会存储公钥,而您拥有私钥。

    私钥以及一些元数据称为服务帐号密钥,通常以 JSON 格式存储。

    由于您拥有私钥,因此您负责确保私钥保密、安全地存储私钥并定期进行轮替。任何可以访问私钥的用户都可以使用它创建 JWT 不记名令牌,并以服务帐号的身份进行身份验证。

如果未谨慎管理,服务帐号密钥可能会带来安全风险。与服务帐号密钥相关的主要威胁包括:

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

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

对于使用替代身份验证方法不可行的情况,本指南介绍了管理、使用和保护服务帐号密钥的最佳做法。

防范凭据泄露

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

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

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

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

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

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

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

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

如果您的组织中的用户发现创建新的服务帐号密钥比使用更安全的替代方案更加容易,则尝试减少流通中的服务帐号密钥的数量可能会很困难。

为防止用户为方便起见而创建服务帐号密钥,请确保用户了解使用服务帐号密钥的替代方案,并能够在需要执行以下操作时使用这些替代方案:

在确保用户可以使用替代方法对服务帐号进行身份验证后,请使用组织政策限制条件来限制只有所选项目可以使用服务帐号密钥。

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

您可以通过多种方式避免创建服务帐号密钥,包括将服务帐号附加到资源、使用 Workload Identity 或使用工作负载身份联合。基于上述替代方案,最好将使用服务帐号密钥视为例外情况,而非常规。

为防止不必要地使用服务帐号密钥,请使用组织政策限制条件

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

轮替服务帐号密钥以减少泄露的密钥造成的潜在损害

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

如果密钥被泄露,不法分子可能无法立即找到它,而是可能需要数天或数周的时间才能找到密钥。您可以定期使服务帐号密钥失效并将其替换为新密钥,来充分利用此延迟时间:轮替服务帐号密钥的频率越高,不法分子找到泄露的服务帐号密钥时此密钥仍有效的可能性就越小。

如需轮替密钥,您可以遵循基于推送或拉取的模型:

  • 在基于推送的模型中,您可以使用集中式工具或系统,以定期创建新的服务帐号密钥并将其推送到各个应用来替换现有密钥。之后,该工具会删除过时的服务帐号密钥。

    在此模型中,只有集中式工具需要创建或上传新服务帐号密钥的权限,但它需要其管理的所有服务帐号都具备这些权限。

  • 在基于拉取的模型中,每个应用自行处理密钥轮替。应用会定期使用 IAM API 创建或上传新服务帐号密钥,同时使用其现有密钥进行身份验证。应用获得新服务帐号密钥后,将删除其先前的密钥。

    在此模型中,每个应用的服务帐号都必须有权创建或上传新服务帐号密钥,但仅限于其自身。

使用上传的密钥让密钥自动失效

您通过 IAM 创建和下载的服务帐号密钥没有失效日期,在您删除之前会一直有效。

您可以通过上传服务帐号密钥并在 X.509 证书文件中指定失效日期来限制服务帐号密钥的有效性。失效日期过后,密钥将无法再用于身份验证,但在您删除密钥之前会与服务帐号保持关联。

限制服务帐号密钥的有效性可以限制安全风险,并在密钥轮替失败时可作为故障安全措施。同时,限制密钥的有效性会增加因未及时续订的密钥而导致应用故障的风险。

防范权限提升

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

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

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

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

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

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

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

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

使用 HSM 或 TPM 存储密钥

使用 Google Cloud Console 或 gcloud 工具创建服务帐号密钥时,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、Azure KeyVault 或 AWS Secret Manager。如果您将服务帐号密钥存储在其中一个密钥库中,则必须使用云提供商的 IAM 系统来控制对密文的访问权限。除了使用 IAM 来控制对密文的访问权限,然后授予对 Google Cloud 上的资源的访问权限,还可以在无需创建服务帐号密钥的情况下使用工作负载身份联合来管理访问权限。

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

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

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

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

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

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

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

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

  1. 首先使用附加的服务帐号Workload Identity工作负载身份联合对服务帐号进行身份验证。
  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 Console 或 gcloud 工具创建的 Google 管理的密钥和用户管理的密钥,X.509 证书是自动创建的,并且仅包含电子邮件地址是和失效日期等基本元数据。

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

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

防范不可否认的威胁

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

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

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

为每个应用使用专用服务帐号

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

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

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

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

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

后续步骤