概述
通常web
应用获取用户客户端的真实ip
一个很常见的需求,例如将用户真实ip
取到之后对用户做白名单访问限制、将用户ip
记录到数据库日志中对用户的操作做审计等等...k8s
中运行的应用通过Service
抽象来互相查找、通信和与外部世界沟通,在k8s
中是kube-proxy
组件实现了Service
的通信与负载均衡,流量在传递的过程中经过了源地址转换SNAT
,因此在默认的情况下,常常是拿不到用户真实的ip
的...
这个问题在k8s
官方文档(https://kubernetes.io/zh/docs/tutorials/services/source-ip/)中基于Cluster IP
、NodePort
、LoadBalancer
三种不同的Service
类型进行了一定的说明.
简单来说,就是原先 k8s 能在一个 Pod 的情况在多个 Node 进行访问,因为其做了转发做了 SNAT
将源 IP
客户端发送数据包到
node2:nodePort
node2
使用它自己的 IP 地址替换数据包的源 IP 地址(SNAT)node2
将数据包上的目标 IP 替换为 Pod IP数据包被路由到 node1,然后到端点
Pod 的回复被路由回 node2
Pod 的回复被发送回给客户端
当然 Kubernetes 也提供了一个特性保留原始客户端 IP 但是这样就无法在多个 Node 中进行访问.
还有一种方案,就是在 LoadBalancer 添加新一个新的消息头.例如 X-Forwarded-For
.但是 Ingress 会将真实 IP 放入至 x-original-forwarded-for
前提就是需要前置服务将源 IP 放置 X-Forwarded-For
.
环境介绍
相关说明
真实生产场景下,一般提供给用户的都是七层https
服务
首先域名解析在外部负载设备绑定的公网ip
上,负载周边可能还会有一些安全设备例如WAF
等,这里不多介绍
流量经过负载后进入到k8s
集群中,其中Ingress Controller
以DaemonSet
方式部署并使用hostNetwork
模式接收并处理到达宿主机的80
、443
端口流量
关于https
证书的配置,一般有以下两种可选方式:
配置在负载设备(负载类型如果只考虑七层负载),由负载负责将数据包封包解包,并转发到后端,如果用户通过
https
形式访问,流量经过的流程是:用户端->负载80
端口->负载443
端口->服务端(k8s node
)的80
端口配置在后端,例如
Ingress
资源上,如果用户通过https
形式访问,流量经过的流程是:用户端->负载80
端口->服务端(k8s node
)的80
端口->服务端(k8s node
)的443
端口
但是为了获取用户的真实ip
,只能选择方式一,因为如果证书配置在后端服务,流量经过负载时是加密的,负载一般在没有证书的情况下,是无法对数据包进行解包操作透传用户ip
的.
第一种情况 我们可以在 F5 开启 XFF 将 x-original-forwarded-for
放入 HTTP 协议
第二种情况 我们在 Ingress
进行 Https
的校验,这就会有一个问题 因为 F5 没有证书就无法对包进行篡改添加 XFF
所以我们获取不到真实的内容
第三钟情况 我们将 HTTPS
的解析放置在 F5
中这样 F5
就可以进行拆包,给包中的内容添加一个 XFF
这样就可以获取到真实的 IP.
环境准备
一个能获取到当前 IP 或者消息头的软件 这里推荐 whoami https://hub.docker.com/r/containous/whoami
一个k8s
负载均衡器
F5 配置
应为我不是一个网络管理员所以这块内容不会.我让同事帮我开启了 F5 的 XFF 的透传
IngressController
Nginx
配置资料
吐槽下 我们购买了青云商业版本,提交了工单,青云工程师先直接扔给我了一个文档... 我会我就不提工单了兄弟...
https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/
data:
use-forwarded-headers: "true"
compute-full-forwarded-for: "true"
forwarded-for-header: "X-Forwarded-For"
use-forwarded-headers
如果为
true
,会将传入的X-Forwarded-*
头传递给upstreams
如果为
false
,会忽略传入的X-Forwarded-*
头,用看到的请求信息填充它们。如果直接暴露在互联网上,或者它在基于L3/packet-based load balancer
后面,并且不改变数据包中的源IP
时使用此选项forwarded-for-header
设置标头字段以标识客户端的原始
IP
地址。 默认: X-Forwarded-Forcompute-full-forwarded-for
将远程地址附加到
X-Forwarded-For
标头,而不是替换它。 启用此选项后,upstreams
应用程序将根据其自己的受信任代理列表提取客户端IP
未配置之前
Hostname: whoami-v1-778694b4f-jfz4h
IP: 127.0.0.1
IP: ::1
IP: 10.240.129.149
IP: fe80::9cfb:1aff:fe47:680a
RemoteAddr: 10.240.10.48:55950
GET / HTTP/1.1
Host: w.eternalcloud.cn
User-Agent: curl/8.7.1
Accept: */*
X-Forwarded-For: 10.240.156.0
X-Forwarded-Host: w.eternalcloud.cn
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Scheme: http
X-Real-Ip: 10.3.35.53
X-Request-Id: 5585aceba8bbf4dfc8d1c4707a9ec073
X-Scheme: http
配置完成后
Hostname: whoami-v1-778694b4f-jfz4h
IP: 127.0.0.1
IP: ::1
IP: 10.240.129.149
IP: fe80::9cfb:1aff:fe47:680a
RemoteAddr: 10.240.10.48:55950
GET / HTTP/1.1
Host: w.eternalcloud.cn
User-Agent: curl/8.7.1
Accept: */*
X-Forwarded-For: 10.3.35.53, 10.240.156.0
X-Forwarded-Host: w.eternalcloud.cn
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Scheme: http
X-Original-Forwarded-For: 10.3.35.53
X-Real-Ip: 10.3.35.53
X-Request-Id: 5585aceba8bbf4dfc8d1c4707a9ec073
X-Scheme: http
评论