Provavelmente é mais fácil apenas mostrar por exemplo onde estou encontrando problemas, então vou direto ao ponto ...
Este snippet funcionará como está para Nginx com módulos de reescrita/autenticação ativados. Portanto, esperamos que esse problema seja rápido e fácil de reproduzir em praticamente qualquer instalação do Nginx ...
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/;
}
}
O exemplo de configuração do site Nginx acima faz o seguinte:
- Envia qualquer solicitação para
/auth
viaauth_request
chamada - O local /auth envia a solicitação para outro servidor que adiciona um cabeçalho
x-user bar
auth_request_set
define uma nova variável$foo
com base no valor do cabeçalho upstreamx-user
definido na etapa 2 acima.- Um novo cabeçalho é definido
x-test
com o valor de$foo
- A solicitação prossegue para um destino externo.
A resposta é exatamente como eu esperaria e confirmei que o $foo
var foi definido corretamente:
$ curl -s --head http://localhost:8080 | grep -E 'HTTP|x-test'
HTTP/1.1 200 OK
x-test: bar
Então, aí vem o problema...
Preciso ajustar essa configuração para que retorne 403 caso o valor do cabeçalho upstream esteja incorreto.
Parecia uma tarefa simples. Então adicionei uma if{}
condicional para verificar o cabeçalho:
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/;
}
A if
condicional foi avaliada como verdadeira, então obtive um 403, que não era o que eu esperava. Então, isso não funciona :
$ curl -s --head http://localhost:8080 | grep -E 'HTTP|x-test'
HTTP/1.1 403 Forbidden
Eu percebo que se é mau, no entanto, parece que estou usando apenas para retornar , o que deve estar ok. Estou aberto a usar qualquer método para atingir o mesmo objetivo - com ou sem if , então estou aberto a ideias!!
Eu tentei fazer coisas como mover as instruções auth_request
e/ou if
para o server{}
bloco, mas nada parece fazer com que isso seja avaliado da maneira que eu esperava.
Resolução de problemas / detalhes adicionais:
Eu verifiquei que o problema é que o if
é avaliado ANTES do auth_request_set
é
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
Eu verifiquei que isso não é um problema se usar set
em vez deauth_request_set
. Isso funciona (mas não atinge o objetivo):
# 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/;
}
Essa configuração funciona. set
é avaliado antes if
:
$ curl -s --head http://localhost:8080 | grep -E 'HTTP|x-test'
HTTP/1.1 200 OK
x-test: bar
O comportamento persiste mesmo se auth_request
estiver no server{}
contexto :
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
Analisei os seguintes documentos e perguntas:
- Posso comparar uma variável definida por auth_request_set depois que auth_request retornou no nginx?
- https://stackoverflow.com/questions/73431103/cant-access-added-headers-using-nginx-auth-request-set
- O cabeçalho personalizado Nginx $ upsteam_cache_status não aparecerá
- auth_request não bloqueia a diretiva de retorno, não pode retornar o 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/
O
if
é problemático, porque é uma construção imperativa em uma configuração declarativa.Portanto, nem sempre funciona como esperado. Mais informações podem ser encontradas no artigo IfIsEvil .
Nesse caso,
set
eauth_request_set
ocorrem em diferentes estágios do processamento da solicitação nginx, e oif
processamento ocorre entre esses dois estágios.Infelizmente, não sei como fazer o que você deseja no nginx. Talvez isso precise ser feito no servidor upstream para o qual você faz proxy da solicitação.
Isso não responde à pergunta, veja a resposta de Tero aqui para a resposta real (spoiler:
if
é verdadeiramente mau, mesmo se for usado comreturn
).No entanto, como uma resposta funcional fornecendo uma solução alternativa: Aqui está pelo menos uma maneira de fazer com que solicitações invalidadas sejam enviadas como 403. O ponto de extremidade proxy_pass é dinâmico, dependendo do cabeçalho testado. Isso parece resolver o caso de uso ...