Nginx: Mutual (Two way) SSL authentication for upstream HTTPS servers



Nginx  is a really good,  high performance reverse proxy server which supports Mutual Authentication  for incoming requests but doesn't support for upstream/backend servers.  In most of the deployments where nginx is used as a reverse proxy, it also acts as a SSL termination point where upstream requests are routed using either non SSL or one-way SSL connections.

Recently, I was working on a prototype to develop Api Gateway + reverse proxy which manages SSL certificates for different upstream backends and route incoming requests based on the routing rules. Some of the upstream backends expect to have their own certificates with mutual authentication.

After spending sometime on google search and seeing questions posted on stack overflow,  I realized that nginx doesn't support mutual/two-way authentications for upstreams so decided to implement support.  

I modified ngx_http_proxy_module.c to add following two new config parameters which allows to specify client certificate pem and client certificate key files. I have submitted my patch to nginx development community here

NOTE: Make sure you do not populate proxy_ssl_trusted_certificate.  As it is supported by nginx for upstream one way ssl, it takes preference over my config parameters.
 proxy_ssl_client_certificate  
 proxy_ssl_client_certificate_key  

1. Apply below patch to your Nginx source code and recompile.  I have verified this patch against nginx-1.4.7 
Download patch here

2.  Configure your nginx.conf as below.  See the comments for more details.

location /  
      {  
       default_type application/json;  
   
       #this enables client verification  
       proxy_ssl_verify on;  
       proxy_ssl_verify_depth 3;  
   
       #client certificate for upstream server  
       proxy_ssl_client_certificate /etc/upstream-a.pem;  
        
       #client key generated from upstream cert  
       proxy_ssl_client_certificate_key /etc/upstream-a.key;  
        
       #configure based on your security requirement  
       proxy_ssl_ciphers ALL;  
       proxy_ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;  
   
       #make sure to match the ssl server name from upstream server certificate   
       proxy_ssl_name "abc.company.com;  
       proxy_pass https://abc.company.com:9900;  
    }  

Hope this help.  Let me know if you have any questions.

2 comments:

Mark Kelly said...

Hi Joshi.

I'm interested in trying this patch. I understand I can apply the patch myself, but do you know if it's likely to make it into an nginx release at some point?

Thanks

Mark.

Rohit Joshi said...

Link for Patch: http://forum.nginx.org/read.php?29,252656,252657#msg-252657