Nginx proxy to back-end with SSL client certificate authentication

Is it sufficient to have the client certificate details passed through?

You can add

proxy_set_header X-SSL-CERT $ssl_client_escaped_cert;

to your config and then the certificate info is available to server B via a X-SSL-Cert header.


Apparently, this is what you are looking for: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ssl_certificate Available since version 1.7.8.

location / {
    ...
    proxy_pass     the_other_nginx;
    proxy_ssl_certificate  the_certificate.pem;
    ...
}

The issue seems to be largely version dependend. On Ubuntu 14.04 LTS the default nginx is an outdated 1.4. First you need to install a PPA based version

https://leftshift.io/upgrading-nginx-to-the-latest-version-on-ubuntu-servers

shows how to do this with:

sudo add-apt-repository ppa:nginx/stable
sudo aptitude safe-upgrade

you should end up with:

nginx -v
nginx version: nginx/1.8.0

The configuration from @xatr0z answer https://serverfault.com/a/636455/162693 pointing to http://www.senginx.org/en/index.php/Proxy_HTTPS_Client_Certificate does not work:

non-working proposal

backend {
    server some-ip:443;
}

server {
    listen 80;


    location / {
        proxy_ssl_certificate        certs/client.crt;
        proxy_ssl_certificate_key    certs/client.key;


        proxy_pass https://backend;
    }
}

does not work out of the box with 1.8.0. It's probably meant as a hint only and not to be used as a configuration file as such or depends on another version.

I am testing with a apache2 based backend server A with SSL and self-signed client certificates enabled. The Apache config SSLOptions are set to:

SSLOptions +ExportCertData +FakeBasicAuth + StdEnvVars

This makes debugging the situation easier since a phpinfo() script on the backend side will show the Server and Client Side information.

To verify this i used:

https://backend/test/phpinfo

with the SSL certificate installed in the browser and I get sections like: SSL_SERVER_S_DN_CN for the server certificate and SSL_CLIENT_S_DN_CN for the client certificate.

As a first start I used (fill in the parts in brackets) to configure nginx on the frontend server B:

server {
  listen 8080;
  server_name <frontend>;

  location / {
    proxy_buffering off;
    proxy_pass https://<backend>;
    #proxy_ssl_certificate      certs/<SSL Client Certificate>.crt;
    #proxy_ssl_certificate_key  certs/<SSL Client Certificate>.key;
  }
}

uncomenting the SSL Client Certificate specific part just to check that the reverse proxy itself works.

nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
service nginx restart
nginx stop/waiting
nginx start/running, process 8931

Now http://frontend:8080/test/phpinfo.php works The

SSL_SERVER_S_DN_CN for the server certificate is displayed and SSL_CLIENT_S_DN_CN for the client certificate is not (yet) displayed

Now after uncommenting:

server {
  listen 8080;
  server_name <frontend>;

  location / {
    proxy_buffering off;
    proxy_pass https://<backend>;
    proxy_ssl_certificate      certs/<SSL Client Certificate>.crt;
    proxy_ssl_certificate_key  certs/<SSL Client Certificate>.key;
  }
}

and checking/restarting

nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
service nginx restart
nginx stop/waiting
nginx start/running, process 8931

http://frontend:8080/test/phpinfo.php works and

SSL_SERVER_S_DN_CN for the server certificate is displayed and SSL_CLIENT_S_DN_CN for the client certificate is displayed

so now we got things working as asked for.

Please note bug https://trac.nginx.org/nginx/ticket/872#ticket