乐趣区

关于云原生:使用BFE如何实现地址透传

在通过负载平衡转发后,客户端地址如何透传到上游的服务是一个常见的问题。本文将阐明在 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 NONE
    Layer4LoadBalancer = "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 开源我的项目”微信公众号,取得本我的项目的更多更新。谢谢!

退出移动版