How to send variable with auth_request in nginx? - nginx

I'm trying to send a variable via the auth_request directive so that I can then use the variable for the actual authorization. I'm trying to do it with a GET request, but if other methods work that is fine. It will also work if there is a way to reference the auth_request. I'm trying to create one location that can verify every app instead of a different location for each app.
auth_request /auth?app=myapp;
...
location /auth {
internal;
proxy_pass http://127.0.0.1:8000/portal/auth?PASS_GET_VARIABLE;
}

Turns out the variable app=myapp is already being passed. The way to do this is with a rewrite and changing the proxy_pass URI.
auth_request /auth?app=myapp;
location /auth {
internal;
rewrite ^/auth(.*) /portal/auth$1;
proxy_pass http://127.0.0.1:8000;
}
If no URI is specified, the location match is passed as the URI. So in this example, /auth?app=myapp would get changed to /portal/auth?app=myapp, and it would be passed along.

Related

Replicate proxy_pass location behavior with variables

So usually when creating a nginx location it would look something like this:
location /foo/ {
proxy_pass http://example.com/;
}
With this setup, requests to /foo/bar are forwarded to http://example.com/bar which is the intended behavior.
However when trying to prevent caching of the domain name example.com or when trying to prevent nginx from crashing if the upstream host is unavailable at startup the only solution seems to be to not use the target directly in the proxy_pass directive, but to instead create a variable containing the target like this:
location /foo/ {
set $targetUri http://example.com/;
proxy_pass $targetUri;
}
But this totally changes the setup. As soon as proxy_pass contains a variable, it no longer appends anything to the target uri, as the nginx docs describe:
When variables are used in proxy_pass [...]. In this case, if URI is specified in the directive, it is passed to the server as is, replacing the original request URI.
So requests to /foo/bar are simply forwarded to http://example.com/.
When bringing $request_uri into the mix, more than what we want is appended:
location /foo/ {
set $targetUri http://example.com$request_uri;
proxy_pass $targetUri;
}
Requests to /foo/bar are now forwarded to http://example.com/foo/bar.
The only workaround I have found is to resort to regex patterns for the location:
location ~ ^/foo/(.*)$ {
set $targetUri http://example.com/$1$is_args$args;
proxy_pass $targetUri;
}
Is there any way to replicate the behavior of proxy_pass when using variables without having to regex-match the location? The reason I want to avoid regex is because the location path is based on a user input from which the location block is generated.
Remove the trailing / from your $targetUri variable so that proxy_pass does not have the "optional URI" part in its value. Then use rewrite...break to duplicate the original behaviour.
For example:
location /foo/ {
set $targetUri http://example.com;
rewrite ^/foo(.*)$ $1 break;
proxy_pass $targetUri;
}

Add a custom header while redirecting in NGINX

I am trying to redirect all API calls to an authorization service endpoint using nginx. I will need to pass a custom header in which i intend to pass the original uri or $request_uri.
Trying the below:
location /api/other {`
add_header X-Original_URI $request_uri
return 308 https://example.com/myauthservice/api/authorize
}
unfortunately the header is not getting added, need some help to see if this is correct way to do.
I tried auth_request module, proxy_pass. auth_request I cannot use, as it cannot send $request_body. Followed this, but not able store or capture the $request_body.
proxy_pass I am not able to use as it ends up like this:
https://myauthservice/api/authorize/createuser
where createuser is from https://example.com/api/other/createuser
You can prevent appending the /createuser suffix to the proxied request. As the proxy_pass documentation states:
In some cases, the part of a request URI to be replaced cannot be determined:
...
When the URI is changed inside a proxied location using the rewrite directive, and this same configuration will be used to process a request (break):
location /name/ {
rewrite /name/([^/]+) /users?name=$1 break;
proxy_pass http://127.0.0.1;
}
In this case, the URI specified in the directive is ignored and the full changed request URI is passed to the server.
Try the following location block:
location /api/other {
rewrite ^ /myauthservice/api/authorize break;
proxy_set_header X-Original_URI $request_uri;
proxy_pass https://example.com;
}

How does nginx proxy pass works for nested paths?

I'm try to send the following over to a different node with the nested path
server_name http://cloudflare.myserver.com
location /api/client {
proxy_pass http://cloudflare.anotherserver.com
}
How can I forward the request
http://cloudflare.myserver.com/api/client/users/1
to
http://cloudflare.anotherserver.com/users/1
notice the users/1 needed to be forwarded also.
As per the docs:
If the proxy_pass directive is specified with a URI, then when a
request is passed to the server, the part of a normalized request URI
matching the location is replaced by a URI specified in the directive
So your location block needs to look like this:
location /api/client/ {
proxy_pass http://cloudflare.anotherserver.com/;
}

How do you send an auth_request to a variable URI in nginx?

I am trying to use the auth_request module to check whether a user is allowed to access a certain file. The user posts the request at /my/download/uri/<File ID>. I want the authorisation request to be posted at auth_service:9999/files/<File ID>. The relevant part of my config is as follows:
location /my/download/uri {
auth_request /auth/files/$uri;
alias /my/file/directory;
}
location /auth {
internal;
proxy_pass http://auth_service:9999/;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
}
The request is received by the authorisation service, but at literally /files/$uri; the variable is not placed. I have tried getting the URI ready via a set variable first, but to no avail. How can I get nginx to properly direct the authorisation request?
(Note: I am aware I can include the original request in the header of the authorisation request via X-Original-URI. However, this would mean I have to do additional processing of the full URI on the authorisation server to get the relevant data, which I would rather not do if there is a way to post the authorisation request to the correct URI in the first place.)
You cant use variables in auth_request this is apparently a design choice for nginx
https://trac.nginx.org/nginx/ticket/761
I came up with this through trial and error. I had trouble putting $uri in a variable, not sure why.
location ~ /my/download/uri/(.*) {
set $key $1
auth_request /auth;
alias /my/file/directory;
}
location /auth {
internal;
proxy_pass http://auth_service:9999/$key;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
}

Nginx - how to return a proxy generated file?

Description:
I want to implement an http server (using nginx) that serves static files.
If the requested file doesn't exist, nginx shall send a request to a service (REST API) that will create the file and return its path.
After that, I want nginx to return the static file that was created.
Question:
What is the best way to return the file after its creation?
So far I managed to do this by changing the REST API in order to return the created file path with the 302 status code and with a location header as a redirect, but I am not sure if this is a good thing to do. Is it?
Is there any nginx-side solution for this? Do I have to create a custom module?
Conf file:
http {
server {
listen 80;
location /files {
try_files $uri #rest;
}
location #rest {
rewrite ^(.*)$ /api/ break;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://localhost:8080;
}
}
}
Edit: Actually, on balance, this should be even simpler:
location #rest {
...
proxy_intercept_errors on;
error_page 404 = $uri;
}
Configure the named location to intercept an "error" coming back (I chose 404), and then using the error_page directive will cause the given URI to be loaded again. Since the file now exists, the request should succeed.
Side note: I had thought try_files $uri #rest $uri would have worked, but an internal redirection only happens for the last argument.
The simplest option here is probably for your REST service to use X-Sendfile/X-Accel to return the relevant URI that Nginx should serve once the file is created. Your REST service could return the target URI using the header X-Accel-Redirect.
In your case, your API could actually just return the same URI it received as the X-Accel-Redirect header, and then Nginx would re-use the same location block and find the file for the subrequest occurring.
If this fails, however, using an internal Nginx location as per the examples at http://wiki.nginx.org/XSendfile and http://wiki.nginx.org/X-accel:
location /files-protected {
internal;
root /path/to/files;
}
and returning the relevant URI to that would also work.

Resources