你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

通过反向代理公开 Azure Spring Apps

Azure Spring Apps
Azure 应用程序网关
Azure Front Door

Azure Spring Apps 中托管应用或微服务时,你并不总是希望将它们直接发布到 Internet。 你可能希望通过反向代理公开它们。 使用此方法,可将服务放置在应用的前面。 该服务可以定义跨领域的功能,例如 Web 应用程序防火墙 (WAF) 功能,以帮助保护应用和实现负载均衡、路由、请求筛选和速率限制。

在 Azure Spring Apps 的前面部署常用的反向代理服务(例如 Azure 应用程序网关Azure Front Door)时,请确保只能通过此反向代理访问你的应用。 此安全措施有助于防止恶意用户试图绕过 WAF 或规避限制。

Azure DDoS 防护与应用程序设计最佳做法相结合,提供增强的 DDoS 缓解功能来更全面地防御 DDoS 攻击。 应在任何外围虚拟网络上启用 Azure DDOS 防护。

本文介绍如何强制实施访问限制,以便只能通过反向代理服务访问 Azure Spring Apps 中托管的应用程序。 强制实施这些限制的建议做法取决于部署 Azure Spring Apps 实例的方式以及使用的反向代理。 根据是部署在虚拟网络内部还是外部,还会有一些不同的注意事项。 本文提供有关四种方案的信息。

  • 在虚拟网络中部署 Azure Spring Apps以及从网络内部以私密方式访问应用

    • 你可以控制运行应用的虚拟网络。 使用网络安全组 (NSG) 等本机 Azure 网络功能来锁定访问,以便仅允许从反向代理访问。

    • 可以使用 Azure 应用程序网关向 Internet 公开应用,然后应用相应的访问限制来锁定应用。 后文的方案 1 中介绍了此方法。

    • 不能直接使用 Azure Front Door,因为它无法访问专用虚拟网络中的 Azure Spring Apps 实例。 Azure Front Door 只能通过公共 IP 地址或者通过使用专用终结点的服务连接到后端。 如果 Azure Spring Apps 的多区域部署需要全局负载均衡,仍可以通过应用程序网关公开 Azure Spring Apps 实例。 若要实现此方案,请将 Azure Front Door 放置在应用程序网关前面。 后文的方案 2 中介绍了此方法。

  • 在虚拟网络外部部署 Azure Spring Apps 并将应用直接部署到 Internet(如果为应用分配了终结点)。

    • 你无法控制网络,且无法使用 NSG 来限制访问。 仅允许反向代理访问应用需要在 Azure Spring Apps 本身中使用某种方法。

    • 因为应用是可公开访问的,你可以使用应用程序网关或 Azure Front Door 作为反向代理。 后文的方案 3 中介绍了应用程序网关方法。 后文的方案 4 中介绍了 Azure Front Door 方法。

    • 可以根据需要结合使用这两种方法。 如果同时使用应用程序网关和 Azure Front Door,请在两个反向代理之间使用方案 2 中所用的相同访问限制。

注意

可以使用其他反向代理服务,而不是应用程序网关或 Azure Front Door。 对于位于 Azure 虚拟网络中的区域服务(例如 Azure API 管理),指导类似于适用于应用程序网关的指导。 如果使用非 Azure 服务,指导类似于适用于 Azure Front Door 的指导。

方案比较

下表简要比较了 Azure Spring Apps 的四种反向代理配置方案。 有关每种方案的完整详细信息,请参阅本文的相应部分。

方案 部署 服务 配置
1 在虚拟网络内 应用程序网关 - 对于要公开的每个应用,为其分配一个终结点并将相应的自定义域映射到该应用。
- 对于应用程序网关中的后端池,使用为每个应用分配的终结点。
- 在服务运行时子网中添加一个 NSG,它只允许来自应用程序网关子网、应用子网和 Azure 负载均衡器的流量。 阻止所有其他流量。
2 在虚拟网络内 将 Azure Front Door 和应用程序网关配合使用 - 使用方案 1 所述的相同方法限制应用程序网关与 Azure Spring Apps 之间的访问。
- 在应用程序网关子网上,创建一个仅允许具有 AzureFrontDoor.Backend 服务标记的流量的 NSG。
- 在应用程序网关中创建一个自定义 WAF 规则,用于验证 X-Azure-FDID HTTP 标头是否包含特定的 Azure Front Door 实例 ID。
3 虚拟网络之外 应用程序网关和 Spring Cloud 网关 - 使用 Spring Cloud 网关公开后端应用。 只有 Spring Cloud 网关应用需要分配终结点。 所有后端应用的自定义域应映射到这一个 Spring Cloud 网关应用。
- 对于应用程序网关中的后端池,使用为 Spring Cloud 网关应用分配的终结点。
- 在 Spring Cloud 网关中,将 XForwarded Remote Addr 路由谓词设置为应用程序网关的公共 IP 地址。
- 或者,在 Spring Framework 应用中,将 server.forward-headers-strategy 应用程序属性设置为 FRAMEWORK
4 虚拟网络之外 将 Azure Front Door 与 Spring Cloud 网关配合使用 - 使用 Spring Cloud 网关公开后端应用。 只有 Spring Cloud 网关应用需要分配终结点。 所有后端应用的自定义域应映射到这一个 Spring Cloud 网关应用。
- 对于 Azure Front Door 中的后端池或源,使用为 Spring Cloud 网关应用分配的终结点。
- 在 Spring Cloud 网关中,将 XForwarded Remote Addr 路由谓词设置为 Azure Front Door 的所有出站 IP 范围,并将此设置保持最新状态。 设置 Header 路由谓词以确保 X-Azure-FDID HTTP 标头包含你的唯一 Azure Front Door ID。
- 或者,在 Spring Framework 应用中,将 server.forward-headers-strategy 应用程序属性设置为 FRAMEWORK

注意

完成配置设置后,请考虑使用 Azure Policy资源锁来防止可能允许绕过反向代理并直接公开应用程序的意外或恶意更改。 此保护措施仅适用于 Azure 资源(特别是 NSG),因为 Azure Spring Apps 内部的配置对 Azure 控制平面不可见。

虚拟网络内的部署

在虚拟网络中部署 Azure Spring Apps 时,会使用两个子网

  • 包含相关网络资源的服务运行时子网
  • 托管代码的应用子网

因为服务运行时子网包含用于应用连接的负载均衡器,所以你可以在此服务运行时子网上定义一个仅允许来自反向代理的流量的 NSG。 阻止所有其他流量时,虚拟网络中的任何人都可以在不通过反向代理的情况下访问你的应用。

重要

限制为只能从反向代理进行子网访问可能会导致依赖于从客户端设备直接连接到应用的功能(例如日志流式传输)出现故障。 请考虑专门为这些客户端设备添加 NSG 规则,并且仅在需要特定的直接访问时才添加这些规则。

应该为要通过反向代理公开的每个应用分配一个终结点,从而让反向代理能在虚拟网络中访问该应用。 对于每个应用,还应该映射它使用的自定义域,以避免替代反向代理中的 HTTP Host 标头并使原始主机名保持不变。 该方法能避免 Cookie 损坏或重定向 URL 无法正常工作之类的问题。 有关详细信息,请参阅主机名保留

注意

或者可以遵循当 Azure Spring Apps 部署在虚拟网络外部时适用的指导(或者在除 NSG 之外还实施深层防御)。 该部分介绍访问限制通常是怎样通过使用 Spring Cloud 网关实现的(这也会影响后端应用,因为它们不再需要分配的终结点或自定义域)。

方案 1:使用应用程序网关作为反向代理

方案 1 介绍如何使用应用程序网关向 Internet 公开应用,然后应用相应的访问限制来锁定应用。

下图描绘了方案 1 的体系结构:

Diagram that shows the use of Azure Application Gateway with Azure Spring Apps in a virtual network.

下载此体系结构的 Visio 文件

当应用程序网关位于 Azure Spring Apps 实例前面时,使用为 Spring Cloud 网关应用分配的终结点作为后端池。 示例终结点为 myspringcloudservice-myapp.private.azuremicroservices.io。 终结点会解析为服务运行时子网中的专用 IP 地址。 因此,若要限制访问,可将 NSG 与以下入站安全规则(为“拒绝”规则指定最低优先级)一起放置在服务运行时子网上:

操作 源类型 源值 协议 目标端口范围
允许 IP 地址 应用程序网关子网的专用 IP 范围(例如 10.1.2.0/24)。 TCP 80, 443(或其他适用的端口)
允许 IP 地址 Azure Spring Apps 中应用子网的专用 IP 范围(例如 10.1.1.0/24)。 TCP *
允许 服务标记 AzureLoadBalancer Any *
拒绝 服务标记 Any Any *

方案 1 的配置可确保服务运行时子网仅允许来自以下源的流量:

  • 专用应用程序网关子网
  • 应用子网(需要在两个 Azure Spring Apps 子网之间进行双向通信。)
  • Azure 负载均衡器(这是常规的 Azure 平台要求)

将阻止所有其他流量。

方案 2:使用 Azure Front Door 和应用程序网关作为反向代理

如前所述,不能将 Azure Front Door 直接放在 Azure Spring Apps 的前面,因为它无法访问专用虚拟网络。 (Azure Front Door 标准版或高级版可以连接到虚拟网络中的专用终结点,但 Azure Spring Apps 目前不提供专用终结点支持。)如果你仍想使用 Azure Front Door,例如需要在不同 Azure 区域中的多个 Azure Spring Apps 实例之间进行全局负载均衡时,还是可以通过应用程序网关公开自己的应用。 若要实现此方案,请将 Azure Front Door 放置在应用程序网关前面。

下图描绘了方案 2 的体系结构:

Diagram that shows the use of Azure Front Door and Azure Application Gateway with Azure Spring Apps in a virtual network.

下载此体系结构的 Visio 文件

方案 2 的配置采用与方案 1 相同的方式在应用程序网关和 Azure Spring Apps 之间实现访问限制。 使用适当的规则,对服务运行时子网应用 NSG。

在方案 2 中,还必须确保应用程序网关仅接受来自 Azure Front Door 实例的流量。 Azure Front Door 文档解释了如何锁定对后端的访问以仅允许 Azure Front Door 流量。 当后端是应用程序网关时,可按如下所述实施此限制:

虚拟网络外部的部署

在虚拟网络外部部署 Azure Spring Apps 时不能使用本机 Azure 网络功能,因为你无法控制网络。 必须对应用本身应用所需的访问限制,以便仅允许来自反向代理的流量。 如果有许多应用,此方法可能会增大复杂性,并且存在不一定能正确配置每个应用的风险。

使用 Spring Cloud 网关公开应用并帮助保护应用

若要让各个应用程序的开发人员无需再承担访问控制的责任,可以使用 Spring Cloud 网关来应用这些跨领域限制。 Spring Cloud 网关是一个常用的 Spring 项目,可以像部署任何其他应用一样将其部署到 Azure Spring Apps 中。 使用 Spring Cloud 网关,可以保持你自己的应用程序在 Azure Spring Apps 实例中的私密性,并确保只能通过共享的 Spring Cloud 网关应用访问它们。 然后可以通过使用路由谓词(Spring Cloud 网关的内置功能)为此应用配置所需的访问限制。 这些路由谓词可以使用传入 HTTP 请求的不同属性来确定是要将请求路由到后端应用程序还是拒绝它。 谓词可以使用客户端 IP 地址、请求方法或路径、HTTP 标头等属性。

重要

以这种方式将 Spring Cloud 网关放在后端应用的前面时,必须将所有自定义域映射到 Spring Cloud 网关应用而不是后端应用。 否则,当针对其中任何自定义域的请求传入时,Azure Spring Apps 不会首先将传入流量路由到你的 Spring Cloud 网关。

此方法假设反向代理不会替代 HTTP Host 标头,且保持原始主机名不变。 有关详细信息,请参阅主机名保留

此模式是常用模式。 为完成本文的表述,我们假定你通过 Spring Cloud 网关公开应用程序。 我们假设你使用其路由谓词设置所需的访问限制,以确保仅允许来自反向代理的请求。 即使不使用 Spring Cloud 网关,相同的一般原则也适用。 但是,必须根据本文稍后所述的相同 X-Forwarded-For HTTP 标头将你自己的请求筛选功能内置到应用中。

注意

Spring Cloud 网关本身也是一个反向代理,提供路由、请求筛选、速率限制等服务。 如果该服务提供了方案所需的所有功能,你可能不需要应用程序网关或 Azure Front Door 之类的额外反向代理。 仍应考虑使用其他 Azure 服务的最常见原因是,两者都提供 WAF 功能,或者 Azure Front Door 提供全局负载均衡功能。

Spring Cloud 网关的工作原理超出了本文的范畴。 它是一个高度灵活的服务,可以通过代码或配置对其进行自定义。 为简单起见,本文只会介绍一种不需要更改代码的单纯的配置驱动式方法。 可以通过在部署的 Spring Cloud 网关应用中包含传统的 application.propertiesapplication.yml 文件来实现此方法。 也可以通过使用 Azure Spring Apps 中的 Config Server(将配置文件外部化到 Git 存储库中)来实现此方法。 在以下示例中,我们使用 YAML 语法实现 application.yml 方法,但等效 application.properties 的语法也有效。

将请求路由到应用程序

默认情况下,如果未为 Azure Spring Apps 中的应用分配终结点或者未为它配置自定义域,则无法从外部访问它。 如果应用将自身注册到 Spring Cloud 服务注册表,则 Spring Cloud 网关可以发现该应用,这样它就可以使用路由规则将流量转发到正确的目标应用。

因此,在 Azure Spring Apps 中唯一需要分配终结点的应用是你的 Spring Cloud 网关应用。 使用此终结点可以从外部访问该应用。 不应将终结点分配给任何其他应用。 否则可以直接访问这些应用,而不是通过 Spring Cloud 网关访问,这样会导致可以绕过反向代理。

要通过 Spring Cloud 网关公开所有已注册应用,一种简单方法是使用 DiscoveryClient 路由定义定位符,如下所示:

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          predicates:
          - Path="/"+serviceId+"/**" # Include the Path predicate to retain default behavior
          - (...)

或者,可以选择性地定义特定于应用的路由,通过 Spring Cloud 网关公开特定的应用:

spring:
  cloud:
    gateway:
      routes:
      - id: my_app1_route
        uri: lb://MY-APP1
        filters:
        - RewritePath=/myapp1(?<segment>/?.*), $\{segment}
        predicates:
        - (...)

通过发现定位符方法和显式路由定义,都可以使用路由谓词来拒绝无效请求。 在这种情况下,我们使用该功能来阻止不是来自 Azure Spring Apps 前面的预期反向代理的请求。

使用 X-Forwarded-For HTTP 标头限制访问

将应用部署到 Azure Spring Apps 时,HTTP 客户端或反向代理不会直接连接到该应用。 网络流量首先通过内部入口控制器。

注意

此方法意味着,在接下来的方案中访问应用之前,需要通过请求管道中的三个甚至四个反向代理。 可能的反向代理如下:Azure Front Door 和/或应用程序网关、入口控制器和 Spring Cloud 网关应用。

由于这项额外的服务,直接网络客户端的 IP 地址始终是内部 Azure Spring Apps 组件。 IP 地址永远不是逻辑客户端(类似于预期会调用应用的反向代理)。 不能使用客户端 IP 地址来实施访问限制。 也不能使用 Spring Cloud 网关的内置 RemoteAddr 路由谓词进行请求筛选,因为它默认使用客户端 IP 地址。

幸运的是,Azure Spring Apps 始终将逻辑客户端的 IP 地址添加到发往应用的请求中的 X-Forwarded-For HTTP 标头。 X-Forwarded-For 标头的最后一个(最右侧)值始终包含逻辑客户端的 IP 地址。

若要基于 X-Forwarded-For 标头筛选请求,可以使用内置的 XForwarded Remote Addr 路由谓词。 该谓词允许配置反向代理的、可用作最右侧值的 IP 地址或 IP 范围列表。

注意

XForwarded Remote Addr 路由谓词需要 Spring Cloud 网关版本 3.1.1 或更高版本。 Spring Cloud 2021.0.1 版本训练中提供了版本 3.1.1。 如果无法使用此版本,可以对 Spring Cloud 网关应用进行少量的代码更改,以修改 RemoteAddr 路由谓词确定客户端 IP 地址的方式。 可以实现与使用 XForwarded Remote Addr 路由谓词相同的结果。 将 RemoteAddr 配置为使用 XForwardedRemoteAddressResolver,并将后者配置为使用 maxTrustedIndex1。 此方法将 Spring Cloud 网关应用配置为使用 X-Forwarded-For 标头的最右侧值作为逻辑客户端 IP 地址。

配置应用以查看正确的主机名和请求 URL

使用 Spring Cloud 网关时,需要考虑一个重要因素。 Spring Cloud 网关会将出站请求中的 HTTP Host 标头设置为应用实例的内部 IP 地址(例如 Host: 10.2.1.15:1025)。 应用程序代码看到的请求主机名不再是浏览器发送的原始请求主机名(例如 contoso.com)。 在某些情况下,这可能会导致 Cookie 损坏或重定向 URL 无法正常工作等问题。 有关此类问题以及如何配置反向代理服务(例如应用程序网关或 Azure Front Door)以避免这些问题的详细信息,请参阅主机名保留

Spring Cloud 网关在 Forwarded 标头中提供原始主机名。 还设置其他标头(如 X-Forwarded-PortX-Forwarded-ProtoX-Forwarded-Prefix),以便应用程序可以使用它们重新构造原始请求 URL。 在 Spring Framework 应用程序中,可以通过在应用程序属性中将 server.forward-headers-strategy 设置设置为 FRAMEWORK 来自动实现此配置。 (不要将该值设置为 NATIVE,否则会使用其他标头,且不考虑必需的 X-Forwarded-Prefix 标头。)有关详细信息,请参阅在前端代理服务器后面运行。 使用此配置,HttpServletRequest.getRequestURL 方法会考虑所有这些标头,并返回浏览器发送的确切请求 URL。

注意

你可能觉得在 Spring Cloud 网关中使用 PreserveHostHeader 筛选器更好,这样就会保留出站请求中的原始主机名。 但是,这种方法不起作用,因为该主机名已映射为 Spring Cloud 网关应用上的自定义域。 它不能再次在最终的后端应用上映射。 此配置会导致 HTTP 404 错误,因为后端应用会拒绝传入的请求。 它无法识别主机名。

方案 3:将应用程序网关与 Spring Cloud 网关配合使用

方案 3 介绍如何使用应用程序网关作为通过 Spring Cloud 网关终结点公开访问的应用的反向代理。

下图描绘了方案 3 的体系结构:

Diagram that shows the use of Azure Application Gateway with Azure Spring Apps outside of a virtual network.

下载此体系结构的 Visio 文件

当应用程序网关位于 Azure Spring Apps 实例前面时,使用为 Spring Cloud 网关应用分配的终结点作为后端池。 示例终结点为 myspringcloudservice-mygateway.azuremicroservices.io。 由于 Azure Spring Apps 部署在虚拟网络外部,因此,此 URL 将解析为公共 IP 地址。 当后端池为公共终结点时,应用程序网关将使用其前端公共 IP 地址来访问后端服务。

若要仅允许来自应用程序网关实例的请求访问 Spring Cloud 网关,可以配置 XForwarded Remote Addr 路由谓词。 配置该谓词以仅允许来自应用程序网关的专用公共 IP 地址的请求,如以下示例所示:

(...)
predicates:
- XForwardedRemoteAddr="20.103.252.85"

方案 4:将 Azure Front Door 与 Spring Cloud 网关配合使用

方案 4 介绍如何使用 Azure Front Door 作为通过 Spring Cloud 网关终结点公开访问的应用的反向代理。

下图描绘了方案 4 的体系结构:

Diagram that shows the use of Azure Front Door with Azure Spring Apps outside of a virtual network.

下载此体系结构的 Visio 文件

该方案与方案 3 类似,此配置使用 Spring Cloud 网关应用的公共 URL 作为 Azure Front Door 中的后端池或源。 示例终结点为 https://myspringcloudservice-mygateway.azuremicroservices.io

由于 Azure Front Door 是具有许多边缘位置的全球服务,它会使用许多 IP 地址来与其后端池通信。 Azure Front Door 文档介绍了如何锁定对后端的访问以便仅允许 Azure Front Door 流量。 但在此方案中,你无法控制部署应用的 Azure 网络。 遗憾的是,你无法使用 AzureFrontDoor.Backend 服务标记来获取完整的且保证最新的出站 Azure Front Door IP 地址列表。 取而代之的是,必须下载 Azure IP 范围和服务标记,找到 AzureFrontDoor.Backend 节,然后将 addressPrefixes 数组中的所有 IP 范围复制到 XForwarded Remote Addr 路由谓词配置中。

重要

Azure Front Door 使用的 IP 范围可以会更改。 每周会发布权威的 Azure IP 范围和服务标记文件,并记录对 IP 范围的所有更改。 若要确保配置保持最新状态,请每周验证 IP 范围,并根据需要更新配置(最好是采用自动更新的方式)。 若要避免此方法造成的维护开销,可以在虚拟网络中部署 Azure Spring Apps,并通过使用带有 AzureFrontDoor.Backend 服务标记的 NSG 来使用前文所述的方案。

由于 Azure Front Door IP 范围与其他组织共享,因此还必须确保根据包含唯一 Front Door IDX-Azure-FDID HTTP 标头来锁定为只能从特定的 Azure Front Door 实例进行访问。 可以通过使用 Header 路由谓词来限制访问权限,除非指定的 HTTP 标头包含特定值,否则该路由谓词将拒绝请求。

在此方案中,Spring Cloud 网关路由谓词配置可能如以下示例所示:

(...)
predicates:
- XForwardedRemoteAddr="13.73.248.16/29","20.21.37.40/29","20.36.120.104/29","20.37.64.104/29", ...(and many more)...
- Header="X-Azure-FDID", "e483e3cc-e7f3-4e0a-9eca-5f2a62bde229"

作者

Microsoft 会维护此内容。 以下参与者参与了对原始内容的开发。

主要作者:

若要查看非公开的 LinkedIn 个人资料,请登录到 LinkedIn。

后续步骤