使用 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。