

Kubernets中获取客户端真实IP总结
source link: https://segmentfault.com/a/1190000022272897
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

1. 导言
绝大多数业务场景都是需要知道客户端IP的
在k8s中运行的业务项目,如何获取到客户端真实IP?
本文总结了通行的2种方式
要答案的直接看方式一、方式二和总结
SEO 关键字
nginx ingress客户端真实ip
kubernets获取客户端真实ip
rke获取客户端真实ip
rancher获取客户端真实ip
本文由 www.iamle.com 流水理鱼 原创,wx公众号同名
1.1 流量链路介绍
7层转发链路 Client(客户端) > Nginx > K8s Ingress(Nginx ingress)
4层转发链路 Client(客户端) > 公有云LB > K8s Ingress(Nginx ingress)
ps: 实际业务会串联更多层级的转发。WAF、CDN、Api Gateway一般是http 7层转发,LB一般是4层tcp转发
1.2 准备whoami探针
whomai是一个go编写的调试探针工具,回显http头信息
在k8s中部署一个containous/whoami用来作为探针,配置好ingress公网和访问,这样客户端web访问可以看到基本的http头信息,方便调试
kubectl apply -f - <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: whoami namespace: default labels: app: whoami spec: replicas: 1 selector: matchLabels: app: whoami template: metadata: labels: app: whoami spec: containers: - image: containous/whoami imagePullPolicy: Always name: whoami ports: - containerPort: 80 name: 80tcp02 protocol: TCP dnsPolicy: ClusterFirst restartPolicy: Always EOF
ps:ingress自行增加
客户端web访问,回显http头示例
Hostname: whoami-65b8cc4b-6vwns IP: 127.0.0.1 IP: 10.42.2.12 RemoteAddr: 10.42.1.0:47850 GET / HTTP/1.1 Host: whoami.iamle.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.162 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6,la;q=0.5 Cookie: _ga=GA1.2.30707523.1570429261; Dnt: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: cross-site Sec-Fetch-User: ?1 Upgrade-Insecure-Requests: 1 X-Forwarded-For: 8.8.8.8, 10.0.0.1 X-Forwarded-Host: whoami.iamle.com X-Forwarded-Port: 443 X-Forwarded-Proto: https X-Original-Forwarded-For: 8.8.8.8 X-Original-Uri: / X-Real-Ip: 8.8.8.8 X-Request-Id: 3852c9780589ffba4c1f9f2785691d5f X-Scheme: https
2. 两种方式 7层http头X-Forwarded-For透传 和 4层Proxy Protocol透传
获得客户端真实IP有针对7层和针对4层两种方式
2.1 7层http头X-Forwarded-For透传介绍
http工作在网络第7层,http中有个X-Forwarded-For字段
大部分CDN、WAF、LB用X-Forwarded-For字段来存客户端IP,也有用X-Real-Ip字段,cloudflare、百度云加速还扩展了CF-Connecting-IP字段
标准数据为
X-Forwareded-For:Client,proxy1,proxy2,proxy3……
第一个ip是客户端ip,后面的proxy为路过一层就加一层的ip
这里的proxy可以是WAF、CDN、LB、Api Gateway等
2.2 4层Proxy Protocol透传
tcp工作在网络第4层,Proxy Protocol就是在tcp中增加一个小的报头,用来存储额外的信息
代理协议即 Proxy Protocol,是haproxy的作者Willy Tarreau于2010年开发和设计的一个Internet协议,通过为tcp添加一个很小的头信息,来方便的传递客户端信息(协议栈、源IP、目的IP、源端口、目的端口等),在网络情况复杂又需要获取客户IP时非常有用。
其本质是在三次握手结束后由代理在连接中插入了一个携带了原始连接四元组信息的数据包。
目前 proxy protocol有两个版本,v1仅支持human-readable报头格式(ASCIII码),v2需同时支持human-readable和二进制格式,即需要兼容v1格式
proxy protocol的接收端必须在接收到完整有效的 proxy protocol 头部后才能开始处理连接数据。因此对于服务器的同一个监听端口,不存在兼容带proxy protocol包的连接和不带proxy protocol包的连接。如果服务器接收到的第一个数据包不符合proxy protocol的格式,那么服务器会直接终止连接。
Proxy protocol是比较新的协议,但目前已经有很多软件支持,如haproxy、nginx、apache、squid、mysql等等,要使用proxy protocol需要两个角色sender和receiver,sender在与receiver之间建立连接后,会先发送一个带有客户信息的tcp header,因为更改了tcp协议头,需receiver也支持proxy protocol,否则不能识别tcp包头,导致无法成功建立连接。
nginx是从1.5.12起开始支持的
3. 方式一 X-Forwarded-For配置
适用于7层http转发
3.1 NGINX Ingress Controller X-Forwarded-For配置
查看NGINX Ingress Controller的ConfigMaps配置文档,可以找到以下配置项
use-forwarded-headers
如果为true,NGINX会将传入的 X-Forwarded-* 头传递给upstreams。当NGINX位于另一个正在设置这些标头的 L7 proxy / load balancer 之后时,请使用此选项。
如果为false,NGINX会忽略传入的 X-Forwarded-* 头,用它看到的请求信息填充它们。如果NGINX直接暴露在互联网上,或者它在基于 L3/packet-based load balancer 后面,并且不改变数据包中的源IP,请使用此选项。
ps: NGINX Ingress Controller直接暴露互联网也就是Edge模式不能开启为true,否则会有伪造ip的安全问题。也就是k8s有公网ip,直接让客户端访问,本配置不要设为true!
forwarded-for-header
设置标头字段以标识客户端的原始IP地址。 默认: X-Forwarded-For
ps:如果 NGINX Ingress Controller 在CDN,WAF,LB等后面,设置从头的哪个字段获取IP,默认是X-Forwarded-For
这个配置应该和use-forwarded-headers配合使用
compute-full-forwarded-for
将远程地址附加到 X-Forwarded-For 标头,而不是替换它。 启用此选项后,upstreams应用程序将根据其自己的受信任代理列表提取客户端IP
修改configmap nginx-configuration配置
kubectl -n ingress-nginx edit cm nginx-configuration
在apiVersion: v1下,kind: ConfigMap上加入
data: compute-full-forwarded-for: "true" forwarded-for-header: "X-Forwarded-For" use-forwarded-headers: "true"
或者直接apply附加配置
kubectl apply -f - <<EOF apiVersion: v1 data: compute-full-forwarded-for: "true" forwarded-for-header: X-Forwarded-For use-forwarded-headers: "true" kind: ConfigMap metadata: labels: app: ingress-nginx name: nginx-configuration namespace: ingress-nginx EOF
ps:如果nginx-configuration不在namespace ingress-nginx中就在namespace kube-system中找
3.2 Nginx作为边缘节点(Edge)配置
作为Edge需要重写remote_addr,保证了客户端IP不会被伪造
必须:X-Forwarded-For 重写为 $remote_addr
非必须扩展:X-Real-IP 重写为 $remote_addr
upstream wwek-k8s { server 8.8.8.8:443; server 8.8.8.7:443; server 8.8.8.6:443; } map $http_upgrade $connection_upgrade { default Upgrade; '' close; } server { if ($http_x_forwarded_proto = '') { set $http_x_forwarded_proto $scheme; } location / { proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Real-IP $remote_addr; proxy_pass https://wwek-k8s; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_read_timeout 900s; proxy_buffering off; } }
3.3 X-Forwarded-For是否可以伪造
客户端是否能伪造IP,取决于边缘节点(Edge)是如何处理X-Forwarded-For字段的。
客户端直接连接的首个proxy节点都叫做边缘节点(Edge),不管是网关、CDN、LB等只要这一层是直接接入客户端访问的,那么他就是一个边缘节点。
不重写-不安全的边缘节点(Edge)
边缘节点如果是透传http头中的X-Forwarded-For字段,那么这个就是不安全的,客户端可以在http中实现包含X-Forwarded-For字段值,这个值又被透传了。
#不安全 X-Forwareded-For:Client(Edge不重写,只透传),proxy1,proxy2,proxy3……
重写-安全的边缘节点(Edge)
边缘节点(Edge)如果重写remote_addr到X-Forwarded-For,那么这就是安全的。边缘节点(Edge)获取的remote_addr就是客户端的真实IP
#安全 X-Forwareded-For:Client(Edge获取的remote_addr),proxy1,proxy2,proxy3……
4. 方式二 Proxy Protocol 配置实例
适用于4层tcp转发
公有云的负载均衡LB一般都支持Proxy Protocol
查看NGINX Ingress Controller的ConfigMaps配置文档,可以找到如何配置Proxy Protocol
use-proxy-protocol
启用或禁用roxy Protocol,以接收通过代理服务器和负载均衡器(例如HAProxy和Amazon Elastic Load Balancer(ELB))传递的客户端连接(真实IP地址)信息。
NGINX Ingress Controller 作为receiver角色 Proxy Protocol配置
kubectl -n ingress-nginx edit cm nginx-configuration
在apiVersion: v1下,kind: ConfigMap上加入
data: use-proxy-protocol: "true"
或者直接apply附加配置
kubectl apply -f - <<EOF apiVersion: v1 data: use-proxy-protocol: "true" kind: ConfigMap metadata: labels: app: ingress-nginx name: nginx-configuration namespace: ingress-nginx EOF
ps: 注意需要上一层LB支持Proxy Protocol,才能这么配置,否则会导致无法链接
5. 总结
7层http头X-Forwarded-For透传
链路proxy有透传X-Forwarded-For
访问链路上多层proxy,任意一个节点不支持Proxy Protocol
4层协议Proxy Protocol透传
上下游可控都支持Proxy Protocol协议
链路proxy中丢失了http头
https反向代理http(某些情况下由于Keep-alive导致不是每次请求都传递x-forword-for
应该用那种方式?
7层用X-Forwarded-For,4层用Proxy Protocol
如果链路的边缘节点(Edge)X-Forwarded-For字段是安全的,建议用X-Forwarded-For
如果链路proxy全路径都支持Proxy Protocol,那么建议用Proxy Protocol
如果有4层tcp业务应用,那么获取客户端IP就的用Proxy Protocol
总之搞清楚了这2种方式的原理按照场景选择
5. 参考
- HTTP HeadersX-Forwarded-For https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/X-Forwarded-For
- Proxy Protocol Introduction https://www.haproxy.com/blog/haproxy/Proxy Protocol/
- NGINX Ingress Controller ConfigMaps https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#use-forwarded-headers
- Configuring NGINX to Accept the PROXY Protocol https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol/#configuring-nginx-to-accept-the-proxy-protocol
- nginx Module ngx_http_realip_module https://nginx.org/en/docs/http/ngx_http_realip_module.html
- rancher K8s Ingress Controllers https://rancher.com/docs/rke/latest/en/config-options/add-ons/ingress-controllers/
- rancher Set Up Load Balancer and Ingress Controller within Rancher https://rancher.com/docs/rancher/v2.x/en/k8s-in-rancher/load-balancers-and-ingress/
- 阿里云负载均衡 如何获取客户端真实IP https://help.aliyun.com/document_detail/54007.html
- 阿里云全站加速 获取客户端真实IP https://help.aliyun.com/document_detail/119658.html
- 腾讯云高防IP 获取客户端真实IP https://cloud.tencent.com/document/product/1014/31124
- How does Cloudflare handle HTTP Request headers?
本文由博客一文多发平台 OpenWrite 发布!
Recommend
-
54
安装完kubernets后,不可避免的要在集群中安装一些日常所需要的软件和服务。其中对于运维来说,jenkins是经常使用的一个工具,这里,介绍一下如何在k8s中安装jenkins工具。这也是为将来为jinkins+k8s的ci/cd流程做一个基础的架构环境。一:首先,检查k8s环境,确保...
-
52
[编者的话]这篇文章作者分别阐述了kubernetes与serverless的优缺点,实际上两者可能并不是竞争关系,在某些架构中,两者可以同时存在以满足不同的需求。但是最终的目的都是为了使应用程序部署更方便快捷,更易管理,更具成本效益和以及...
-
33
很多刚刚接触 gRPC 的用户,通常会惊讶于 Kubernetes 默认提供的负载均衡对于 gRPC 来说无法实现开箱即用的效果。比如,将一个简单的基于 Node.js 实现的 gRPC 微服务部署在 Kubernetes 后,如下图所示:
-
5
容器服务 在 TKE 中获取客户端真实源 IP 文档中心 >
-
7
您现在的位置:首页 --> PHP --> 当网站使用CDN后获取客户端真实IP的方法 当网站使用CDN后获取客户...
-
9
如何获取客户端真实 IP?从 Gin 的一个 "Bug" 说起 作者:郑伟@石墨文档 请求 IP 作为用户的身份标识属性之一,是一种非常重要的基础数据。在很多场景下,我们会基于客户端请求 IP 去做网...
-
5
怎么获取客户端真实的ip为 ...
-
4
获取客户端访问真实 IP-阳明的博客|Kubernetes|Istio|Prometheus|Python|Golang|云原生 https://unsplash.com/photos/EfIcvL2R5Ac 通常,当集群内的客户端连接到服务的时候,是支持服务的 Pod 可以获取到客户端的 IP...
-
9
某云负载均衡真实IP的问题,我们这边已经遇到过两次了。而且每次和售后沟通的时候都大费周折,主要是要给售后说明白目前文档的获取真实IP是有问题的,他们觉得文档上说明的肯定没问题,售后要是不明白,他们不会给LB部门上报,这个事就没法推进。...
-
4
Nginx获取真实的客户端IP和限制IP IP限制的写法 有时候,我们的...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK