跳到内容

微服务安全备忘录

简介

微服务架构正日益广泛地用于设计和实现基于云和本地基础设施中的应用程序系统、大规模应用程序和服务。在应用程序设计和实现阶段,有许多安全挑战需要解决。在设计阶段必须解决的基本安全要求是认证和授权。因此,对于应用程序安全架构师来说,理解并正确使用现有架构模式在基于微服务的系统中实现认证和授权至关重要。本备忘录的目标是识别这些模式,并为应用程序安全架构师提供如何使用它们的建议。

边缘层授权

在简单场景中,授权可以仅发生在边缘层(API 网关)。API 网关可用于集中强制执行所有下游微服务的授权,从而无需为每个独立服务提供认证和访问控制。在这种情况下,NIST 建议实施缓解措施,例如相互认证,以防止对内部服务(API 网关绕过)的直接匿名连接。需要注意的是,边缘层的授权具有以下限制

  • 在具有许多角色和访问控制规则的复杂生态系统中,将所有授权决策都推送到 API 网关会很快变得难以管理。
  • API 网关可能成为单一决策点,这可能违反“纵深防御”原则。
  • 运维团队通常拥有 API 网关,因此开发团队无法直接进行授权更改,由于额外的沟通和流程开销,这会降低开发速度。

在大多数情况下,开发团队在两个地方实现授权——在边缘层进行粗粒度授权,并在服务层进行。为了认证外部实体,边缘可以使用通过 HTTP 头部(例如“Cookie”或“Authorization”)传输的访问令牌(引用令牌或自包含令牌)或使用 mTLS。

服务层授权

服务层授权使每个微服务能够更好地控制访问控制策略的强制执行。为了进一步讨论,我们将使用符合 NIST SP 800-162 的术语和定义。访问控制系统的功能组件可以分类如下

  • 策略管理点(PAP):提供用于创建、管理、测试和调试访问控制规则的用户界面。
  • 策略决策点(PDP):通过评估适用的访问控制策略来计算访问决策。
  • 策略执行点(PEP):根据主体请求访问受保护对象的请求,强制执行策略决策。
  • 策略信息点(PIP):作为属性的检索源或策略评估所需的数据源,为 PDP 做出决策提供所需信息。

NIST ABAC framework

服务层授权:现有模式

去中心化模式

开发团队直接在微服务代码层面实现 PDP 和 PEP。所有需要实现该规则的访问控制规则和属性都在每个微服务上定义和存储(步骤 1)。当微服务收到请求以及一些授权元数据(例如,最终用户上下文或请求的资源 ID)时,微服务分析它(步骤 3)以生成访问控制策略决策,然后强制执行授权(步骤 4)。 去中心化模式高层设计

现有的编程语言框架允许开发团队在微服务层实现授权。例如,Spring Security 允许开发者在资源服务器中启用范围检查(例如,使用从传入 JWT 中提取的范围),并用它来强制执行授权。

在源代码级别实现授权意味着每当开发团队想要修改授权逻辑时,都必须更新代码。

具有单一策略决策点的集中化模式

在此模式中,访问控制规则集中定义、存储和评估。访问控制规则使用 PAP 定义(步骤 1),并连同评估这些规则所需的属性一起传递给集中式 PDP(步骤 2)。当一个主体调用微服务端点(步骤 3)时,微服务代码通过网络调用调用集中式 PDP,PDP 通过根据访问控制规则和属性评估查询输入来生成访问控制策略决策(步骤 4)。根据 PDP 的决策,微服务强制执行授权(步骤 5)。

Centralized pattern with single policy decision point HLD

为了定义访问控制规则,开发/运维团队必须使用某种语言或符号。例如可扩展访问控制标记语言(XACML)和下一代访问控制(NGAC),它们是描述策略规则的标准。

此模式可能由于对远程 PDP 端点的额外网络调用而导致延迟问题,但可以通过在微服务级别缓存授权策略决策来缓解。需要指出的是,PDP 必须以高可用性模式运行,以防止弹性和可用性问题。应用程序安全架构师应将其与其他模式(例如,API 网关级别的授权)结合使用,以强制执行“纵深防御”原则。

具有嵌入式策略决策点的集中化模式

在此模式中,访问控制规则集中定义,但在微服务级别存储和评估。访问控制规则使用 PAP 定义(步骤 1),并连同评估这些规则所需的属性一起传递给嵌入式 PDP(步骤 2)。当一个主体调用微服务端点(步骤 3)时,微服务代码调用 PDP,PDP 通过根据访问控制规则和属性评估查询输入来生成访问控制策略决策(步骤 4)。根据 PDP 的决策,微服务强制执行授权(步骤 5)。

Centralized pattern with embedded policy decision point HLD

在这种情况下,PDP 代码可以作为微服务内置库或服务网格架构中的 Sidecar 实现。考虑到可能的网络/主机故障和网络延迟,建议将嵌入式 PDP 作为微服务库或 Sidecar 部署在与微服务相同的主机上。嵌入式 PDP 通常将授权策略和策略相关数据存储在内存中,以最大程度地减少授权强制执行过程中的外部依赖并获得低延迟。与“具有单一策略决策点的集中化模式”方法的主要区别在于,授权决策不存储在微服务端,而是将最新授权策略存储在微服务端。需要指出的是,缓存授权决策可能导致应用过时的授权规则和违反访问控制。

Netflix 展示了 (链接, 链接) 一个使用“具有嵌入式 PDP 的集中化模式”在微服务层面实现授权的真实案例。

Centralized pattern with embedded policy decision point HLD

  • 策略门户和策略存储库是用于创建、管理和版本化访问控制规则的基于用户界面的系统。
  • 聚合器从所有外部源获取访问控制规则中使用的数据并保持其最新。
  • 分发器从策略存储库中拉取访问控制规则,并从聚合器中拉取访问控制规则中使用的数据,然后将它们分发给各个 PDP。
  • PDP(库)异步拉取访问控制规则和数据,并保持其最新,以由 PEP 组件强制执行授权。

授权实施建议

  1. 为了实现可伸缩性,不建议在源代码中硬编码授权策略(去中心化模式),而应使用专门的语言来表达策略。目标是将授权从代码中外部化/解耦,而不仅仅是让网关/代理充当检查点。由于其弹性和广泛采用,服务层授权的推荐模式是“具有嵌入式 PDP 的集中化模式”。
  2. 授权解决方案应是平台级解决方案;一个专门的团队(例如,平台安全团队)必须负责授权解决方案的开发和运营,以及在开发团队之间共享实现授权的微服务蓝图/库/组件。
  3. 授权解决方案应基于广泛使用的解决方案,因为实施自定义解决方案具有以下缺点
    • 安全或工程团队必须构建和维护一个自定义解决方案。
    • 有必要为系统架构中使用的每种语言构建和维护客户端库 SDK。
    • 有必要对每个开发人员进行自定义授权服务 API 和集成的培训,并且没有开源社区可以获取信息。
  4. 并非所有访问控制策略都能由网关/代理和共享授权库/组件强制执行,因此某些特定的访问控制规则仍必须在微服务业务代码层面实现。为此,建议微服务开发团队使用简单的问卷/检查表来发现此类安全要求,并在微服务开发过程中妥善处理它们。
  5. 建议实施“纵深防御”原则并在以下方面强制执行授权:
    • 网关和代理层,粗粒度级别。
    • 微服务层,使用共享授权库/组件来强制执行细粒度决策。
    • 微服务业务代码层,以实现业务特定的访问控制规则。
  6. 必须在访问控制策略的开发、批准和推出方面实施正式程序。

外部实体身份传播

为了在微服务级别做出细粒度授权决策,微服务必须理解调用者的上下文(例如,用户 ID、用户角色/组)。为了允许内部服务层强制执行授权,边缘层必须将已认证的外部实体身份(例如,最终用户上下文)连同请求一起传播到下游微服务。传播外部实体身份的最简单方法之一是重用边缘接收到的访问令牌并将其传递给内部微服务。然而,需要指出的是,这种方法由于可能导致外部访问令牌泄露而高度不安全,并且可能增加攻击面,因为通信依赖于专有的基于令牌的系统实现。如果内部服务意外暴露给外部网络,则可以使用泄露的访问令牌直接访问它。如果内部服务只接受内部服务已知的令牌格式,则这种攻击是不可能的。此模式也不是对外部访问令牌无感知的,即内部服务必须理解外部访问令牌并支持各种认证技术以从不同类型的外部令牌(例如 JWT、cookie、OpenID Connect 令牌)中提取身份。

身份传播:现有模式

以明文或自签名数据结构发送外部实体身份

在这种方法中,微服务从传入请求中提取外部实体身份(例如,通过解析传入的访问令牌),创建包含该上下文的数据结构(例如 JSON 或自签名 JWT),并将其传递给内部微服务。在此场景中,接收方微服务必须信任调用方微服务。如果调用方微服务想要违反访问控制规则,它可以通过在 HTTP 头部设置任何它想要的用户/客户端 ID 或用户角色来实现。这种方法仅适用于高度信任的环境,其中每个微服务都由一个应用安全软件开发实践的受信任开发团队开发。

使用受信任颁发者签名的数据结构

在此模式中,外部请求经边缘层的认证服务认证后,由受信任的颁发者生成、签名或加密一个表示外部实体身份的数据结构(例如,包含用户 ID、用户角色/组或权限),并将其传播到内部微服务。 签名身份传播

Netflix 展示了一个使用该模式的真实案例:一个名为“Passport”的结构,它包含用户 ID 及其属性,并在边缘层对每个传入请求进行 HMAC 保护。此结构传播到内部微服务,绝不向外部暴露。

  1. 边缘认证服务(EAS)从密钥管理系统获取密钥。
  2. EAS 从传入请求接收访问令牌(例如,在 cookie、JWT、OAuth2 令牌中)。
  3. EAS 解密访问令牌,解析外部实体身份,并以签名的“Passport”结构将其发送到内部服务。
  4. 内部服务可以使用包装器提取用户身份以强制执行授权(例如,实现基于身份的授权)。
  5. 如有必要,内部服务可以将“Passport”结构传播到调用链中的下游服务。

Netflix 身份传播方法 值得一提的是,该模式与外部访问令牌无关,并允许将外部实体与其内部表示解耦。

身份传播实施建议

  1. 为了实现一个与外部访问令牌无关且可扩展的系统,请将为外部实体颁发的访问令牌与其内部表示解耦。使用单一数据结构来表示和传播微服务之间的外部实体身份。边缘层服务必须验证传入的外部访问令牌,颁发内部实体表示结构,并将其传播到下游服务。
  2. 使用由受信任颁发者签名(对称或非对称加密)的内部实体表示结构是社区推荐采用的模式。
  3. 内部实体表示结构应可扩展,以允许添加更多声明,这可能导致低延迟。
  4. 内部实体表示结构不得向外部暴露(例如,向浏览器或外部设备)

服务间认证

现有模式

相互传输层安全

通过 mTLS 方法,每个微服务除了实现传输数据的机密性和完整性之外,还可以合法地识别与其通信的对象。部署中的每个微服务都必须携带一对公钥/私钥,并使用该密钥对通过 mTLS 向接收方微服务进行认证。mTLS 通常通过自托管的公钥基础设施实现。使用 mTLS 的主要挑战是密钥配置和信任引导、证书吊销以及密钥轮换。

基于令牌

基于令牌的方法工作在应用层。令牌是一个容器,可能包含调用方 ID(微服务 ID)及其权限(作用域)。调用方微服务可以通过使用其服务 ID 和密码调用特殊的安全令牌服务来获取签名令牌,然后将其附加到每个传出请求中,例如通过 HTTP 头部。被调用微服务可以提取令牌并在线或离线验证它。 令牌验证

  1. 在线场景
    • 为了验证传入令牌,微服务通过网络调用集中式服务令牌服务。
    • 可以检测到被吊销(受损)的令牌。
    • 高延迟。
    • 应应用于关键请求。
  2. 离线场景
    • 为了验证传入令牌,微服务使用下载的服务令牌服务公钥。
    • 可能无法检测到被吊销(受损)的令牌。
    • 低延迟。
    • 应应用于非关键请求。在大多数情况下,基于令牌的认证通过 TLS 工作,这提供了传输中数据的机密性和完整性。

日志记录

基于微服务的系统中的日志服务旨在满足可追溯性和问责制原则,并帮助通过日志分析检测操作中的安全异常。因此,对于应用程序安全架构师来说,理解并充分利用现有架构模式在基于微服务的系统中实现审计日志记录以进行安全操作至关重要。下方图片展示了高层架构设计,它基于以下原则

  • 每个微服务使用标准输出(通过 stdout, stderr)将日志消息写入本地文件。
  • 日志代理定期拉取日志消息并将其发送(发布)到消息代理(例如 NATS, Apache Kafka)。
  • 中心日志服务订阅消息代理中的消息,接收并处理它们。 日志模式

日志子系统架构的高层建议及其基本原理如下所示。

  1. 微服务不应直接通过网络通信将日志消息发送到中心日志子系统。微服务应将其日志消息写入本地日志文件
    • 这有助于减轻因攻击导致的日志服务故障或合法微服务泛滥导致的日志服务故障而造成数据丢失的威胁
    • 在日志服务中断的情况下,微服务仍会将日志消息写入本地文件(不会丢失数据),日志服务恢复后,日志将可供传输;
  2. 应有一个独立于微服务的专用组件(日志代理)。日志代理应收集微服务上的日志数据(读取本地日志文件)并将其发送到中心日志子系统。由于可能存在的网络延迟问题,日志代理应与微服务部署在同一主机(虚拟或物理机)上
    • 这有助于减轻因攻击导致的日志服务故障或合法微服务泛滥导致的日志服务故障而造成数据丢失的威胁
    • 在日志代理故障的情况下,微服务仍将信息写入日志文件,日志代理恢复后将读取文件并将信息发送到消息代理;
  3. 为了防止对中心日志子系统可能发生的 DoS 攻击,日志代理不应使用异步请求/响应模式发送日志消息。应有一个消息代理来实现日志代理与中心日志服务之间的异步连接
    • 这有助于减轻因合法微服务泛滥导致的日志服务故障而造成数据丢失的威胁
    • 在日志服务中断的情况下,微服务仍会将日志消息写入本地文件(不会丢失数据),日志服务恢复后,日志将可供传输;
  4. 日志代理和消息代理应使用相互认证(例如,基于 TLS)来加密所有传输数据(日志消息)并进行自身认证
    • 这有助于缓解以下威胁:微服务欺骗、日志/传输系统欺骗、网络流量注入、嗅探网络流量
  5. 消息代理应强制执行访问控制策略,以减轻未经授权的访问并实现最小权限原则
    • 这有助于减轻微服务权限提升的威胁
  6. 日志代理应过滤/清理输出日志消息,以确保敏感数据(例如 PII、密码、API 密钥)绝不会发送到中心日志子系统(数据最小化原则)。有关应从日志记录中排除的项的全面概述,请参阅 OWASP 日志备忘录
  7. 微服务应生成一个关联 ID,该 ID 唯一标识每个调用链,并有助于对日志消息进行分组以便调查。日志代理应在每条日志消息中包含关联 ID。
  8. 日志代理应定期提供健康和状态数据,以指示其可用性或不可用性。
  9. 日志代理应以结构化日志格式(例如 JSON、CSV)发布日志消息。
  10. 日志代理应在日志消息中附加上下文数据,例如平台上下文(主机名、容器名称)、运行时上下文(类名、文件名)。

有关应记录的事件和可能的数据格式的全面概述,请参阅 OWASP 日志备忘录应用程序日志词汇表备忘录

参考资料