Using NGINX Reverse Proxy for client certificate authentication - start discussion

First we need install and configure Nginx according to page: https://docs.openhab.org/installation/security.html

To require client certificate we need two more options:

ssl_client_certificate
ssl_verify_client

More info http://nginx.org/en/docs/http/ngx_http_ssl_module.html

Now our configuraion can be as:

server {
    listen                          80;
    server_name                     mydomain_or_myip;
    location / {
       return 301                      https://$server_name$request_uri;
    }

    #### When using Let's Encrypt Only ####
    location /.well-known/acme-challenge/ {
        root                             /var/www/mydomain;
    }

}
server {
    listen                          443 ssl;
    server_name                     mydomain_or_myip;

    ssl_certificate                 /etc/letsencrypt/live/mydomain/fullchain.pem; # or /etc/ssl/openhab.crt
    ssl_certificate_key             /etc/letsencrypt/live/mydomain/privkey.pem;   # or /etc/ssl/openhab.key
    
    ssl_client_certificate          /etc/nginx/Client-CA.pem; # trusted CA used to issuing client certs
    ssl_verify_client                on;
    
    add_header                      Strict-Transport-Security "max-age=31536000"; # Remove if using self-signed and are having trouble.

    location / {
        proxy_pass                              http://localhost:8080/;
        proxy_set_header Host                   $http_host;
        proxy_set_header X-Real-IP              $remote_addr;
        proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto      $scheme;
        satisfy                                 any;
        allow                                   192.168.0.1/24;
        allow                                   127.0.0.1;
        deny                                    all;
        auth_basic                              "Username and Password Required";
        auth_basic_user_file                    /etc/nginx/.htpasswd;
    }
}

So configuring nginix for requireing client certificate is easy.

Now we need Client-CA.pem and certificates for each client.

There are many tutorials how to manage simple PKI.
There are also many opensource software which support this.
Some examples: https://en.wikipedia.org/wiki/Public_key_infrastructure#Open_source_implementations
I use http://hohnstaedt.de/xca/ is very easy.

Last step is install client certificate in our device.
In simply way we need pkcs#12 file with client certificate. We copy it to phone and we can instll it during OpenHub configurations.

So as we see it is not only nginx configurations, more works is with certificate management.

5 Likes

Hi

Thanks, ive managed to get this working on my device.

thanks

Many thanks for this tutorial Slawomir!
Got everything running along with an SSL-Labs A rating of my OpenHAB installation at home.
I think I am finally ready to migrate from Fibaro HC2 to OpenHAB.
Cheers!

How does the Let’s Encrypt certbot renewal work with this? It doesn’t have the client certificate. Do you temporarily disable the client certificate to allow for renewal? Or use some other method?

Also, you also have auth_basic enabled. Why is that? I thought the point of the client certificate validation is that you don’t need it. Or do you want another layer of protection?

Thanks

Let’s Encrypt use port 80 for domain validation, as we can read in certbot documentation.

We should well-nown location in server on port 80.

The example in the openHAB docs here has a redirect to the https port. Doesn’t that include the certbot domain validation? Wouldn’t that have a problem for the acme challenge? Or do you have the port 80 block configured differently than this example?

server {
    listen                          80;
    server_name                     mydomain_or_myip;
    return 301                      https://$server_name$request_uri;
}

According to ACME specification Let’s Encrypt, use port 80 for HTTP-01 challenge.

Probably Let’s Encrypt work ok because follow redirect, so both configuration will be ok.

In this post question was, how to work with Let’s Encrypt and client certificate. So we simply use port 80 for Let’s Encrypt and port 443 for our rest comunication.

More:


Sorry, I misread the original post and somehow thought the acme-challenge was in the original place. I agree that it will work where it is. And I agree that port 80 should be open. But even the page you quoted says all port 80 requests should be redirected to port 443. Anyway, I was thinking that something like this might work in the 443 server. Make the authentication be optional, and check it in the / block. There is no check for the acme-challenge location.

    # client certificate
    ssl_client_certificate /etc/nginx/client_certs/ca.crt;
    ssl_verify_client optional;

    location / {
      # if the client-side certificate failed to authenticate, show a 403
      # message to the client
      if ($ssl_client_verify != SUCCESS) {
        return 403;
      }

Any comments on this? I know “if” has a bad reputation with nginx, but they do seem say this usage type is okay. Maybe this is no better than the original.

Also, I am curious as to why you use basic authentication as well as the client certificate. Just for extra security?

thanks

Hello, thank you for the post. I am actually having a blocking problem. I configured my nginx server to use self signed certificates and added the virtual server to handle my clients https requests. However I would like to allow only a list of known clients to call my endpoints. I have the clients certificates and I imported to my Ubuntu. However when I add my client crt certificate to the ssl_client_certificate, restar my nginx and try to access using the pfx Client certificate I am having a 400 bad request. Any idea ? Thank you