29

I have two servers, both have nginx. Server A is listening to 443 and is configured to authenticate with a Client SSL certificate.

Server B has an internal process that needs to communicate to Server A through nginx.

I'd like to configure Nginx on server B that will listen to 8080 (no encryption, since it's all local communication) and proxy_pass to ServerA:443.

The question is how do I inject a Client Certificate ? I didn't found any proxy_xxxx function that would do that.

I do know how to make an equivalent to that with socat, but my requirement is to use nginx.

3
  • 2
    Looking at the directives in the proxy module of nginx, it seems it is not possible to make a nginx server to use a cert to authenticate: nginx.org/en/docs/http/ngx_http_proxy_module.html Apache does support that feature, though. Commented Aug 20, 2014 at 19:43
  • That's what I was afraid of... any idea if there's a custom module or something that can make this work ? That kind of feature has to exist ! Commented Aug 21, 2014 at 12:49
  • I have found a utility to migrate config files from apache to nginx (github.com/nhnc-nginx/apache2nginx), so I downloaded it, created a dummy apache.conf and pass it through the tool, but I've got this result: ### Section 2: Unconverted directives ### # Flag Description # [S] Unsupported directives. # In conf file: dummy.conf # Line 32: SSLProxyMachineCertificateFile /path/to/cert (mod_ssl.c) # [S] SSLProxyMachineCertificateFile: No relevant directive in Nginx. Commented Aug 21, 2014 at 15:21

4 Answers 4

35

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.

6
  • 1
    As comented here, be aware if your backend can replace \t with \n from this header once readed. Commented Jun 22, 2016 at 13:01
  • 8
    According to nginx's documentation, the $ssl_client_cert variable is deprecated; the$ssl_client_escaped_cert variable should be used instead. Commented Apr 1, 2018 at 8:36
  • 2
    @dubek good catch, I would update the answer directly in cases like this. Commented Apr 1, 2018 at 14:40
  • I've been trying this solution, but it only seems to be passing the cert through if certificate validation is set ON. I don't want to turn it on, is there a way to make it work without setting the validation on? Commented Oct 16, 2019 at 11:58
  • @juhako I am having the same issue... I want Nginx to pass down the certificate information, but I dont want to turn on the ssl_verify_client (or put it as optional).... This is driving me crazy Commented Oct 8, 2020 at 9:32
9

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

2
  • You might want to watch out for the renegotiating issue ruby-forum.com/topic/6875137 which might spoil the show Commented Jan 5, 2016 at 19:28
  • This worked perfectly. Thx Commented Nov 25, 2024 at 17:41
6

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; ... } 
4
  • 1
    This is wrong. This assigns a client cert to the proxy to be used for the requests to the backend. But the asked, said that this communication is unencrypted an local only, so there is no client certificate checking. The answer of jwilkins works well. Commented Sep 10, 2015 at 7:01
  • 1
    @KenyakornKetsombut I believe you misread the question. Server B has no encryption (listening on 8080) but has to communicate to server A (listening on 443, with encryption). So B need to send the client cert to A to authenticate. You can use proxy_ssl_certificate to accomplish that. jwilkins answer, will forward to A the cert given to B. Both may work depending on what you need. Commented Sep 17, 2015 at 16:47
  • Hi Nicolas. I was trying to say: if Server B is not using encryption (on port 8080) it does not use any thing like HTTPS/SSL or however you call it. Client certificates are a part of SSL, so this part can't be done by Server B. B cannot send or receive any client certificate. Commented Sep 18, 2015 at 3:33
  • 1
    I get nginx: [emerg] no "proxy_ssl_certificate_key" is defined for certificate "certs/Roro_Client.pem" nginx: configuration file /etc/nginx/nginx.conf test failed when I try this with 1.8.0 Commented Jan 5, 2016 at 10:00
0

There's quite a neat article on nginx and SSL client certificates; it uses PHP with FastCGI as the example but I'm think you can be adapt that to a reverse proxy setup:

server { listen 443; ssl on; server_name example.com; ssl_certificate /etc/nginx/certs/server.crt; ssl_certificate_key /etc/nginx/certs/server.key; ssl_client_certificate /etc/nginx/certs/ca.crt; ssl_verify_client optional; location / { root /var/www/example.com/html; fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME /var/www/example.com/lib/Request.class.php; fastcgi_param VERIFIED $ssl_client_verify; fastcgi_param DN $ssl_client_s_dn; include fastcgi_params; } } 

Source http://nategood.com/client-side-certificate-authentication-in-ngi

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.