0

I need some help in nginx.conf. I need to protect resources starting from /devices using client certificate authentication. The other resources are over https but don't need client certificate.

I installed nginx on ubuntu 16.04 using repository. Then I create a file called dozee.conf inside /etc/nginx/conf.d/ and pasted the content from an serverfault Q&A (https://serverfault.com/a/721704/80340) and modified it as required.

The configuration inside dozee.conf looks like

server {
  listen       *:443 ssl;
  server_name localhost;

  ssl on;
  ssl_certificate         /etc/nginx/server.crt;
  ssl_certificate_key     /etc/nginx/server.key;
  ssl_client_certificate  /etc/nginx/ca.crt;

  ssl_verify_client on;

  location /device {
    proxy_pass          http://localhost:8080/device;
    proxy_read_timeout  90;
    #proxy_redirect      http://localhost/ $scheme://$host:$server_port/;
  }
}

server {
  listen       *:443 ssl;

  ssl on;
  ssl_certificate         /etc/nginx/server.crt;
  ssl_certificate_key     /etc/nginx/server.key;
  ssl_client_certificate  /etc/nginx/ca.crt;

  ssl_verify_client off;

  location / {
    proxy_pass          http://localhost:8080/;
    proxy_read_timeout  90;
    #proxy_redirect      http://localhost/ $scheme://$host:$server_port/;
  }
}

The issue I am facing here is that the behaviour of the nginx is dominated by second server block.

If I change ssl_verify_client off; in second server block to ssl_verify_client on; both the paths / & /device start asking client certificate.

If I keeps ssl_verify_client as off none of them needs a client certificate.

What I am doing wrong here?

3

Your first server block matches only requests like https://localhost/some/url. All other requests are processed by the second server block.

However, it might be that nginx cannot be used for the use case you want. When the TLS connection is initialised, there is no information about the upper layer HTTP request for nginx to decide if it should require a client certificate from the client or not. It can only do this based on the virtual host name information, which is passed with SNI on the TLS connection setup.

In Apache, one can force a TLS re-negotiation based on the URL path, where Apache then requests a client certificate. I haven't found similar option in nginx.

Therefore your only option with nginx might be to use another virtual host (eg. devices.example.com) for your devices. And this is the actual solution that the answer had where you copy-pasted the configuration.

|improve this answer|||||
  • There may be the information about which host the client wants to talk with at the time of the SSL/TLS handshake if both parties support the so-called SNI extension for TLS. nginx appears to support it. @Mayank, Google for nginx+sni for more results. – kostix Sep 15 '17 at 14:12
  • The question states that one requires TLS client authentication for URL paths starting with /device, and other parts do not require authentication. Therefore the SNI mechanism doesn't help, which I already mentioned in my answer. – Tero Kilkanen Sep 15 '17 at 17:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.