背景介绍
客户的一些业务场景需要明确服务的请求来源,需要准确获取和记录请求客户端的真实源IP。例如:安全团队需要对请求的来源进行审计及安全事件的处理,数据团队需要通过源IP做数据分析等。
结合客户在使用Amazon EKS过程中不同的工作场景,对各种获取源IP的实现方法进行总结,供大家参考。
具体场景
一、在“原生Kubernetes Service资源的配置选项”中保留客户端源IP。
Kubernetes依靠kube-proxy组件实现Service的通信与负载均衡。默认情况下Kube-proxy在做转发的时候会做一次SNAT(source network address translation),在这个过程中,由于使用了SNAT对源地址进行了转换,导致Pod中的服务拿不到真实的客户端IP地址信息。
如下图所示:
如果要启用保留客户IP功能,可以对Service对象中“externalTrafficPolicy”字段进行设置。
apiVersion: v1
kind: Service
metadata:
name: Test-Service
spec:
selector:
app: Test-Service
ports:
- port: 80
targetPort: 80
externalTrafficPolicy: Local
type: LoadBalancer #
ExternalTrafficPolic有两个选项值:Cluster(默认)和Local。Cluster模式下流量可以转发到其他节点上的Pod,Kube-proxy转发时会替换掉报文的源IP;Local模式下流量只发给本机的Pod,Kube-proxy转发时会保留源IP。
对比图如下:
虽然Local模式可以保留客户端源IP,但是在生产环境下,通常会有多个节点同时接收客户端的流量,如果使用Local模式,负载均衡可能就不是很好,因为一旦容器(pod)分布在多个节点上,它只转发给本机,不跨节点转发流量,这将会导致服务可访问性变低。
二、通过Amazon Application Load Balancer ingress->Service获取真实源IP。
Kubernetes Ingress是一种API对象,借助它可以管理对集群中运行的Kubernetes服务的外部(或)内部HTTP[s]访问,Amazon Elastic Load Balancing Application Load Balancer(Amazon ALB)是一个非常受欢迎的负载均衡服务,它可在应用程序层(第 7 层)跨一个区域的多个目标(例如Amazon EKS多个pod)调整传入流量的负载平衡。
Amazon Application Load Balancer负载均衡器(七层)默认会将客户端真实源IP放至HTTP Header的X-Forwarded-For和X-Real-IP字段中。后端应用通过获取HTTP Header中的X-Forwarded-For或X-Real-IP字段值就可以得到客户端真实源IP。例如:只需要在配置/etc/nginx/nginx.conf配置文件LogFormat部分中,添加$http_x_forwarded_for,类似于以下内容:
http {
...
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
...
}
左右滑动查看更多
三、通过Amazon NLB->Nginx Ingress-> Service访问获取真实IP。
Amazon ALB入口控制器非常优秀,但也有一些使用场景下更适合将Amazon NLB与Amazon NGINX入口控制器配合使用。Amazon NLB每秒能够处理数百万个请求,同时保持极低的延迟,因此非常适合TCP流量的负载均衡。Amazon NLB专为处理突增和波动流量模式而优化,同时每个可用区使用单个静态IP地址。Nginx Ingress可以自定义组件实现特定功能比如:限流,动静分离等。
具有TCP/SSL侦听器的四层负载均衡器Amazon Network Load Balancer,后端应用程序可以通过两种方式获取源IP。
(1) 通过启用Proxy Protocol v2来取得Client IP。
此方式需要在负载均衡器上启用代理协议版本2
https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#proxy-protocol
有关说明,请参阅启用代理协议
https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#enable-proxy-protocol
另外启用代理协议v2之前,请确保您的应用程序目标可以处理代理协议标头,否则您的应用程序可能会中断。
例如:Ningx需要更改server部分的listen行,以启用 proxy_protocol。确保更改http部分的log_format行,以设置proxy_protocol_addr:
http {
...
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$proxy_protocol_addr"';
access_log /var/log/nginx/access.log main;
...
}
server {
...
listen 80 default_server proxy_protocol;
...
}
...
}
左右滑动查看更多
(2)Amazon NLB现在已支持IP透传的模式,通过启用Client IP preservation,后端应用无需额外配置。也建议大家使用此种方式。
有关说明,请参阅客户端IP保留
https://docs.aws.amazon.com/zh_cn/elasticloadbalancing/latest/network/load-balancer-target-groups.html#target-group-attributes
注:在Amazon EKS环境下,Amazon NLB与Kubernetes Service和Ingress资源结合时,可以通过Amazon Load Balancer Controller自动创建Amazon NLB资源以及相应的Target Group。也可使用Amazon Load Balancer Controller中的新功能TargetGroupBinding,它允许客户在Amazon EKS集群之外自己创建和管理Amazon NLB和TargetGroup。通过TargetGroupBinding可以将Kubnernetes Service和指定的Target Group进行关联。
由于此内容不是本文的重点,本文不作过多介绍,详细内容请大家可以查看官方文档以及相关blog。
总结
Kubernetes原生的负载均衡机制以及相关集成的负载均衡组件Nginx、Amazon Network Load Balancer、Amazon Application Load Balancer等都使业务上获取客户源IP变的复杂,本文主要介绍了在Amazon EKS使用场景下服务端如何获取客户端真实源IP:
通过Service资源的配置选项保留客户端源IP,只需修改Kubernetes Service资源配置即可,但可能会存在潜在的Pods(Endpoints)流量负载不均衡风险;
在七层(HTTP/HTTPS)服务转发场景下,可以通过获取HTTP Header中X-Forwarded-For和X-Real-IP字段的值来获取客户端真实源IP;
在四层(tcp/udp)服务转发场景下,除了可以通过启用Proxy Protocol v2来获取客户端真实源IP外,Amazon NLB现在也支持IP透传的模式,不需要后端应用做额外配置就可以获取客户端真实源IP。
参考材料:
https://kubernetes.io/docs/concepts/services-networking/ingress/
https://kubernetes.io/zh/docs/tasks/access-application-cluster/create-external-load-balancer/
https://docs.aws.amazon.com/zh_cn/elasticloadbalancing/latest/network/load-balancer-target-groups.html#client-ip-preservation
https://aws.amazon.com/cn/premiumsupport/knowledge-center/elb-capture-client-ip-addresses/
https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html
本篇作者
梁战雷
亚马逊云科技解决方案架构师
具有超过13年的运维工作经验,在微服务,容器,Devops等云原生领域有丰富的项目落地实施经验,现在主要负责企业级客户的上云推广及支持工作。
崔志阳
首汽约车基础架构部运维工程师
主要负责ISSA层平台及云架构方面的设计与优化。在运维领域有多年的架构设计及运维经验,对Devops、服务网格、容器领域、云原生相关技术等有着深入的研究和热情。
听说,点完下面4个按钮
就不会碰到bug了!