Opened 3 years ago
Last modified 10 months ago
#2350 new enhancement
Option to have set_real_ip_from use the proxied client ip when using proxy protocol.
Reported by: | Owned by: | ||
---|---|---|---|
Priority: | minor | Milestone: | |
Component: | documentation | Version: | 1.19.x |
Keywords: | Cc: | ||
uname -a: | Linux ingress-ingress-nginx-controller-5d794cbf68-qck52 5.10.0-0.bpo.9-amd64 #1 SMP Debian 5.10.70-1~bpo10+1 (2021-10-10) x86_64 Linux | ||
nginx -V: | nginx/1.19.10 |
Description
I'm running nginx on kubernetes in the following configuration:
client -> cloudflare -> load balancer -> nginx ingress -> service
My load balancer runs the proxy protocol and sends traffic to nginx which is on a private network. I'd like trust the X-Forwarded-From header from Cloudflare, but I can't configure that because "set_real_ip_from" refers to the IP of the incoming connection to nginx from my load balancer. When I set "set_real_ip_from" to my private network, which the load balancer is on, ngx_http_realip_module trusts the X-Forwarded-From headers sent to it by my load balancer, which could be coming from anywhere, so it's very easily spoofable.
I'd like the option for "set_real_ip_from" to check the IP of the request forwarded to nginx when using the proxy protocol.
Change History (7)
comment:1 by , 3 years ago
comment:2 by , 3 years ago
That does appear to work! I spent a silly amount of time trying for figure this out. Thanks for the workaround :D
comment:3 by , 3 years ago
On further inspection, the workaround doesn't appear to be working. I might have mistaken the Cloudflare edge server IP for my own.
As far as I understand set_real_ip_from your.balancer.ip;
means it trust whatever real_ip_header
is set to be the real ip if it comes from my load balancer. So this won't do much because all traffic comes from the load balancer. Then real_ip_header proxy_protocol
sets the $remote_addr
to the one seen by the load balancer thats running the PROXY protocol. Then proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for
appends $remote_addr
to the X-Forwarded-For
header. So when I'm behind Cloudflare, this would be the edge server IP address, which is what I'm seeing.
comment:4 by , 3 years ago
On the backend server you have to use real_ip_recursive and appropriate set_real_ip_from
(with your intermediate proxy IP, your balancer IP, and Cloudflare IPs) to make sure nginx will look through multiple addresses.
comment:6 by , 15 months ago
I came here from #2524. It would be extremely useful to be able to use variables in real IP module, like "real_ip_variable $fixed_cloudfront_viewer_address". And "real_ip_header" is just a short/faster way to do "real_ip_variable $http_xxxxx".
Then the below example would sort out CloudFront viewer addresses, and similar could sort out any other header or source.
map $http_cloudfront_viewer_address $fixed_cloudfront_viewer_address { "~^([0-9a-fA-F:]+):([0-9]+)$" "[$1]:$2"; default $http_cloudfront_viewer_address; } real_ip_from_variable $fixed_cloudfront_viewer_address;
As far as I understand your use case, you need to set real IP from two sources:
set_real_ip_from your.balancer.ip; real_ip_header proxy_protocol;
.As of now, nginx only accepts a single source of addresses: either an HTTP header, or PROXY protocol. A quick workaround would to be use additional proxying to provide appropriate header: something like
set_real_ip_from your.balancer.ip; real_ip_header proxy_protocol;
withproxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
should do the trick. Obviously enough, this is not an optimal solution though.A better solution might be to teach the realip module to accept variables, so it would be possible to set something like
"$http_x_forwarded_for, $proxy_protocol_addr"
as an address source.