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