不同场景下容器内获取客户端源IP
在容器化环境中,客户端与容器服务器间的通信可能涉及多种代理服务器。当外部请求经过代理服务器多层转发时,客户端源IP地址可能无法被成功传递至容器内的业务中。本文将针对CCE集群提供网络访问的不同方案,详细说明如何在容器内部有效地获取客户端源IP。
场景介绍
根据不同的网络设置,容器内获取客户端源IP的方法可能会有所不同。以下是几种常见的网络访问配置及其对应的解决方案:
- Ingress七层转发:应用在七层访问时,客户端源IP默认保存在HTTP头部的“X-Forwarded-For”字段,无需进行其他配置即可获取客户端源IP。
- Service四层转发:不同类型的Service获取源IP的方式及原理不同。
- 负载均衡类型Service:将弹性负载均衡器作为流量入口,支持使用共享型或独享型的弹性负载均衡器。
- 共享型弹性负载均衡器需要在监听器上开启“获取客户端IP”功能。
- 独享型弹性负载均衡器在监听器上默认启用“获取客户端IP”功能,无需用户手动设置。
- 节点访问类型Service:将容器端口映射到节点端口,将节点端口作为对外服务的访问入口。节点访问Service的客户端源IP能力与它的“服务亲和”配置相关。
- 当节点访问类型Service的“服务亲和”配置为“集群级别”时,流量在集群中会经过一次转发,导致Service后端的容器无法获取客户端源IP。
- 当节点访问类型Service的“服务亲和”配置为“节点级别”时,流量不经过转发直接访问节点上的容器,因此Service后端的容器可以获取客户端源IP。
- 负载均衡类型Service:将弹性负载均衡器作为流量入口,支持使用共享型或独享型的弹性负载均衡器。
若已使用Istio服务网格,获取源IP地址的方法请参见服务加入Istio后,如何获取客户端真实源IP?
支持获取源IP地址的场景
由于网络模型差异,CCE在部分使用场景下暂不支持获取源IP,如表1,若在集群使用过程中需要获取源IP,请尽量避免此类场景。表中“-”代表无此场景。
一级分类 |
二级分类 |
负载均衡类型 |
VPC、容器隧道网络模型 |
云原生网络2.0模型(CCE Turbo集群) |
操作指导 |
---|---|---|---|---|---|
七层转发(Ingress) |
ELB型 |
共享型 |
支持 |
支持 |
|
独享型 |
支持 |
支持 |
|||
Nginx型(对接NGINX Ingress控制器插件) |
共享型 |
支持 |
暂不支持 |
||
独享型 |
支持 |
支持 |
默认开启,无需进行其他配置 |
||
四层转发(Service) |
负载均衡(LoadBalancer) |
共享型 |
支持 |
暂不支持(使用hostNetwork的工作负载支持) |
|
独享型 |
支持 |
支持 |
|||
节点访问(NodePort) |
- |
支持 |
暂不支持(使用hostNetwork的工作负载支持) |
ELB Ingress
对于ELB Ingress(即使用HTTP/HTTPS协议),ELB默认会开启获取客户端源IP,无需其他操作。
客户端源IP会被负载均衡放在HTTP头部的X-Forwarded-For字段,格式如下:
X-Forwarded-For: 客户端源IP, 代理服务器1-IP, 代理服务器2-IP, ...
X-Forwarded-For字段中获取的第一个地址就是获取客户端源IP。
Nginx Ingress
云原生网络2.0模型下(即CCE Turbo集群),Ingress开启对接NGINX Ingress控制器插件时使用共享型ELB暂不支持获取源IP,参见支持获取源IP地址的场景。如需获取源IP,请卸载NGINX Ingress控制器插件并在重新安装时使用独享型ELB。
- Nginx Ingress使用独享型ELB时,默认开启源地址透传功能,无需其他配置即可获取客户端源IP。
- Nginx Ingress使用共享型ELB时,获取客户端源IP的操作步骤如下:
- 以Nginx工作负载为例,未配置源IP访问前,使用以下命令查看访问日志,其中nginx-c99fd67bb-ghv4q为Pod名称:
kubectl logs nginx-c99fd67bb-ghv4q
回显如下:
... 10.0.0.7 - - [17/Aug/2023:01:30:11 +0000] "GET / HTTP/1.1" 200 19 "http://114.114.114.114:9421/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.203" "100.125.**.**"
其中100.125.**.**为负载均衡的地址段,说明流量经过负载均衡转发。
- 开启“获取客户端IP”功能。仅使用共享型ELB时需操作,独享型ELB默认开启源地址透传功能,无需手动开启。
- 重新访问工作负载,并查看新增的访问日志如下:
... 10.0.0.7 - - [17/Aug/2023:02:43:11 +0000] "GET / HTTP/1.1" 304 0 "http://114.114.114.114:9421/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.203" "124.**.**.**"
显示成功获取到客户端源IP。
如果您需要为集群Nginx Ingress Controller所使用的ELB开启WAF功能,不同的WAF模式会影响Nginx Ingress Controller获取真实的客户端IP:
- 使用WAF云模式的CNAME接入
采用CNAME模式接入,会导致请求先通过WAF,经过WAF进行防护检查之后再转发给ELB。因此即使ELB已开启源地址透传,实际上客户端得到为WAF的回源IP,造成Nginx Ingress Controller将默认无法获得真实的客户端IP。此时您可以编辑NGINX Ingress控制器插件,在nginx配置参数处添加以下配置。
{ "enable-real-ip": "true", "use-forwarded-headers": "true", "proxy-real-ip-cidr": <您从WAF获取到的回源IP段> }
- 使用WAF云模式ELB接入
该模式为透明接入(旁路部署),仅支持独享型ELB,Nginx Ingress Controller默认可以获得真实的客户端IP。
负载均衡( LoadBalancer )
- CCE集群(VPC、容器隧道网络模型):使用共享型和独享型ELB均支持获取源IP。
- CCE Turbo集群(云原生网络2.0模型):使用独享型ELB时支持获取源IP;使用共享型ELB时,仅开启hostNetwork的工作负载支持获取源IP。
VPC、容器隧道网络模型
通过控制台开启获取源IP的步骤如下:
- 在CCE控制台创建负载均衡类型的Service,服务亲和选择“节点级别”而不是“集群级别”。
- 前往ELB控制台,开启ELB实例对应监听器的“获取客户端IP”功能。独享型ELB默认开启源地址透传功能,无需手动开启。
- 在管理控制台左上角单击图标,选择区域和项目。
- 选择“服务列表 > 网络 > 弹性负载均衡 ELB”。
- 在“弹性负载均衡器”界面,单击需要操作的负载均衡名称。
- 切换到“监听器”页签,单击需要修改的监听器名称右侧的“编辑”按钮。如果存在修改保护,请在监听器基本信息页面中关闭修改保护后重试。
- 开启“获取客户端IP”开关。
图3 开启开关
apiVersion: v1
kind: Service
metadata:
name: nginx
annotations:
kubernetes.io/elb.id: <your_elb_id> # ELB ID,替换为实际值
kubernetes.io/elb.class: union # 负载均衡器类型
kubernetes.io/elb.transparent-client-ip: 'true' # 开启获取客户端源IP
spec:
selector:
app: nginx
externalTrafficPolicy: Local
ports:
- name: service0
port: 80
protocol: TCP
targetPort: 80
type: LoadBalancer
云原生网络2.0模型(CCE Turbo集群)
- 开启hostNetwork的工作负载:支持将服务亲和选项设置为“节点级别”,可获取源IP。
- 其他工作负载:无法将服务亲和选项设置为“节点级别”,因此无法获取源IP。
建议使用独享型ELB,外部访问可不经过转发直通容器。独享型ELB默认开启源地址透传,无需前往ELB控制台手动开启“获取客户端IP”开关,只需要在CCE控制台创建负载均衡服务时选择独享型负载均衡,即可获取客户端源IP。