绝大多数业务场景都是须要知道客户端IP的
在k8s中运行的业务项目,如何获取到客户端真实IP?
本文总结了通行的2种方式
要答案的直接看方式1、方式二和总结
SEO 关键字
nginx ingress客户端真实ip
kubernets获取客户端真实ip
rke获取客户端真实ip
rancher获取客户端真实ip
本文由 www.iamle.com 流水理鱼 原创,wx公众号同名html
7层转发链路 Client(客户端) > Nginx > K8s Ingress(Nginx ingress)
4层转发链路 Client(客户端) > 公有云LB > K8s Ingress(Nginx ingress)
ps: 实际业务会串联更多层级的转发。WAF、CDN、Api Gateway通常是http 7层转发,LB通常是4层tcp转发mysql
whomai是一个go编写的调试探针工具,回显http头信息
在k8s中部署一个containous/whoami用来做为探针,配置好ingress公网和访问,这样客户端web访问能够看到基本的http头信息,方便调试nginx
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自行增长git
客户端web访问,回显http头示例github
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
得到客户端真实IP有针对7层和针对4层两种方式web
http工做在网络第7层,http中有个X-Forwarded-For字段sql
大部分CDN、WAF、LB用X-Forwarded-For字段来存客户端IP,也有用X-Real-Ip字段,cloudflare、百度云加速还扩展了CF-Connecting-IP字段
标准数据为apache
X-Forwareded-For:Client,proxy1,proxy2,proxy3……
第一个ip是客户端ip,后面的proxy为路过一层就加一层的ip
这里的proxy能够是WAF、CDN、LB、Api Gateway等api
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起开始支持的
适用于7层http转发
查看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中找
做为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; } }
客户端是否能伪造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层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,才能这么配置,不然会致使没法连接
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种方式的原理按照场景选择
本文由博客一文多发平台 OpenWrite 发布!