跳到内容

密钥管理速查表

1 简介

如今,密钥无处不在,尤其随着 DevOps 运动的普及。应用程序编程接口 (API) 密钥、数据库凭据、身份和访问管理 (IAM) 权限、安全外壳 (SSH) 密钥、证书等。许多组织将其硬编码在源代码中,以明文形式散布在配置文件和配置管理工具中。

组织越来越需要集中存储、供应、审计、轮换和管理密钥,以控制对密钥的访问并防止它们泄露和损害组织。通常,服务共享相同的密钥,这使得识别泄露或泄露的来源变得具有挑战性。

本速查表提供了最佳实践和指南,以帮助正确实施密钥管理。

2 通用密钥管理

以下部分讨论了与密钥管理相关的主要概念。

2.1 高可用性

选择足够强大的技术来可靠地提供流量至关重要。

  • 用户(例如 SSH 密钥、root 账户密码)。在事件响应场景中,用户期望能够快速获得凭据,以便恢复离线服务。等待凭据可能会影响操作团队的响应速度。
  • 应用程序(例如数据库凭据和 API 密钥)。如果服务性能不佳,可能会降低依赖应用程序的可用性或增加应用程序启动时间。

在大型组织中,此类服务可能会收到大量请求。

2.2 集中化和标准化

DevOps 团队用于应用程序的密钥可能与市场营销团队或 SRE 团队存储的密钥以不同方式使用。您经常会发现维护不善的密钥,其中密钥使用者或生产者的需求不匹配。因此,您必须谨慎地标准化和集中化密钥管理解决方案。标准化和集中化可能意味着您使用多个密钥管理解决方案。例如:您的云原生开发团队选择使用云提供商提供的解决方案,而您的私有云使用第三方解决方案,并且每个人都有一个选定的密码管理器帐户。通过确保团队标准化与这些不同解决方案的交互,它们在发生事件时仍可维护和可用。即使公司将其密钥管理集中到一个解决方案,您通常也需要将该密钥管理解决方案的主要密钥存储在辅助密钥管理解决方案中。例如,您可以使用云提供商的设施来存储密钥,但该云提供商的根/管理凭据需要存储在其他地方。

标准化应包括密钥生命周期管理、密钥管理解决方案的身份验证、授权和记账,以及生命周期管理。请注意,组织应立即清楚密钥的用途以及在哪里可以找到它。您使用的密钥管理解决方案越多,您需要的文档就越多。

2.3 访问控制

当用户可以在密钥管理系统中读取密钥和/或更新密钥时,这意味着密钥现在可以通过该用户和他用于操作密钥的系统泄露。因此,工程师不应拥有密钥管理系统中所有密钥的访问权限,应应用最小权限原则。密钥管理系统需要提供在每个对象和组件上配置细粒度访问控制的能力,以实现最小权限原则。

2.4 自动化密钥管理

手动维护不仅增加了泄露的风险;它还引入了在维护密钥时人为错误的风险。此外,它可能会变得浪费。因此,最好限制或消除人与实际密钥的交互。您可以通过多种方式限制人为交互:

  • 密钥管道: 拥有一个密钥管道,负责密钥管理的大部分工作(例如创建、轮换等)。
  • 使用动态密钥: 当应用程序启动时,它可以请求其数据库凭据,这些凭据在动态生成时将为该会话提供新的凭据。应尽可能使用动态密钥,以减少凭据重用的影响范围。如果应用程序的数据库凭据被盗,重新启动后它们将过期。
  • 静态密钥的自动化轮换: 密钥轮换在手动实施时是一个具有挑战性的过程,可能导致错误。因此,最好自动化密钥的轮换,或者至少确保该过程得到 IT 的充分支持。

轮换某些密钥(例如加密密钥)可能会触发完全或部分数据重新加密。存在不同的密钥轮换策略:

  • 渐进式轮换
  • 为写入操作引入新密钥
  • 为读取操作保留旧密钥
  • 快速轮换
  • 预定轮换
  • 等等...

2.5 内存中密钥的处理

通过最小化密钥在内存中的时间窗口并限制对其内存空间的访问,可以实现额外的安全级别。

根据应用程序的具体情况,这可能很难以确保内存安全的方式实现。由于这种潜在的实现复杂性,建议您首先开发威胁模型,以便清楚地揭示您对应用程序部署环境的隐式假设,并了解攻击者的能力。

通常,尝试保护内存中的密钥会被认为是过度杀伤,因为当您评估威胁模型时,您所考虑的潜在威胁行为者要么没有能力执行此类攻击,要么防御成本远远超过因内存中暴露密钥而导致的泄露可能造成的影响。此外,在开发适当的威胁模型时应牢记,如果攻击者已经访问了处理密钥的进程内存,那么此时可能已经发生了安全漏洞。此外,应该认识到,随着 RowhammerMeltdown 和 Spectre 等攻击的出现,重要的是要了解操作系统本身不足以保护您的进程内存免受这些类型攻击。当您的应用程序部署到云中时,这变得尤为重要。保护内存免受这些及类似攻击的唯一万无一失的方法是,将您的进程内存与所有其他不受信任的进程完全物理隔离。

尽管存在实施困难,但在高度敏感的环境中,保护内存中的密钥可以作为有价值的附加安全层。例如,在高级攻击者可能导致系统崩溃并获得内存转储访问权限的场景中,他们可能能够从中提取密钥。因此,在不受信任的环境或安全至关重要的情况下,建议仔细保护内存中的密钥。

此外,在 C/C++ 等低级语言中,保护内存中的密钥相对容易。因此,即使攻击者访问内存的风险很低,实施此实践也可能是有益的。另一方面,对于依赖垃圾回收的编程语言,保护内存中的密钥通常要困难得多。

  • 结构和类: 在 .NET 和 Java 中,不要使用不可变结构(如 Strings)来存储密钥,因为无法强制它们进行垃圾回收。相反,请使用基本类型,如字节数组或字符数组,可以直接覆盖内存。您还可以使用 Java 的 GuardedString 或 .NET 的 SecureString,它们正是为了解决这个问题而设计的。

  • 清零内存: 密钥使用后,应将其占用的内存清零,以防止其在内存中残留并可能被访问。

    • 如果使用 Java 的 GuardedString,请调用 dispose() 方法。
    • 如果使用 .NET 的 SecureString,请调用 Dispose() 方法。
  • 内存加密: 在某些情况下,可能可以使用硬件或操作系统功能来加密处理密钥的进程的整个内存空间。这可以提供额外的安全层。例如,Java 中的 GuardedString 会加密内存中的值,而 .NET 中的 SecureString 在 Windows 上也会这样做。

请记住,目标是尽可能缩短密钥在内存中以明文形式存在的时间窗口。

有关更详细的信息,请参阅 OWASP MAS 项目的 敏感数据内存测试

2.6 审计

由于应用程序的性质,审计是密钥管理的重要组成部分。您必须安全地实施审计,以抵御篡改或删除审计日志的尝试。至少,您应该审计以下内容:

  • 谁请求了密钥以及用于哪个系统和角色。
  • 密钥请求是否获得批准或拒绝。
  • 密钥何时使用以及由谁/什么使用。
  • 密钥何时过期。
  • 是否有任何尝试重用过期密钥。
  • 是否有任何身份验证或授权错误。
  • 密钥何时更新以及由谁/什么更新。
  • 底层支持基础设施堆栈上的任何管理操作和可能的实际用户活动。

所有审计都必须具有正确的时间戳。因此,密钥管理解决方案应在其支持基础设施上设置正确的时间同步协议。您应该监控运行该解决方案的堆栈,以发现可能的时钟偏差和手动时间调整。

2.7 密钥生命周期

密钥遵循生命周期。生命周期的阶段如下:

  • 创建
  • 轮换
  • 撤销
  • 过期

2.7.1 创建

新密钥必须安全生成,并具有足够的加密强度以满足其目的。密钥必须分配最低权限,以启用其所需的用途/角色。

您应该安全地传输凭据,理想情况下,在请求用户账户时,不要将密码与用户名一起发送。相反,您应该通过安全通道(例如相互验证的连接)或旁路通道(例如推送通知、短信、电子邮件)发送密码。请参阅 多因素认证速查表,了解每个通道的优缺点。

应用程序可能无法从拥有多个通信通道中受益,因此您必须安全地供应凭据。

有关密钥创建的更多技术建议,请参阅 Open CRE 项目关于密钥查找 的内容。

2.7.2 轮换

您应该定期轮换密钥,这样任何被盗的凭据只能在短时间内有效。定期轮换还将减少用户退回不良习惯(如重复使用凭据)的倾向。

根据密钥的功能及其保护的内容,生命周期可能从几分钟(完美前向保密的端到端加密聊天)到几年(硬件密钥)。

用户凭据不属于定期轮换的范围。根据 NIST 建议,只有在怀疑或有证据表明它们已受到损害时才应轮换这些凭据。

2.7.3 撤销

当不再需要或可能泄露密钥时,您必须安全地撤销它们以限制访问。对于(TLS)证书,这还涉及证书撤销。

2.7.4 过期

在可能的情况下,您应该创建在指定时间后过期的密钥。此过期可以是密钥使用系统的主动过期,也可以是密钥管理系统中设置的过期日期,强制触发支持过程,从而导致密钥轮换。您应该通过密钥管理解决方案应用策略,以确保凭据仅在适合凭据类型的有限时间内可用。应用程序应在信任密钥之前验证密钥是否仍处于活动状态。

2.8 随处可见的传输层安全 (TLS)

切勿通过明文传输密钥。在当今时代,鉴于 TLS 的普遍采用,没有借口。

此外,您可以有效使用密钥管理解决方案来提供 TLS 证书。

2.9 停机、紧急访问、备份和恢复

考虑密钥管理服务因各种原因(例如计划维护停机)而变得不可用的可能性。如果您之前没有获取凭据,则可能无法检索恢复服务所需的凭据。因此,根据早期指标和审计日志仔细选择维护窗口。

其次,应定期测试和审计系统的备份和恢复程序的安全性。关于备份和恢复的一些要求。确保:

  • 已建立自动化备份程序并定期执行;备份和快照的频率应基于密钥数量及其生命周期。
  • 经常测试恢复程序,以确保备份完整无损。
  • 加密备份并将其放置在具有受限访问权限的安全存储上。监控备份位置,防止(未经授权的)访问和管理操作。

最后,您应该实施紧急(“破窗”)流程,以便在系统因非定期维护原因而变得不可用时恢复服务。因此,紧急破窗凭据应定期安全地备份到辅助密钥管理系统,并定期测试以验证其有效性。

2.10 策略

在组织范围内一致地执行定义密码最低复杂性要求和批准的加密算法的策略。使用集中式密钥管理解决方案可以帮助公司实施这些策略。

其次,拥有组织范围的密钥管理策略可以帮助强制执行本速查表中定义的最佳实践。

2.11 元数据:准备迁移密钥

密钥管理解决方案应提供至少存储以下关于密钥的元数据的功能:

  • 创建/使用/归档/轮换/删除的时间
  • 创建/使用/归档/轮换/删除者(例如,实际生产者和使用生产方法的工程师)
  • 创建/使用/归档/轮换/删除的内容
  • 在遇到密钥问题或有疑问时联系谁
  • 密钥的用途(例如,指定的目标使用者和密钥的目的)
  • 密钥的类型(例如,AES 密钥、HMAC 密钥、RSA 私钥)
  • 如果手动轮换,何时需要轮换

注意:如果您不存储有关密钥的元数据,也不准备迁移,则会增加供应商锁定的可能性。

3 持续集成 (CI) 和持续部署 (CD)

构建、测试和部署变更通常需要访问许多系统。持续集成 (CI) 和持续部署 (CD) 工具通常存储密钥以向应用程序提供配置或在部署期间提供配置。或者,它们与密钥管理系统进行大量交互。各种最佳实践可以帮助 CI/CD 中的密钥管理顺利进行;本节将讨论其中一些。

3.1 硬化 CI/CD 管道

CI/CD 工具定期使用(高权限)凭据。确保管道不容易被员工攻击或滥用。以下是一些可以帮助您的指南:

  • 将 CI/CD 工具视为生产环境:对其进行强化、修补,并强化其底层基础设施和服务。
  • 实施安全事件监控。
  • 实施最小权限访问:开发人员不需要管理项目。相反,他们只需要能够执行所需的功能,例如设置管道、运行管道和处理代码。管理任务可以使用单独存储库中的配置即代码快速完成,该存储库由 CI/CD 系统用于更新其配置。不需要可能访问密钥的特权角色。
  • 确保管道输出不会泄露密钥,并且您无法使用调试工具监听生产管道。
  • 确保您无法执行任何 CI/CD 系统的运行器和工作器。
  • 实施适当的身份验证、授权和记账。
  • 确保只有经批准的流程才能创建管道,包括 MR/PR 步骤,以确保创建的管道经过安全审查。

3.2 密钥应该在哪里?

有多种地方可以存储密钥以执行 CI/CD 操作:

  • 作为 CI/CD 工具的一部分:您可以将密钥存储在 GitLab/GitHub/Jenkins 中。这与提交到代码不同。
  • 作为您的密钥管理系统的一部分:您可以将密钥存储在密钥管理系统中,例如云提供商(AWS Secret ManagerAzure Key VaultGoogle Secret Manager)或第三方设施(Hashicorp VaultConjurKeeper)提供的设施中。在这种情况下,CI/CD 管道工具需要凭据才能连接到这些密钥管理系统以获取密钥。有关使用云提供商的密钥管理系统的更多详细信息,请参阅 云提供商

另一种选择是使用 CI/CD 管道利用密钥管理系统的加密即服务来对密钥进行加密。然后,CI/CD 工具可以将加密的密钥提交到 git,部署时消费服务可以获取并再次解密。有关更多详细信息,请参阅 3.6 节。

注意:并非所有密钥都必须在 CI/CD 管道中才能到达实际部署。相反,请确保已部署的服务在自己的生命周期(例如部署、运行时和销毁)中处理其部分密钥管理。

3.2.1 作为 CI/CD 工具的一部分

当密钥成为 CI/CD 工具的一部分时,这意味着这些密钥会暴露给您的 CI/CD 作业。CI/CD 工具可以包括例如 GitHub 密钥、GitLab 存储库密钥、Microsoft Azure DevOps 中的环境变量/变量组、Kubernetes 密钥等。这些密钥通常可由有权执行此操作的人员(例如 GitHub 中的维护者、GitLab 中的项目所有者、Jenkins 中的管理员等)配置/查看,这共同构成了以下最佳实践:

  • 无“大密钥”:确保 CI/CD 工具中的密钥不是长期存在的,没有广泛的影响范围,并且没有高价值。此外,限制共享密钥(例如,切勿为所有管理员用户设置一个密码)。
  • 现状/待办:清楚地了解哪些用户可以查看或更改密钥。通常,GitLab/GitHub 项目的维护者可以查看或以其他方式提取其密钥。
  • 减少可以对项目执行管理任务的人员数量,以限制暴露。
  • 日志和警报:收集 CI/CD 工具的所有日志,并制定规则以检测密钥提取或滥用,无论是通过 Web 界面访问它们,还是通过双重 base64 编码或使用 OpenSSL 加密它们时转储它们。
  • 轮换:定期轮换密钥。
  • 分叉不应泄露:验证存储库的分叉或作业定义的副本不会复制密钥。
  • 文档:确保记录您作为 CI/CD 工具一部分存储的密钥以及原因,以便在需要时轻松迁移这些密钥。

3.2.2 存储在密钥管理系统中

当然,您可以将密钥存储在指定的密钥管理解决方案中。例如,您可以使用您的(云)基础设施提供商提供的解决方案,例如 AWS Secrets ManagerGoogle Secrets ManagerAzure KeyVault。您可以在本速查表的 第 4 节 中找到有关这些内容的更多信息。另一个选项是专用密钥管理系统,例如 Hashicorp VaultKeeperConjur。以下是 CI/CD 与这些系统交互的一些注意事项。请确保以下事项已得到处理:

  • 轮换/临时性:CI/CD 工具用于向密钥管理系统进行身份验证的凭据应频繁轮换,并在作业完成后过期。
  • 授权范围:CI/CD 工具使用的凭据(例如角色、用户等)的范围,仅授权 CI/CD 工具执行其作业所需的那些密钥和密钥管理服务。
  • 调用者的归属:CI/CD 工具使用的凭据仍然保留调用密钥管理解决方案的归属。确保您可以将 CI/CD 工具进行的任何调用归因于请求 CI/CD 工具操作的个人或服务。如果通过密钥管理器的默认配置无法实现,请确保您在请求参数方面具有关联设置。
  • 以上所有:仍遵循 3.2.1 节中列出的注意事项:日志和警报、处理分叉等。
  • 备份:将产品关键操作的密钥备份到单独的存储(例如冷存储),尤其是加密密钥。

3.2.3 完全不被 CI/CD 触及

密钥不一定需要通过 CI/CD 管道提供给密钥的消费者。当密钥的消费者检索密钥时甚至更好。在这种情况下,CI/CD 管道仍然需要指示编排系统(例如 Kubernetes)它需要使用给定服务账户安排特定服务,然后消费者可以使用该服务账户检索所需的密钥。然后,CI/CD 工具仍然拥有编排平台的凭据,但不再拥有对密钥本身的访问权限。关于这些凭据类型的注意事项与 3.2.2 节中描述的类似。

3.3 CI/CD 工具的身份验证和授权

CI/CD 工具应拥有指定的服务帐户,这些帐户只能在所需密钥或密钥消费者编排的范围内操作。此外,CI/CD 管道运行应易于归因于定义作业或触发作业的人员,以检测谁试图窃取或操纵密钥。当您使用基于证书的身份验证时,管道调用者的身份应包含在证书中。如果您使用令牌向所述系统进行身份验证,请确保您设置了请求这些操作的主体(例如用户或作业创建者)。

定期验证您的系统是否(仍然)是这种情况,以便您可以有效地进行日志记录、归因和针对可疑操作的安全警报。

3.4 日志和记账

攻击者可以使用 CI/CD 工具提取密钥。例如,他们可以使用管理界面或作业创建,通过加密或双重 base64 编码来窃取密钥。因此,您应该记录 CI/CD 工具中的每个操作。您应该在管道工具及其管理界面的每次非标准操作时定义安全警报规则,以监控密钥使用情况。日志应至少可查询 90 天,并长期存储在冷存储中。安全团队可能需要时间来了解攻击者如何使用 CI/CD 工具窃取或操纵密钥。

3.5 轮换 vs 动态创建

您可以利用 CI/CD 工具来轮换密钥或指示其他组件进行密钥轮换。例如,CI/CD 工具可以请求密钥管理系统或另一个应用程序轮换密钥。或者,CI/CD 工具或另一个组件可以设置动态密钥:消费者在生存期内需要使用的密钥。当消费者不再生存时,密钥将失效。此过程减少了密钥泄露的可能性,并允许轻松检测滥用。如果攻击者从消费者 IP 以外的任何地方使用密钥,您可以轻松检测到。

3.6 管道创建的密钥

您可以使用管道工具生成密钥,并将其直接提供给工具部署的服务,或将密钥提供给密钥管理解决方案。或者,密钥可以加密存储在 git 中,以便密钥及其元数据尽可能靠近开发人员的日常工作场所。git 存储的密钥确实要求开发人员不能自行解密密钥,并且密钥的每个消费者都拥有其加密的密钥变体。例如:密钥应该在每个 DTAP 环境中都不同,并用另一个密钥进行加密。对于每个环境,只有该环境中指定的消费者才能解密特定密钥。密钥不会跨环境泄露,并且仍然可以轻松地存储在代码旁边。密钥的消费者现在可以使用边车解密密钥,如 5.2 节所述。消费者将利用边车而不是检索密钥来解密密钥。

当管道自行创建密钥时,请确保所涉及的脚本或二进制文件遵守密钥生成的最佳实践。最佳实践包括安全随机性、密钥创建的适当长度等,并且密钥是根据存储在 git 或其他地方的明确定义的元数据创建的。

4 云提供商

对于云提供商,至少有四个重要主题需要探讨:

  • 指定的密钥存储/管理解决方案。您使用哪些服务?
  • 信封加密和客户端加密
  • 身份和访问管理:减少爆炸半径
  • API 配额或服务限制

4.1 要使用的服务

在任何环境中最好使用指定的密钥管理解决方案。大多数云提供商至少提供一项密钥管理服务。当然,也可以在云中的计算资源上运行不同的密钥管理解决方案(例如 HashiCorp Vault 或 Conjur)。本节我们将讨论云提供商的服务产品。

有时可以自动轮换您的密钥,无论是通过云提供商提供的服务还是(自定义构建的)功能。通常,您应该首选云提供商的解决方案,因为入门门槛和配置错误的风险较低。如果您使用自定义解决方案,请确保该功能的角色仅能由该功能承担,以执行其轮换。

4.1.1 AWS

对于 AWS,推荐的解决方案是 AWS Secret Manager

权限在密钥级别授予。请查阅 Secrets Manager 最佳实践

也可以使用 Systems Manager Parameter Store,它更便宜,但有几个缺点:

  • 您需要确保自己指定了加密(Secrets Manager 默认这样做)
  • 它提供的自动轮换功能较少(您可能需要构建自定义功能)
  • 它不支持跨账户访问
  • 它不支持跨区域复制
  • 可用的 安全中心控件 较少
4.1.1.1 AWS Nitro Enclaves

借助 AWS Nitro Enclaves,您可以创建受信任的执行环境。因此,一旦应用程序运行,就无法进行任何基于人工的访问。此外,飞地不附带任何永久存储。因此,存储在 Nitro Enclaves 上的密钥和其他敏感数据具有额外的安全层。

4.1.1.2 AWS CloudHSM

对于在高度机密应用程序中使用的密钥,可能需要对这些密钥的加密和存储进行更多控制。AWS 提供 CloudHSM,允许您为 AWS 服务自带密钥 (BYOK)。因此,您将对密钥的创建、生命周期和持久性拥有更多控制。CloudHSM 允许自动扩展和备份您的数据。云服务提供商 Amazon 将无法访问存储在 Azure Dedicated HSM 中的密钥材料。

4.1.2 GCP

对于 GCP,推荐的服务是 Secret Manager

权限在密钥级别授予。

请查阅 Secret Manager 最佳实践

4.1.2.1 Google Cloud Confidential Computing

GCP 保密计算 允许在运行时加密数据。因此,应用程序代码和数据将保持机密、加密,并且无法被人工或工具访问。

4.1.3 Azure

对于 Azure,推荐的服务是 Key Vault

与其他云不同,权限是在 密钥保管库 级别授予的。这意味着不同工作负载和不同敏感级别的密钥应相应地放在单独的密钥保管库中。

请查阅 Key Vault 最佳实践

4.1.3.1 Azure Confidential Computing

借助 Azure Confidential Computing,您可以创建受信任的执行环境。因此,每个应用程序都将在加密的 enclave 中执行,该 enclave 可端到端地保护应用程序使用的数据和代码。此外,在 enclave 内部运行的任何应用程序都无法被任何工具或人工访问。

4.1.3.2 Azure 专用 HSM

对于在 Azure 环境中使用且需要特殊安全考虑的密钥,Azure 提供 Azure Dedicated HSM。这使您可以更好地控制存储在其上的密钥,包括增强的管理和加密控制。云服务提供商 Microsoft 将无法访问存储在 Azure Dedicated HSM 中的密钥材料。

4.1.4 其他云、多云和云无关

如果您使用多个云提供商,您应该考虑使用与云无关的密钥管理解决方案。这将允许您在所有云提供商(以及可能在本地)上使用相同的密钥管理解决方案。另一个优点是,这避免了与特定云提供商的供应商锁定,因为该解决方案可以在任何云提供商上使用。

有开源和商业解决方案可用。一些例子包括:

4.2 信封加密和客户端加密

本节将介绍密钥如何加密以及如何在云中管理该加密的密钥。

4.2.1 客户端加密与服务器端加密

密钥的服务器端加密确保云提供商负责存储中密钥的加密。这样,密钥在静态时可免受泄露。静态加密通常除了选择用于加密的密钥(参见 4.2.2 节)之外,不需要额外的工作。但是:当您将密钥提交给其他服务时,它将不再加密。它在与目标服务或人工用户共享之前被解密。

密钥的客户端加密确保密钥保持加密状态,直到您主动解密它。这意味着只有当它到达消费者时才会被解密。您需要一个合适的加密系统来满足这一点。考虑使用安全配置的 PGP 等机制以及其他更具可扩展性和相对易于使用的系统。客户端加密可以提供密钥的端到端加密:从生产者到消费者。

4.2.2 自带密钥与云提供商密钥

当您加密静态密钥时,问题是:您想使用哪个密钥?您对云提供商的信任度越低,您就会越想自行管理。

通常,您可以选择使用密钥管理服务管理的密钥来加密密钥,或者使用云提供商的密钥管理解决方案来加密密钥。通过云提供商的密钥管理解决方案提供的密钥可以由云提供商管理,也可以由您自己管理。行业标准将后者称为“自带密钥”(BYOK)。您可以直接导入或在密钥管理解决方案中生成此密钥,或者使用云提供商支持的云 HSM。然后,您可以使用自己的密钥或提供商的客户主密钥来加密密钥管理解决方案的数据密钥。数据密钥反过来加密密钥。通过管理 CMK,您可以控制密钥管理解决方案中的数据密钥。

虽然通常所有提供商都可以导入您自己的密钥材料(AWSAzureGCP),但除非您知道自己在做什么并且您的威胁模型和策略要求这样做,否则由于其复杂性和使用难度,这不是推荐的解决方案。

4.3 身份和访问管理 (IAM)

IAM 适用于本地和云设置:为了有效管理密钥,您需要设置合适的访问策略和角色。这不仅仅涉及密钥策略;它还应包括强化整个 IAM 设置,否则可能会导致权限提升攻击。确保您绝不允许开放的“传递角色”权限或不受限制的 IAM 创建权限,因为这些权限可能会使用或创建可访问密钥的凭据。接下来,确保您严格控制谁可以模拟服务账户:您的机器角色是否可以被利用服务器的攻击者访问?数据管道工具的服务角色可以轻松访问密钥吗?确保您的威胁模型中包含每个云组件的 IAM(例如,问自己:您如何使用此组件进行权限提升?)。有关带示例的多个注意事项,请参阅 这篇博客文章

有效利用 IAM 主体的临时性:例如,确保只有特定角色和服务帐户在需要时才能访问密钥。监控这些帐户,以便您可以识别谁或什么使用了它们来访问密钥。

其次,请确保您对密钥的访问范围进行限制:不应允许任何人随意访问所有密钥。在 GCP 和 AWS 中,您可以创建细粒度的访问策略,以确保主体不能一次性访问所有密钥。在 Azure 中,拥有密钥保管库的访问权限意味着拥有该密钥保管库中所有密钥的访问权限。因此,在 Azure 上工作时,拥有单独的密钥保管库以隔离访问至关重要。

4.4 API 限制

云服务通常可以在给定时间内提供有限的 API 调用量。当您达到这些限制时,您可能会(D)DoS 自己。这些限制大多数适用于每个帐户、项目或订阅,因此请相应地分散工作负载以限制您的爆炸半径。此外,某些服务可能支持数据密钥缓存,从而防止密钥管理服务 API 上的负载(例如,请参阅 AWS 数据密钥缓存)。某些服务可以利用内置的数据密钥缓存。S3 就是一个这样的例子

5 容器和编排器

您可以通过多种方式丰富容器中的密钥:构建时(不推荐)以及在编排/部署期间。

5.1 密钥注入(文件、内存)

有三种方法可以将密钥获取到 Docker 容器内的应用程序中。

  • 挂载卷(文件):使用此方法,我们将密钥保存在特定的配置文件/密钥文件中,并将其作为挂载卷挂载到我们的实例中。确保这些挂载由编排器挂载,而不是内置的,因为这会随着容器定义泄露密钥。相反,请确保编排器在需要时挂载卷。
  • 从密钥存储中获取(内存中):边车应用程序/容器直接从密钥管理器服务获取其所需的密钥,而无需处理 Docker 配置。此解决方案允许您使用动态构建的密钥,而无需担心密钥可从文件系统或通过检查 Docker 容器的环境变量中查看。
  • 环境变量:我们可以直接将密钥作为 Docker 容器配置的一部分提供。注意:密钥本身绝不应使用 Docker ENV 或 Docker ARG 命令硬编码,因为这些命令很容易随容器定义泄露。请参阅 WrongSecrets 上的 Docker 挑战。相反,让编排器用实际密钥覆盖环境变量,并确保这不是硬编码的。此外,环境变量通常可供所有进程访问,并可能包含在日志或系统转储中。因此,除非其他方法不可行,否则不建议使用环境变量。

5.2 短生命周期边车容器

为了注入密钥,您可以创建短生命周期的边车容器,这些容器从远程端点获取密钥,然后将它们存储在挂载到原始容器的共享卷上。原始容器现在可以从挂载卷中使用密钥。使用这种方法的好处是,我们不需要集成任何第三方工具或代码来获取密钥。一旦边车获取了密钥,它就会终止。这方面的例子包括 Vault Agent Sidecar InjectorConjur Secrets Provider。通过将密钥挂载到与 Pod 共享的卷,Pod 内的容器可以在不知道密钥管理器的情况下使用密钥。

5.3 内部访问与外部访问

您应该只将密钥暴露给容器与部署表示(例如 Kubernetes Pod)之间的通信机制。切勿通过部署或编排器之间共享的外部访问机制(例如共享卷)暴露密钥。

当编排器存储密钥(例如 Kubernetes Secrets)时,请确保编排器的存储后端已加密且密钥管理良好。有关更多信息,请参阅 Kubernetes 安全速查表

6 实施指南

在本节中,我们将讨论实施。请注意,最好始终参考所选密钥管理系统的官方文档以进行实际实施,因为它将比任何辅助文档(如本速查表)更及时。

6.1 密钥材料管理策略

密钥材料管理在 密钥管理速查表 中讨论。

6.2 动态与静态用例

我们看到了动态密钥的以下用例,其中包括:

  • 用于辅助服务的短生命周期密钥(例如凭据或 API 密钥),表示将主服务(例如消费者)连接到服务的意图。
  • 用于保护和加密内存中和运行时通信过程的短生命周期完整性和加密控制。考虑只需在单个会话或单个部署生命周期内存在的加密密钥。
  • 在服务部署期间用于与部署者和支持基础设施交互的短生命周期凭据,以构建堆栈。

请注意,这些动态密钥通常需要与我们所需连接的服务一起创建。为了创建这些类型的动态密钥,我们通常需要长期静态密钥来创建动态密钥本身。其他静态用例:

  • 由于在与同一服务的其他实例交互中的使用性质,需要比单个部署更长生命周期的密钥材料(例如存储加密密钥、TLS PKI 密钥)
  • 连接到不支持创建临时角色或凭据的服务的密钥材料或凭据。

6.3 确保限制到位

密钥绝不应该被任何人、任何事物检索。始终确保您设置了防护措施:

  • 您是否有机会创建访问策略?确保有策略限制可以读取或写入密钥的实体数量。同时,编写策略时要易于扩展,并且不至于太复杂而难以理解。
  • 是否无法在密钥管理解决方案中减少对某些密钥的访问?考虑通过拥有独立的密钥管理解决方案来分离生产和开发密钥。然后,减少对生产密钥管理解决方案的访问。

6.4 安全事件监控是关键

持续监控谁/什么、来自哪个 IP 以及以何种方式访问密钥。有各种需要注意的模式,例如但不限于:

  • 监控谁在密钥管理系统访问密钥:这是否是正常行为?如果 CI/CD 凭据从与 CI/CD 系统运行位置不同的 IP 访问密钥管理解决方案,则提供安全警报并假定密钥已泄露。
  • 监控需要密钥的服务(如果可能),例如,密钥用户是否来自预期的 IP,是否带有预期的用户代理。如果不是,则发出警报并假定密钥已泄露。

6.5 可用性

确保您的密钥管理解决方案易于使用,因为您不希望人们因复杂性而绕过它或无效地使用它。这种可用性要求:

  • 新密钥的轻松入职和失效密钥的轻松移除。
  • 与现有软件的轻松集成:应用程序作为密钥管理系统的消费者应该易于集成。例如,应该提供 SDK 或简单的边车容器来与密钥管理系统通信,以便现有软件解耦并且不需要大量修改。您可以在 AWS、Google 和 Azure SDK 中找到示例。这些 SDK 允许应用程序与各自的密钥管理解决方案进行交互。您可以在 HashiCorp Vault 软件集成和 Vault Agent Sidecar Injector,以及 Conjur 集成和 Conjur Secrets Provider 中找到类似的示例。
  • 清晰理解密钥管理的组织结构及其流程至关重要。

7 加密

密钥管理与加密密不可分。毕竟,密钥必须加密存储在某处,以保护其机密性和完整性。

7.1 要使用的加密类型

您可以使用各种加密类型来保护密钥,只要它们提供足够的安全性,包括对基于量子计算的攻击的足够抵抗力。鉴于这是一个不断发展的领域,最好查阅 keylength.com 等来源,其中列出了关于现有标准加密类型和密钥长度使用的最新建议,以及 NSA 的 商业国家安全算法套件 2.0,其中列出了抗量子算法。

请注意,在所有情况下,我们都必须优选选择一种同时提供加密和机密性的算法,例如使用 GCM (伽罗瓦/计数器模式) 的 AES-256,或根据该领域的最佳实践混合使用 ChaCha20 和 Poly1305。

7.2 会聚加密

会聚加密 确保给定的明文及其密钥产生相同的密文。这有助于检测密钥的可能重用,从而产生相同的密文。启用会聚加密的挑战在于它允许攻击者使用系统生成一组可能导致相同密钥的加密字符串,从而允许攻击者推导明文密钥。考虑到算法和密钥,如果所使用的会聚加密系统在加密过程中具有足够的资源挑战,则可以减轻此风险。另一个有助于降低风险的因素是确保密钥具有足够的长度,从而进一步阻碍所需的猜测迭代时间。

7.3 加密密钥存储在哪里?

您不应将密钥存储在它们加密的密钥旁边,除非这些密钥本身已加密(请参阅信封加密)。首先查阅 密钥管理速查表,了解加密和可能的 HMAC 密钥的存储位置和方式。

7.4 加密即服务 (EaaS)

EaaS 是一种模式,用户订阅基于云的加密服务,而无需在自己的系统上安装加密。使用 EaaS,您可以获得以下好处:

  • 静态加密
  • 传输中加密 (TLS)
  • 密钥处理和加密实现由加密服务负责,而不是由开发人员负责
  • 提供商可以添加更多服务来与敏感数据交互

8 检测

密钥检测有许多方法,并且有一些非常有用的开源项目可以帮助实现这一点。Yelp Detect Secrets 项目已经成熟,并具有大约 20 种密钥的签名匹配功能。有关其他检测工具的更多信息,请查阅 GitHub 上的 Secrets Detection 主题。

8.1 通用检测方法

“左移”和 DevSecOps 原则也适用于密钥检测。以下这些通用方法旨在更早地考虑密钥并随着时间的推移发展实践。

  • 创建标准测试密钥并在整个组织中普遍使用。这样可以减少误报,因为只需跟踪每种密钥类型的一个测试密钥。
  • 考虑在开发人员级别启用密钥检测,以避免在提交/PR 之前将密钥签入代码,无论是通过 IDE、作为测试驱动开发的一部分,还是通过预提交钩子。
  • 将密钥检测纳入威胁模型的一部分。在威胁建模练习中将密钥视为攻击面的一部分。
  • 经常评估检测实用程序和相关签名,以确保它们符合预期。
  • 考虑使用不止一个检测实用程序并关联/去重结果,以识别潜在的检测弱点区域。
  • 探索熵和易于检测之间的平衡。格式一致的密钥更容易检测,误报率更低,但您也不希望仅仅因为人类创建的密码不符合您的检测规则而错过它。

8.2 待检测的密钥类型

存在许多类型的密钥,您应该为每种类型考虑签名,以确保所有类型的准确检测。其中更常见的类型包括:

  • 高可用性密钥(难以轮换的令牌)
  • 应用程序配置文件
  • 连接字符串
  • API 密钥
  • 凭据
  • 密码
  • 2FA 密钥
  • 私钥(例如,SSH 密钥)
  • 会话令牌
  • 平台特定密钥类型(例如,Amazon Web Services、Google Cloud)

要了解更多关于密钥的有趣知识并练习查找它们,请查看 Wrong Secrets 项目。

8.3 检测生命周期

密钥就像任何其他授权令牌一样。它们应该:

  • 只在必要时存在(经常轮换)
  • 具有自动轮换的方法
  • 只对需要它们的人可见(最小权限)
  • 可撤销(包括记录尝试使用已撤销密钥的尝试)
  • 绝不记录(必须实施加密或掩码方法以避免记录明文密钥)

为密钥生命周期的每个阶段创建检测规则。

8.4 密钥检测方法文档

创建并定期更新文档,以告知开发人员社区有关贵组织可用的程序和系统,以及您期望的密钥管理类型、如何测试密钥以及在检测到密钥时该怎么做。

文档应:

  • 存在并经常更新,尤其是在事件发生后
  • 包含以下信息:

    • 谁有权访问密钥
    • 如何进行轮换
    • 任何在密钥轮换期间可能被破坏的上游或下游依赖项
    • 事故发生时的联系人
    • 泄露带来的安全影响
  • 根据威胁风险、数据分类等因素,确定何时可能以不同方式处理密钥。

9 应急响应

在密钥泄露事件中快速响应,可能是密钥管理中最关键的考虑因素之一。

9.1 文档

密钥泄露事件的应急响应应确保保管链中的每个人都知情并了解如何响应。这包括应用程序创建者(开发团队的每个成员)、信息安全人员和技术领导层。

文档必须包括

  • 如何测试密钥和密钥处理,特别是在业务连续性审查期间。
  • 检测到密钥时应通知谁。
  • 采取的遏制措施
  • 事件期间要记录的信息

9.2 补救

应急响应的首要目标是快速响应和遏制。

遏制应遵循以下步骤

  1. 撤销:已泄露的密钥应立即撤销。密钥必须能够快速解除授权,并且必须有系统来识别撤销状态。
  2. 轮换:必须能够快速创建和实施新密钥,最好通过自动化流程进行,以确保可重复性、较低的实施错误率和最小权限(非直接人可读)。
  3. 删除:已撤销/轮换的密钥必须立即从受影响的系统中移除,包括在代码或日志中发现的密钥。代码中的密钥可以将暴露的提交历史压缩到密钥引入之前,但是这可能会引入其他问题,因为它会重写 Git 历史并破坏到给定提交的任何其他链接。如果您决定这样做,请注意后果并相应地计划。日志中的密钥必须有在保持日志完整性的同时移除密钥的流程。
  4. 日志记录:应急响应团队必须能够访问有关密钥生命周期的信息,以帮助遏制和补救,包括
    • 谁有权限访问?
    • 他们何时使用过?
    • 上次轮换是什么时候?

9.3 日志记录

密钥使用日志记录的其他考虑因素应包括

  • 应急响应日志应存储在应急响应(IR)团队可访问的单一位置
  • 确保在“紫队”演习期间日志信息的准确性,例如:
    • 应该记录什么?
    • 实际记录了什么?
    • 我们是否有足够的警报机制来确保这一点?

考虑使用标准化的日志格式和词汇表,例如日志词汇表速查表,以确保所有必要信息都被记录。

10 多云环境中的密钥管理

10.1 引言

在多云环境中管理密钥面临独特的挑战,因为云提供商及其各自的服务具有多样性。本节讨论了跨多个云提供商管理密钥的挑战和最佳实践。

10.2 挑战

  1. 多样化的 API 和接口:每个云提供商都有其自己的用于管理密钥的 API 和接口,这可能导致跨多个提供商集成和管理密钥的复杂性。
  2. 不一致的安全策略:不同的云提供商可能具有不同的安全策略和实践,这使得在所有环境中强制执行一致的安全标准变得具有挑战性。
  3. 密钥轮换:确保密钥在多个云提供商之间一致且安全地轮换可能很困难,特别是如果每个提供商都有不同的密钥轮换机制。
  4. 访问控制:管理多个云提供商之间的密钥访问控制可能很复杂,因为每个提供商可能具有不同的访问控制机制和策略。
  5. 审计和监控:由于日志记录和监控功能上的差异,确保对多个云提供商之间的密钥访问和使用进行全面的审计和监控可能具有挑战性。

10.3 最佳实践

  1. 使用集中式密钥管理解决方案:实施一个可以与多个云提供商集成的集中式密钥管理解决方案。这有助于标准化密钥管理并在所有环境中强制执行一致的安全策略。示例包括 HashiCorp Vault 和 CyberArk Conjur。
  2. 标准化安全策略:定义并强制执行所有云提供商之间密钥管理的标准化安全策略。这包括密钥轮换、访问控制和审计策略。
  3. 自动化密钥轮换:实施自动化密钥轮换流程,以确保密钥在所有云提供商之间一致且安全地轮换。使用工具和脚本自动化轮换过程,并降低人为错误的风险。
  4. 实施细粒度访问控制:使用细粒度访问控制机制,根据最小权限原则限制对密钥的访问。确保访问控制策略在所有云提供商之间得到一致执行。
  5. 启用全面审计和监控:对所有云提供商之间的密钥访问和使用实施全面审计和监控。使用集中式日志记录和监控解决方案来聚合和分析来自多个提供商的日志。

10.4 参考资料