I need to deny access to site for all, except number of subnets, where the frontend proxies are located. At the same time I need to set real IP for further processing. The diagram looks something like this:
Some infrastructure proxying traffic to nginx
________ ______________________________________________ _________________
| | | | | |
| Client |------>|public-allowed ingress IP egress IP's|<--------->| Nginx |
|________| |______________________________________________| |_________________|
Allowed access
for «egress IP's»
only.
First I tried next configuration (all IP's are for example only):
server {
server_name someserver.tld;
# Subnets where frontend proxies are located
allow 1.2.3.0/24;
allow 4.5.6.0/24;
allow 7.8.9.0/24;
# Deny access bypassing proxies
deny all;
set_real_ip_from 1.2.3.0/24;
set_real_ip_from 4.5.6.0/24;
set_real_ip_from 7.8.9.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
… skipped …
}
As expected that's wasn't working: nginx sets the client's real IP, then checks the conditions and denies access to site for everybody. So I tried next:
# This block is outside of «server» section, so I expect it will be processed first
geo $someserver_allow {
default 0;
1.2.3.0/24 1;
4.5.6.0/24 1;
7.8.9.0/24 1;
}
server {
server_name someserver.tld;
# Deny access bypassing proxies
if ($someserver_allow != 1) {
return 403 "Bypassing the frontend is not allowed.";
}
set_real_ip_from 1.2.3.0/24;
set_real_ip_from 4.5.6.0/24;
set_real_ip_from 7.8.9.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
… skipped …
}
I expected that nginx will process geo
instruction, setting the $someserverallow
ignoring real_ip_header
in server
section, but it seems that I was wrong. To be sure I commented out entire if
clause and added next lines right after the geo
section:
map $someserver_allow $downstream {
default $remote_addr;
}
And also added next in server section:
add_header X-Downstream-IP "$downstream"
Requesting the frontend server with my browser I got my own IP address in X-Downstream-IP
header, not the IP of proxy server.
So, what's wrong with my configuration or, maybe, with my understanding of that how nginx processes instructions?
CodePudding user response:
The realip module is convenient when working with Nginx behind a reverse proxy or load balancer. But it does redefine $remote_addr
which affects logging and the allow
directive amongst others.
You can use $realip_remote_addr
to get the address of your reverse proxy or load balancer.
You can test it using the geo
block in your question, just include that variable as the address parameter.
For example:
geo $realip_remote_addr $someserver_allow {
default 0;
1.2.3.0/24 1;
4.5.6.0/24 1;
7.8.9.0/24 1;
}