Search code examples
djangonginxproxyreverse-proxynginx-reverse-proxy

Trouble with ProxyPass of REMOTE_USER from nginx to Django


I have an nginx web server that's configured with client certificate authentication. Once authenticated, I proxy requests to a uWSGI Django application server. I've set-up my Django application to perform authentication using REMOTE_USER (https://docs.djangoproject.com/en/3.1/howto/auth-remote-user/), however it doesn't seem to be working as I receive the "'AnonymousUser' object is not iterable" error from Django.

I'm assuming that I'm missing something in my nginx configuration:

server {
  listen 80;
  server_name my.website.net;
  return 301 https://$server_name$request_uri;
}
server {
  listen 443 ssl;
  ssl_certificate /etc/letsencrypt/live/my.website.net/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/my.website.net/privkey.pem;
  ssl_verify_client on;
  ssl_verify_depth 2;
  ssl_client_certificate /etc/nginx/ssl/cas.pem;
  proxy_set_header X-SSL-Client-Serial $ssl_client_serial;
  proxy_set_header X-SSL-Client-Verify $ssl_client_verify;
  proxy_set_header X-SSL-Client-S-DN   $ssl_client_s_dn;
  proxy_set_header X-Remote-User $remote_user;
  proxy_set_header REMOTE_USER $remote_user;

  location / {
    root /var/www/my.website.net;
    index index.html index.htm;
  }

  location /django {
    proxy_set_header Host 10.101.10.228;
    proxy_http_version 1.1;
    proxy_set_header Connection "Keep-Alive";
    proxy_set_header Proxy-Connection "Keep-Alive";

    proxy_pass http://10.101.10.228:8000/webapp;
    proxy_redirect http://10.101.10.228/django/ https://my.website.net/django/;

  }

}

I've also tried utilizing the nginx uwsgi_* directives with no luck:

upstream django {
  server 10.101.10.228:8000;
}
location /django {
  include         uwsgi_params;
  uwsgi_pass django;
  uwsgi_param SCRIPT_NAME /webapp;
  uwsgi_param REMOTE_USER $remote_user;
  uwsgi_param X-REMOTE-USER $remote_user;
}

Is there something that appears to be missing?


Solution

  • The $remote_user nginx variable is being populated only for HTTP Basic Authentication. You can rely on $ssl_client_s_dn variable to use the client DN as the username:

    proxy_set_header Remote_User $ssl_client_s_dn;
    

    or

    uwsgi_param REMOTE_USER $ssl_client_s_dn;
    

    You can use the map block to retreive only some specific field from the client DN, for example to get the CN (canonical name) only:

    map $ssl_client_s_dn $remote_user_cn {
        ~,CN=(?<CN>[^,]+) $CN;
    }
    

    and then use the $remote_user_cn variable as the username.