Search code examples
apachesessionnginxcloudant

reverse proxy with a connection pool using a custom session endpoint?


I'm currently using nginx as a proxy to provide connection pooling to a backend database service that uses basic HTTP authentication on connections:

user www-data;
worker_processes 4;
pid /var/run/nginx.pid;

events {
    worker_connections 10000;
}

http {
  client_max_body_size 0;
  sendfile        on;

  upstream cloudant_backend {
    server <hostname>.cloudant.com:443;
    keepalive 64;
  }

  server {
    listen       5984;
    server_name  localhost;

    location / {
      proxy_pass https://cloudant_backend;
      proxy_redirect off;
      proxy_http_version 1.1;
      proxy_set_header Connection "";
      proxy_set_header Host <hostname>.cloudant.com;
      proxy_set_header Authorization "Basic <base64encodedusernamepassword>";
    }
  }
}

Original Source of nginx.conf: https://github.com/greenmangaming/cloudant-nginx

However, there is more efficient option for authenticating with the backend by performing a HTTP POST to /_session endpoint to retrieve an authentication cookie that is reused on subsequent requests.

Question: Is this possible with nginx or Apache httpd? If so, how?


Solution

  • One possible solution may look like this:

    1. Obtaining the cookie is moved to a separate utility run by cron and configured either via crontab or at. The former method should be used if the cloudant server always use certain session longevity, the latter is better for dynamic "current session ends in minutes/hours/days". The program can be written in your favorite programming language, I would take Perl with Libwww or Python with http.client module. The goal of the program is to make a login request to the server, receive the result, extract the Set-Cookie header, and store its value to a file in a nginx configuration format. The configuration sets a dedicated variable to the cookie value.

    2. nginx is configured so that the generated file is included as a part of configuration, via include directive into the server context.

    3. Now the auth cookie may be used in the proxy configuration with

      proxy_set_header Cookie $auth_cookie;

    Once the cookie is renewed the authenticating program should send HUP signal to make it reload the configuration.

    Another possible problem/task to elaborate is how to react in cases when the session expires unexpectedly (e.g. due to the cloudant server reload). To solve it I would setup a simple FastCGI like this, which would trigger an unscheduled run of the authentication program, and then setup this CGI as a [next proxy upstream]. Probably the CGI should also perform the original request to make the whole execution chain be completely transparent to your server clients.

    And yet another problem with automatic renewal is a possible race condition when may clients sends requests to your server while it doesn't a valid authentication cookie. Right now it seems unavoidable to me that the CGI would have to implement some sort of locking (a file lock on the generated configuration file or main nginx configuration file? not sure yet) to prevent obtaining the cookie multiple times simultaneously.

    The proposed approach would allow you to build the whole solution without need of altering the nginx soruces itself. Alternatively if you don't mind against writing nginx modules the solution may be moved into a custom module, but certainly it would require much more care to develop and debug it.

    The code for the proposed solution is trivial enough but if you have questions for a specific part, I can provide some examples and code snippets.