保护 SSH 凭据的最佳实践


本文档介绍了保护 SSH 凭据的最佳实践。

默认情况下,Compute Engine 使用基于公钥的 SSH 身份验证:用户通过其拥有的凭据(即 SSH 私钥)进行身份验证。如果用户的私钥未正确受到保护,则可能会落入作恶方之手,他们可能会使用这些密钥访问您的虚拟机实例。

以下部分包含一些最佳实践,可帮助您避免密钥泄露并降低泄露的私钥的潜在影响:

本文档重点介绍特定于 Google Cloud 的实践或在 Google Cloud 上使用 SSH 时特别重要的实践。本文档未涵盖特定 SSH 客户端或服务器实现的最佳实践。

采用与服务账号密钥处理方法类似的方法处理 SSH 私钥

您的某些虚拟机实例可能具有关联服务账号。将服务账号关联到虚拟机后,在这些虚拟机上运行的工作负载可以向元数据服务器请求短期有效的访问令牌,以便可以访问 Google Cloud API 和资源。

使用 SSH 连接到具有关联服务账号的虚拟机时,您也可以向元数据服务器请求短期有效的访问令牌。因此,向用户授予对虚拟机的 SSH 访问权限与向用户授予充当关联服务账号的权限类似。由于存在这种相似性,请如同服务账号密钥一样处理 SSH 私钥,尤其是它们不受口令保护时:这两种类型的密钥如果遭到泄露,都可能会向作恶方授予对 Google Cloud 资源的访问权限。

为机器用户使用临时 SSH 密钥

部署流水线或自动化流程可能需要通过 SSH 访问虚拟机实例才能执行部署或应用配置更改。请勿让这些工作负载使用长期有效的 SSH 密钥对,而是让它们在每次运行时使用新的临时 SSH 密钥。

如需使用临时 SSH 密钥,请让您的部署流水线或自动化流程执行以下步骤:

  1. 采用不涉及密钥或密文的方式以服务账号的身份进行身份验证,例如使用关联服务账号工作负载身份联合
  2. 使用 ssh-keygen 等工具生成临时 SSH 密钥对。
  3. 将公钥发布到 Google Cloud,并指定不久后的失效日期(例如未来 1 小时)。

    借助 OS Login,您可以在发布密钥时指定密钥失效日期。同样,在将 SSH 公钥发布到项目或虚拟机元数据时,您也可以指定失效日期

  4. 使用私钥建立与虚拟机实例的 SSH 连接。

  5. 您可以选择取消发布公钥并删除私钥。

例如:

# Generate RSA key pair without passphrase
ssh-keygen -t rsa -f ephemeral_key -q -N "" -V 30m

# Publish key to the service account's OS Login profile, with 30 min expiry
gcloud compute os-login ssh-keys add --key-file ephemeral_key.pub --ttl 30m

# Look up the service account's UNIX username
USERNAME=$(gcloud compute os-login describe-profile --format "value(posixAccounts[0].username)")

# Authenticate using the service account's UNIX user and public key
ssh $USERNAME@VM whoami

# Remove key
gcloud compute os-login ssh-keys remove --key-file ephemeral_key.pub

虽然临时 SSH 私钥仍然可能会泄露,但只能在短时间内使用。因此,使用临时 SSH 密钥可以降低凭据泄露的风险,并让您可以将 Cloud IAM 用作主要的身份验证和授权方式。

使用 IAP 对 SSH 公钥身份验证进行补充

默认情况下,SSH 私钥可独立于 Google 凭据使用:如果用户的 SSH 私钥泄露,作恶方可以使用该密钥连接到授权该密钥访问的任何虚拟机实例并进行身份验证。作恶方不必知道用户的用户名或密码,甚至不必拥有任何 Google 凭据。

安全控制措施(两步验证限制 Google Cloud 服务的会话时长)可以有效降低凭据被盗的风险,但这些控制措施仅适用于需要 Google 凭据的资源。

如需确保在没有有效 Google 凭据的情况下无法使用 SSH 密钥,请使用 IAP 管理 SSH 访问并使用防火墙政策强制通过 IAP 执行所有 SSH 访问。

IAP 充当反向代理,仅在用户使用 Google 凭据成功进行身份验证后,才允许用户建立与虚拟机实例的 SSH 连接。此外,IAP 使您可以限制用户可以连接到哪些虚拟机,并强制执行情境感知访问权限。

使用多重身份验证

使用 IAP 管理 SSH 访问会使作恶方更难使用泄露的凭据访问虚拟机实例,但这并不会杜绝这种情况:例如,作恶方可能会破解工作站并找到 SSH 私钥和缓存的 gcloud CLI 凭据,这足以通过 IAP 的身份验证和授权检查,以及连接到用户的虚拟机实例。

您可以配置 Cloud Identity 或 Google Workspace 以要求使用多重身份验证 (MFA),从而降低此类凭据盗用攻击的可能影响。

如果 Cloud Identity 或 Google Workspace 是您的主要身份提供方,请执行以下操作来强制执行 MFA:

  1. 配置 Cloud Identity 或 Google Workspace 以强制执行两步验证
  2. 限制 Google Cloud 服务的会话时长,以使缓存的凭据自动失效,用户必须定期重新进行身份验证并执行 MFA。

如果您将单点登录与外部 IdP 搭配使用,请改为执行以下操作:

  1. 配置 Cloud Identity 或 Google Workspace 以限制 Google Cloud 服务的会话时长,以使缓存的凭据自动失效,用户必须定期使用外部 IdP 重新进行身份验证。
  2. 配置外部 IdP 配置以要求使用 MFA,并限制其会话时长,以便用户在每次 Google Cloud 会话过期时都必须执行 MFA。

如需确保 MFA 也适用于 SSH 访问,您还必须执行以下至少一项操作:

  1. 使用 IAP 控制网络访问,以便用户必须定期执行 MFA 来刷新其 Google 凭据。
  2. 为单个虚拟机实例或整个项目启用 OS Login 2FA,以便用户在每次建立 SSH 连接时都必须执行 MFA。

具有虚拟机实例或项目的 Compute Instance Admin 或等效角色的用户可以通过修改实例元数据来停用 OS Login 2FA。因此,如果您未在 Cloud Identity 或外部 IdP 中也强制执行 MFA,OS Login 2FA 的有效性会受到限制。

使用不可导出的私钥或受口令保护的私钥

许多 SSH 客户端默认会将 SSH 私钥存储为磁盘上的文件。例如,gcloud compute ssh 会在首次使用时生成 SSH 密钥对,并将其存储在您的主目录中。您的操作系统可能会保护您的文件不被其他用户访问,但如果作恶方可以绕过文件系统权限(例如,通过复制磁盘并将其装载到其他机器上),他们便可以将密钥复制到其他位置,并在您不知情的情况下进行使用。

某些 SSH 客户端允许您避免使用基于文件的密钥,并提供替代选项来管理 SSH 私钥,例如:

  • 使用由硬件支持的密钥:现代版本的 OpenSSH 使您可以使用 FIDO2 安全密钥进行身份验证,您可以配置 OS Login,以使其仅允许使用在 Cloud Identity 或 Google Workspace 中注册的安全密钥。使用由硬件支持的密钥有助于避免在计算机的文件系统中存储任何私钥材料。
  • 使用操作系统的密钥存储工具:例如,IAP 桌面可避免使用基于文件的密钥,而是使用 Windows CNG 来保护您的 SSH 密钥。

如果无法使用由硬件支持的密钥或操作系统管理的密钥,则您可以使用口令来保护 SSH 私钥:如需使用受口令保护的 SSH 密钥,作恶方不仅需要私钥的副本,还需要知道密钥的口令。

使用主机密钥对主机进行身份验证

创建与虚拟机实例的 SSH 连接时,您可以通过其名称或 IP 地址标识虚拟机实例。名称和 IP 地址可以重新分配和重复使用,昨天引用某个虚拟机实例的名称在今天可能不会引用同一个虚拟机实例。作恶方可能会故意重新分配或重复使用名称或 IP 地址来仿冒虚拟机实例,诱骗用户连接到已被入侵的虚拟机。

SSH 客户端可以使用 SSH 主机密钥检测之前可信的虚拟机实例被其他虚拟机实例替换的情况:虚拟机的 SSH 主机密钥在首次启动时生成,用于标识实例。SSH 客户端通常会在首次连接时请求并存储虚拟机的主机密钥,并在后续连接时验证虚拟机的主机密钥是否未更改。

SSH 主机密钥的工作原理基于首次使用时信任方案。如果作恶方使用中间人 (MITM) 攻击,让客户端在首次使用时连接并信任错误的虚拟机,则 SSH 主机密钥的有效性会受到影响。获取主机密钥的更好方法是在首次连接到虚拟机之前通过可信的边信道获取。

您可以在项目中通过启用客机属性让 gcloud CLI 通过返回信道获取主机密钥。然后,gcloud CLI 会在您首次连接虚拟机之前读取虚拟机的主机密钥,并将其保存在您的本地计算机上。

请勿在虚拟机上留下个人凭据

当您向 gcloud CLI 授权时,该工具会获取 OAuth 刷新令牌并将其存储在您的本地主目录中。当您后续运行 gcloud CLI 命令时,gcloud CLI 会使用该刷新令牌自动对您进行身份验证。

其他用户可能无法访问您的本地计算机,但在虚拟机实例中,在虚拟机上具有 sudo 权限的其他用户也可以访问您的主目录。

如果作恶方设法获取了虚拟机的 sudo 权限,他们可能会在其他用户的主目录中扫描获取刷新令牌和其他凭据,并使用这些凭据升级其权限或将其访问权限扩展到其他资源(横向移动)。

通过 SSH 连接到虚拟机实例后,请避免使用您的个人凭据向 gcloud CLI 或应用默认凭据 (ADC) 授权,而让 gcloud CLI 改用虚拟机的关联服务账号。同样,请避免运行可能会将个人凭据存储在主目录中的其他工具。

您可以限制 Google Cloud 服务的会话时长,以便存储的 OAuth 刷新令牌在一定时间后自动失效,从而进一步降低风险。

请勿将 SSH 私钥提交到源代码库

某些自动化工具(例如 Ansible)使用 SSH 来访问和管理虚拟机实例。由于此类工具可能有权访问多个虚拟机实例(及其关联服务账号),因此此类工具使用的 SSH 私钥可能会特别敏感。

如果您将 SSH 私钥提交到源代码库,则未经授权的用户和作恶方可以访问该密钥的风险会增加:

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

如需降低这些风险,请将 SSH 私钥存储在与源代码分离的安全位置,并尽可能使用临时 SSH 密钥。

后续步骤