引出问题
升级Kong版本到0.14.1,使用ip-restriction插件的白名单限制访问。但升级后的白名单没有生效。access日志如下:
相关概念
1、配置Kong的Nginx配置nginx-kong.conf查看两个host的含义:
proxy_http_version 1.1;
proxy_set_header Host $upstream_host;
proxy_set_header Upgrade $upstream_upgrade;
proxy_set_header Connection $upstream_connection;
proxy_set_header X-Forwarded-For $upstream_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $upstream_x_forwarded_proto;
proxy_set_header X-Forwarded-Host $upstream_x_forwarded_host;
proxy_set_header X-Forwarded-Port $upstream_x_forwarded_port;
proxy_set_header X-Real-IP $remote_addr;
remote_addr
从配置可以get到字眼X-Real-IP,那么很容易理解Nginx将HTTP请求的真实地址赋值给remote_addr
X-Forwarded-For
X-Forwarded-For的内容由「英文逗号 + 空格」隔开的多个部分组成, 例如:X-Forwarded-For: client, proxy1, proxy2,最开始的是离服务端最远的设备 IP,然后是每一级代理设备的 IP。如果一个HTTP请求到达服务器之前,经过三个代理,那么服务端收到X-Forwarded-For: client_ip, ip1, ip2,Proxy3表示它是在帮Proxy2转发请求。
2、ip-restriction插件的实现
function IpRestrictionHandler:access(conf)
IpRestrictionHandler.super.access(self)
local block = false
local binary_remote_addr = ngx.var.binary_remote_addr
if not binary_remote_addr then
return responses.send_HTTP_FORBIDDEN("Cannot identify the client IP address, unix domain sockets are not supported.")
end
if conf.blacklist and #conf.blacklist > 0 then
block = iputils.binip_in_cidrs(binary_remote_addr, cidr_cache(conf.blacklist))
end
if conf.whitelist and #conf.whitelist > 0 then
block = not iputils.binip_in_cidrs(binary_remote_addr, cidr_cache(conf.whitelist))
end
if block then
return responses.send_HTTP_FORBIDDEN("Your IP address is not allowed")
end
end
通过这句代码local binary_remote_addr = ngx.var.binary_remote_addr可以看出插件是拿remote_addr也就是真实的用户IP做限制的依据。
问题定位
remote_addr=[host1] http_x_forward=[host2] time=[04/Jul/2019:14:14:23 +0800] request=[GET /xxxx/xxx/ HTTP/1.1] status=[403] byte=[220] elapsed=[0.002] refer=[-] body=[-] ua=[-] cookie=[-] host=[host3] log_id=[-] consumer_id=[-] consumer_username=[-]trace_id=[-] spy_id=[-]upstream_response_time=[-] sent_http_set_cookie=[-]
通过access.log我们可以拿到
remote_addr客户端真实IP为host1,http_x_forward 请求代理设备的IP为host2。但在插件的白名单中并没有hout1,造成了请求被拒绝,报:{message: "Your IP address is not allowed"} http_status=403。
那么问题基本可以猜测是:新搭建的Kong获取的remote_addr不正确。
How to Forward Client's request IP
通过查找资料定位原因是:Nginx反向代理或者负载均衡时要设置的请求头[X-Forwarded-For]。所以log里的remote_addr=[host1]是个阿里云某个slb的地址。
解决方法
修改Kong的配置文件/etc/kong/kong.conf修改如下:
trusted_ips = 0.0.0.0/0,::/0
real_ip_header = X-Forwarded-For
trusted_ips从0.11以后,Kong默认不会信任来自任何源的请求头。real_ip_header反向代理或是负载均衡都会放在X-Forwarded-For中,最后只去第一项作为real_ip_header即可。