使用 Nginx real-ip 模块

2021-09-24 14:18:14 浏览数 (1)

使用 Nginx real-ip 模块获取,需在 Ingress 上配置 proxy-real-ip-cidr ,把WAF 和 SLB(7 层) 地址都加上。操作后服务端使用 X-Forwarded-For 可取到真实 IP,通过 X-Original-Forwarded-For 可取到伪造 IP。

这种方案有如下缺点:

•由于 WAF 是云厂商维护,WAF 地址池众多,同时地址会有变化,维护此动态配置难度极大,如更新不及时会导致获取的客户端 IP 不准确。•即使采用此方案,业务方如果要使用新版本的 Gin 的 ctx. ClientIP() 方法,仍然需改动代码,将所有可信代理配置到 TrustedProxies,这会导致基础设施和业务服务耦合,这种方案显然是无法接受的,除非业务方愿意将依赖的 Gin 版本锁死在 v1.6.3。

3.2.1.2. 使用 WAF 自定义 Header

不少云厂商提供了自定义 Header 来获取客户端真实 IP( $remote_addr )能力,我们可以在云厂商 WAF 终端中提前配置好自定义 Header 头,比如 X-Appengine-Remote-Addr 或 X-Client-Real-IP 等,用来获取客户端真实 IP。

这种方案有如下缺点:

•如直接复用 X-Appengine-Remote-Addr 这个 Header,则需设置 engine. AppEngine=true,才可通过 ctx. ClientIP() 方法的前提下获取客户端 IP。•如使用其他 Header,比如 X-Client-Real-IP,则需要自行封装从 X-Client-Real-IP 中获取客户端 IP 方法,同时需要业务配合做改造。

架构大概如下所示:

3.2.2. 客户端->CDN->WAF->SLB->Ingress->Pod
3.2.2.2. 使用 real-ip

使用 real-ip 模块获取,需要在 ingress 上配置 proxy-real-ip-cidr 把 CDN、WAF 和 SLB(7 层)的地址都加上,服务端使用 X-Forwarded-For 可取到真实 IP,通过 X-Original-Forwarded-For 可取到伪造 IP。

此方案优缺点:

•此场景相比 3.2.1 多了层 CDN,CDN 地址池比 WAF 更大,地址池变化频率更高,同时厂商也没有提供 CDN 地址池,维护 Ingress 配置基本不可能。•即使采用此方案,业务方如果要使用新版本的 Gin 的 ctx. ClientIP() 方法,仍然需改动代码,将所有可信代理配置到 TrustedProxies,这会导致基础设施和业务服务耦合,这个肯定无法接受,除非业务方将 Gin 版本锁死在 1.6.3。

3.2.2.1. 使用 CDN 自定义 Header

此方案优缺点:同 3.1.1。架构大概如下所示:

3.2.3. 客户端->SLB->Ingress->Pod

可通过 Ingress 上设置 use-forwarded-headers 来防止 X-Forwarded-For 伪造。

•use-forwarded-headers=false

适用于 Ingress 前无代理层,例如直接挂在 4 层 SLB 上,ingress 默认重写 X-Forwarded-For 为 $remote_addr ,可防止伪造 X-Forwarded-For 。

•use-forwarded-headers=true

适用于 Ingress 前有代理层,例如 7 层 SLB 或 WAF、CDN 等相当于在 nginx.conf 中添加如下配置:

代码语言:javascript复制
real_ip_header      X-Forwarded-For; real_ip_recursive   on; set_real_ip_from    0.0.0.0/0; // 默认信任所有 IP,无法避免伪造 X-Forwarded-For

架构大概如下所示:

4. 总结

从上文中我们不难看出,在云上复杂多变的网络拓扑结构下,我们会频繁地维护 CDN、WAF、SLB、Ingress 等多种网络设施配置。如果需完全保证 X-Forwarded-For 不可伪造,对于要升级 Gin 框架的 Go 服务来说,只有如下两种方案:

•继续尝试通过 X-Forwarded-For 获取客户端真实 IP。•尝试通过其他 Header 获取客户端真实 IP。

4.1. 继续尝试通过 X-Forwarded-For 获取客户端真实 IP

业务中需配置基础设施所有前置代理到 TrustedProxies 中,包含 CDN 地址池、WAF 地址池、Kunernetest Nginx Ingress 地址池,这种方案基本无法落地:

•配置太过复杂,一旦获取 IP 不准,很难排查。•导致业务配置和基础设施耦合,基础设施如果对 CDN、WAF、Ingress 做变动,业务代码必须同步变更。•部分可信代理 IP 根本没法配置,比如 CDN 地址池。

4.2. 尝试通过自定义 Header 获取客户端真实 IP

基础设施团队提供自定义 Header 来获取客户端真实 IP,如 X-Client-Real-IP 或 X-Appengine-Remote-Addr 。这种方案需要基础设施团队在云厂商 CDN 或 WAF 终端上做好相应的配置。这种方案:

•配置简单可靠,维护成本低,仅需在 CDN、WAF 终端配置自定义 Header 即可。•如果使用 X-Appengine-Remote-Addr,对于使用 Google Cloud 的 App Engine 的服务不需做任何修改。对于使用的国内云厂商的服务,则需要显式的配置 engine. AppEngine = true,然后继续通过 ctx.ClientIP() 方法即可。•如果使用其他自定义 Header,如 X-Client-Real-IP 来获取客户端真实 IP,建议可以考虑自行封装 ClientIP(*gin.Context) string 函数,从 X-Client-Real-IP 中获取客户端 IP。

0 人点赞