It's probably easiest to just show by example where I'm hitting issues, so I'll jump right in...
This snippet will work as-is for Nginx with rewrite/auth modules enabled. So hopefully this issue is quick & easy reproduce on pretty much any Nginx install...
server {
listen 8081;
add_header x-user bar;
return 200;
}
server {
listen 8080;
location = /auth {
internal;
proxy_pass http://localhost:8081;
}
location / {
auth_request /auth;
auth_request_set $foo $upstream_http_x_user;
add_header x-test $foo;
add_header success true;
proxy_pass http://example.com/;
}
}
The above example Nginx site config does the following:
- Sends any request to
/auth
via anauth_request
call - The /auth location sends the request to another server which adds a header
x-user bar
auth_request_set
sets a new var$foo
based on the upstream header value ofx-user
set in step 2 above.- A new header is set
x-test
which is set to the value of$foo
- The request proceededs to an external destination.
Response is exactly how I would expect, and confirmed the $foo
var was set correctly:
$ curl -s --head http://localhost:8080 | grep -E 'HTTP|x-test'
HTTP/1.1 200 OK
x-test: bar
So, here comes the problem...
I need to adjust this config so that it'll return 403 if the value of the upstream header is incorrect.
Seemed like a simple task. So I added an if{}
conditional to check the header:
location / {
auth_request /auth;
auth_request_set $foo $upstream_http_x_user;
# this 'if' is the only part added to the original config
if ($foo != bar) {
return 403;
}
add_header x-test $foo;
add_header success true;
proxy_pass http://example.com/;
}
The if
conditional evaluated true so I got a 403, which is not what I was expecting. So, this does not work:
$ curl -s --head http://localhost:8080 | grep -E 'HTTP|x-test'
HTTP/1.1 403 Forbidden
I realize that if is evil however I seem to be using it just to return which should be ok. I'm open to using any method to accomplish the same goal - with or without if, so I'm open to ideas!!
I have tried doing things like moving the auth_request
and/or the if
statements into the server{}
block but nothing seems to make this evaluate the way I was expecting.
Further Troubleshooting / Details:
I have verified the problem is that the if
is evaluated BEFORE the auth_request_set
is
location / {
auth_request /auth;
auth_request_set $foo $upstream_http_x_user;
if ($foo != bar) {
# x-test never gets set because $foo is null when if evaluates
add_header x-test $foo always;
add_header success false always;
return 403;
}
add_header x-test $foo;
add_header success true;
proxy_pass http://example.com/;
}
$ curl -s --head http://localhost:8080 | grep -E 'HTTP|x-test|success'
HTTP/1.1 403 Forbidden
success: false
I have verified this is not an issue if using set
instead of auth_request_set
. This works (but doesn't accomplish the goal):
# set works, but not auth_request_set
location / {
set $foo bar;
if ($foo != bar) {
return 403;
}
add_header x-test $foo;
add_header success true;
proxy_pass http://example.com/;
}
This config works. set
is evaluated before if
:
$ curl -s --head http://localhost:8080 | grep -E 'HTTP|x-test'
HTTP/1.1 200 OK
x-test: bar
The behavior persists even if the auth_request
is in the server{}
context:
server {
listen 8081;
add_header x-user bar;
return 200;
}
server {
listen 8080;
auth_request /auth;
auth_request_set $foo $upstream_http_x_user;
location = /auth {
internal;
proxy_pass http://localhost:8081;
}
location / {
if ($foo != bar) {
return 403;
}
add_header x-test $foo;
add_header success true;
proxy_pass http://example.com/;
}
}
$ curl -s --head http://localhost:8080 | grep -E 'HTTP|x-test|success'
HTTP/1.1 403 Forbidden
success: false
I've reviewed the following docs and questions:
- Can I compare a variable set by auth_request_set after the auth_request has returned in nginx?
- https://stackoverflow.com/questions/73431103/cant-access-added-headers-using-nginx-auth-request-set
- Nginx $upsteam_cache_status custom header will not appear
- auth_request doesn't block return directive, can't return status?
- https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil
- http://nginx.org/en/docs/http/ngx_http_auth_request_module.html
- http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#if
- https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
auth_request
in theserver
context?auth_request
andauth_request_set
in server context, and a mix with onlyauth_request
in server andauth_request_set
in location. All return 403 every time.