------> 课程视频同步分享在今日头条和B站
大家好,我是博哥爱运维。
这节课带大家探索并分享最全面的解决在使用Kubernetes(K8s)和Ingress-Nginx-Controller中无法获取客户端真实IP问题的视频教程,帮助你快速理解并解决这一问题。
如果我们按下面网络架构图,暴露我们服务到公网上提供访问,那么此时我们后端的业务服务POD获取真实IP是没什么问题的,但种形式的网络架构直接暴露出我们源站的公网IP信息到互联网上,无疑于是在公网上裸奔,一旦遭受攻击,对我们的业务服务将是毁灭性的打击。
那么我们会去寻求一些大型提供公网网络防护的企业的帮助,购买他们的安全服务,如动态加速线路、WAF、或者高防线路,这个时候,我们的业务在公网上提供由于可以相对更安全了,但此时会带来另外一个问题,就是我们后端服务获取的客户端IP,都是安全服务提供商的代理IP了。
那么我们怎么解决这个问题,获取到真实CLIENT客户端的IP地址呢,在ingress-nginx控制器上配置其实也不难,加入下面三行配置即可解决:
# kubectl -n kube-system edit configmaps nginx-configuration
apiVersion: v1
data:
......
compute-full-forwarded-for: "true"
forwarded-for-header: "X-Forwarded-For"
use-forwarded-headers: "true"
我们来看看这三行配置的详细含义:
compute-full-forwarded-for
: 将 remote address 附加到 X-Forwarded-For Header而不是替换它。当启用此选项后端应用程序负责根据自己的受信任代理列表排除并提取客户端 IP。
forwarded-for-header
: 设置用于标识客户端的原始 IP 地址的 Header 字段。默认值X-Forwarded-For
,此处由于A10带入的是自定义记录IP的Header,所以此处填入是X_FORWARDED_FOR
use-forwarded-headers
: 如果设置为True时,则将设定的X-Forwarded-*
Header传递给后端, 当Ingress在L7 代理/负载均衡器
之后使用此选项。如果设置为 false 时,则会忽略传入的X-Forwarded-*
Header, 当 Ingress 直接暴露在互联网或者 L3/数据包的负载均衡器后面,并且不会更改数据包中的源 IP请使用此选项。
OK,到这里,大家是不是以为万事大吉了,NONONO,这个时候,其实还存在一个安全隐患是我们必须要提前知道的。
我们先来准备部署一个测试服务,用来模拟后端服务POD,并且能获取ingress-nginx传回来的请求头部信息打印出来,以便我们更直观的观察测试的详细情况
---
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: traefik/whoami:v1.10
imagePullPolicy: Always
name: whoami
ports:
- containerPort: 80
name: 80tcp02
protocol: TCP
dnsPolicy: ClusterFirst
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
labels:
app: whoami
name: whoami
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: whoami
sessionAffinity: None
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
nginx.ingress.kubernetes.io/whitelist-source-range: 10.0.1.201/32 # 只允许信任IP访问,其他返回403
nginx.ingress.kubernetes.io/configuration-snippet: | # 加入自定义头部,保存remote_addr信息
proxy_set_header X-Custom-Real-IP $remote_addr;
name: whoami
spec:
rules:
- host: whoami.boge.com
http:
paths:
- backend:
service:
name: whoami
port:
number: 80
path: /
pathType: ImplementationSpecific
tls:
- hosts:
- whoami.boge.com
secretName: boge-com-tls
上面可以看到,我们对于whoami加入了访问限制,只允许出口IP为10.0.1.201这个地址来访问,其他全部拒绝返回403
curl -H "Host: whoami.boge.com" -s http://10.0.1.201
在201这台节点上请求是正常的
root@node-1:~# curl -H "Host: whoami.boge.com" -s http://10.0.1.201
Hostname: whoami-6cf6989d4c-7hrxz
IP: 127.0.0.1
IP: ::1
IP: 172.20.217.124
IP: fe80::383a:48ff:fe1e:e1e5
RemoteAddr: 172.20.84.128:5110
GET / HTTP/1.1
Host: whoami.boge.com
User-Agent: curl/7.81.0
Accept: */*
X-Custom-Real-Ip: 10.0.1.201
X-Forwarded-For: 10.0.1.201
X-Forwarded-Host: whoami.boge.com
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Scheme: http
X-Real-Ip: 10.0.1.201
X-Request-Id: 5b90653f94b45c1fa20ab038ff294534
X-Scheme: http
我们来到202这台节点请求看看,正常是会返回403拒绝请求的
root@node-2:~# curl -H "Host: whoami.boge.com" -s http://10.0.1.201
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>
但这个时候,我们在请求头部传入伪造的XFF信息,再看结果呢
curl -H "X-Forwarded-For: 10.0.1.201" " -H "Host: whoami.boge.com" -s http://10.0.1.201
这里我们可以看到我们通过伪造XFF,成功绕过了服务的安全访问限制。
root@node-2:~# curl -H "X-Forwarded-For: 10.0.1.201" -H "boge: test" -H "Host: whoami.boge.com" -s http://10.0.1.201
Hostname: whoami-6cf6989d4c-7hrxz
IP: 127.0.0.1
IP: ::1
IP: 172.20.217.124
IP: fe80::383a:48ff:fe1e:e1e5
RemoteAddr: 172.20.84.128:5110
GET / HTTP/1.1
Host: whoami.boge.com
User-Agent: curl/7.81.0
Accept: */*
Boge: test
X-Custom-Real-Ip: 10.0.1.201
X-Forwarded-For: 10.0.1.201, 10.0.1.202
X-Forwarded-Host: whoami.boge.com
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Scheme: http
X-Original-Forwarded-For: 10.0.1.201
X-Real-Ip: 10.0.1.201
X-Request-Id: 81ce680afd34390c7936b72ac0e5c105
X-Scheme: http
解决这个也不复杂,就是我们就对请求到ingress-nginx控制器的来源IP作信任加白处理,只允许信任的IP段传来的XFF等信息。
但要注意的是,对于提供安全的厂商来说,他们的出口IP信息会经常变化的,意味着一旦变化,那么获取客户端真实IP又会存在问题。我们在加这个信任配置的时候,需要根据实际情况来作考量要不要添加,其实只要我们不暴露限制的IP信息,通常情况下还是相对安全的
proxy-real-ip-cidr: 10.0.1.201/32,10.0.1.203/32
加了信任IP配置后,再请求就没有安全问题了
root@node-2:~# curl -H "X-Forwarded-For: 10.0.1.201" -H "boge: test" -H "Host: whoami.boge.com" -s http://10.0.1.201
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>