Home > Software engineering >  Nginx fully open cors with basic authentication without if
Nginx fully open cors with basic authentication without if

Time:05-11

This came up from time here and there but no question properly covers this use case.

The relevant section of http:

    map $http_origin $origin_with_default {
        default '*';
        ~. $http_origin;
    }
    map $request_method $es_target {
        default '';
        POST 'search';
        GET 'search';
        HEAD 'search';
        OPTIONS 'options';
    }
    root         /app;

The relevant section of server:

server {
  location ~* /(.*)/_search {
    limit_except OPTIONS {
      auth_basic "Read Users";
      auth_basic_user_file /etc/nginx/htpasswd_read;
    }
    rewrite ^ /internal/$es_target;
  }
  location /internal {
    return 405;
  }
  location /internal/search/ {
    internal;
    proxy_pass http://elasticsearch/;
    proxy_http_version 1.1;
    proxy_set_header Connection "Keep-Alive";
    proxy_set_header Proxy-Connection "Keep-Alive";

    proxy_hide_header Access-Control-Allow-Origin;
    proxy_hide_header Access-Control-Allow-Credentials;
    proxy_hide_header Access-Control-Allow-Headers;
    proxy_hide_header Access-Control-Allow-Credentials;

    include "cors.headers";
  }
  location /internal/options {
    internal;
    add_header 'Content-Type' 'text/plain; charset=utf-8';
    add_header 'Content-Length' 0;
    add_header 'Access-Control-Max-Age' 1728000;
    include "cors.headers";
    return 204;
  }
}

Finally, the cors.headers file:

add_header Access-Control-Allow-Credentials "true" always;
add_header Access-Control-Allow-Origin $origin_with_default always;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS' always;
add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
  1. POST https://example.com/index_name/_search gives 401. This is as expected.
  2. OPTIONS https://example.com/index_name/_search returns the options headers. This is also as expected.
  3. However, POST https://u:[email protected]/index_name/_search gives a 404 and the server log contains open() "/app/index_name/_search" failed (2: No such file or directory),. Before I added the rewrite ^ /internal/$es_target; and the location /internal/search/ section, when the proxy_pass was just after limit_except inside location ~* /(.*)/_search { it did work. Because of 1) and 2) I believe the rewrite and the location matching works. But why does it try to serve a file instead of doing a proxy pass?

CodePudding user response:

Here's a working config. It needed limit_except removed, every location switched to regex matching consuming everything -- and the last location being last is important to be so otherwise it gets into a rewrite loop. The "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" part of the rewrite module is not something I was able to get working.

We still need the http section:

    map $http_origin $origin_with_default {
        default '*';
        ~. $http_origin;
    }
    map $request_method $es_target {
        default 'invalid';
        POST 'search';
        GET 'search';
        HEAD 'search';
        OPTIONS 'options';
    }

And then comes server

server {
  location ~ /internal/search/(?<search>.*) {
    internal;
    auth_basic "Read Users";
    auth_basic_user_file /etc/nginx/htpasswd_read;
    proxy_pass http://elasticsearch/$search;
    proxy_http_version 1.1;
    proxy_set_header Connection "Keep-Alive";
    proxy_set_header Proxy-Connection "Keep-Alive";

    proxy_hide_header Access-Control-Allow-Origin;
    proxy_hide_header Access-Control-Allow-Credentials;
    proxy_hide_header Access-Control-Allow-Headers;
    proxy_hide_header Access-Control-Allow-Credentials;

    include "cors.headers";
  }
  location ~ /internal/options {
    internal;
    add_header 'Content-Type' 'text/plain; charset=utf-8';
    add_header 'Content-Length' 0;
    add_header 'Access-Control-Max-Age' 1728000;
    include "cors.headers";
    return 204;
  }
  location ~ /internal/invalid {
    return 405;
  }
  location ~* /_search$ {
    rewrite (.*) /internal/$es_target$1;
  }
}
  • Related