在通过负载平衡转发后,客户端地址如何透传到上游的服务是一个常见的问题。本文将阐明在BFE中是如何解决这个问题的。

1. 问题阐明

在通过BFE转发后,RS无奈取得原始的客户端IP地址,而只能取得BFE实例的IP地址。

如图1所示,客户端的IP地址为1.2.3.4,在通过BFE转发后,BFE和RS建设了新的TCP连贯,RS只能看到BFE的地址10.1.0.1

很多利用都须要获取申请原始的客户端IP地址。须要提供机制将原始的客户端IP地址传递到RS。


图1 通过BFE转发后客户端地址的变动

2. BFE的客户端地址透传计划

BFE在扩大模块mod_header中默认提供了捎带客户端IP地址和端口的性能。只有在BFE启动时配置加载mod_header,在转发后申请中就会蕴含这两个信息。

在通过BFE转发后,在HTTP申请的头部会减少2个字段:

  • X-Real-Ip:用于传递原始的客户端IP地址
  • X-Real-Port:用于传递原始的客户端端口

注:

  • mod_header的实现位于
    https://github.com/bfenetwork...
  • mod_header的阐明文档位于
    https://github.com/bfenetwork...

3. 为什么不应用x-forward-for

已经有一个敌人在《深刻了解BFE》的Github讨论区中提了一个问题:为什么不应用X-Forwarded-For来传递客户端IP地址呢?

BFE应用独立定义的“X-Real-Ip”是为了防止“X-Forwarded-For”被伪造。

如果申请在达到BFE时曾经蕴含了“X-Real-Ip”字段,BFE会将这个字段的值重写为BFE所见的客户端IP地址,从而防止这个字段被伪造。

然而BFE不能应用相似的“重写”计划来防止x-forward-for字段的伪造。

能够看看上面的两种可能的场景:

  • 场景一: 如果申请中原本没有蕴含X-Forwarded-For头部
    BFE能够增加新的头部,

    X-Forwarded-For: client-ip, bfe的地址
  • 场景二:如果申请中曾经蕴含X-Forwarded-For头部,如,

    X-Forwarded-For: client1, proxy1, proxy2, proxy3

    那么BFE须要将本人的地址增加到开端

    X-Forwarded-For: client1, proxy1, proxy2, proxy3,BFE的地址

    在这种状况下,client的地址可能为伪造。然而,BFE不能改写X-Forwarded-For的值,因为须要保留X-Forwarded-For的内容供其它可能的剖析

4. 其它信息的透传

除了原始的客户端IP地址,可能还须要BFE向上游服务透传其它信息,如本次申请所拜访的服务端IP地址(VIP),本次申请所应用的TLS/SSL协定版本等。在某些场景中,因为历史的起因,可能也须要对于透传客户端IP地址的头部名称做非凡的设置

在mod_header中,能够对每个租户提供一张配置表,能够针对符合条件的申请,对头部做指定的动作。


图2 租户的mod_header配置表

在配置表中,应用BFE的条件表达式来形容匹配的条件。对申请(Request)和响应(Response)的Header可能执行的操作包含设置、增加、删除等。针对同一个匹配条件,能够执行多个操作。

为了便于操作,在mod_header中还提供了一些内置的变量,用于在配置图2中的action时应用。如:

  • %bfe_cip,代表客户端IP (CIP)
  • %bfe_vip,代表服务端IP (VIP)

在上面这个配置的例子中,对于属于“example_product”的申请,如果申请的Path前缀为“/header”,则设置名为X-Bfe-Vip的Header,用于向上游服务传递服务端IP地址。

{    "Version": "20190101000000",    "Config": {        "example_product": [            {                "cond": "req_path_prefix_in(\"/header\", false)",                "actions": [                    {                        "cmd": "REQ_HEADER_SET",                        "params": [                            "X-Bfe-Vip",                            "%bfe_vip"                        ]                    },                ],                "last": true            }        ]    }}

5. BFE如何从上游取得客户端地址

在理论部署中,在BFE的上游常常会应用四层负载平衡,以实现多个BFE实例间的流量平衡,并解决BFE的高可用。

流量在通过四层负载均衡器的转发后,BFE同样也无奈间接取得原始的客户端IP地址,而只能看到四层负载均衡器的外部地址。


图3 通过四层负载均衡器后地址发生变化

因为很多四层负载均衡器不能像BFE这样批改HTTP申请头部(局部的起因是因为这样的性能对于四层负载均衡器来说太简单;局部的起因是因为在HTTPS的场景下四层负载均衡器无奈“看见”和批改申请的内容),所以须要应用更底层的机制。

常见的计划有两种:

  • 计划1:应用TOA(TCP Option Address)
    通过在TCP Options中插入客户端地址形式,将客户端地址从四层负载均衡器携带到BFE。
    LVS这样的开源负载平衡软件和F5这样的商用负载平衡产品都反对开启TOA。

    如果应用TOA计划,在BFE所在的服务器,须要装置TOA插件。这样BFE从socket中读取到的客户端IP地址就是原始的客户端IP地址。
    TOA的详情能够参考以下文章:
    https://zhuanlan.zhihu.com/p/...
    https://www.jianshu.com/p/e77...

  • 计划2:应用Proxy Protocol
    Proxy Protocol是由HAProxy创造的。其次要思维是:在发送数据之前,首先发送一个非凡的头信息,用于传递客户端IP地址、端口等信息。
    HAProxy这样的开源负载平衡软件和F5这样的商用负载平衡产品都反对开启Proxy Prococol。
    如果应用Proxy Prococol计划,须要批改BFE的配置。在bfe.conf中,须要将Layer4LoadBalancer设置为"PROXY"。

    [Server]…# type of layer-4 load balancer (PROXY/NONE), default NONELayer4LoadBalancer = "PROXY"…

    能够参考
    https://github.com/bfenetwork...。
    Proxy Protocol的详情能够参考以下文章:
    https://www.haproxy.org/downl...
    https://www.jianshu.com/p/cc8...

6. 总结

在向上游服务透传原始客户端IP地址等信息方面,BFE提供了残缺的反对。

在蕴含四层负载均衡器的场景中,能够应用TOA或Proxy Protocol将原始的客户端IP地址从客户端传递给BFE。

欢送关注“BFE开源我的项目”微信公众号,取得本我的项目的更多更新。谢谢!