1

I have spring boot application running on port 8081 on localhost. I am running HTTPS using a self signed certificate.

First, I have created a ca certificate using OpenSSL.

openssl req \
  -new \
  -x509 \
  -nodes \
  -newkey rsa:2048\
  -days 365 \
  -subj '/CN=bcc' \
  -keyout ca.key \
  -out ca.crt

I have generated certificate for spring boot and nginx server using this ca certificate.


## Using this certificate for spring boot

openssl genrsa \
  -out server.key 2048

openssl req \
  -new \
  -key server.key \
  -subj '/CN=bcc-ca-website.org' \
  -out server.csr

openssl x509 \
  -req \
  -in server.csr \
  -CA ca.crt \
  -CAkey ca.key \
  -CAcreateserial \
  -days 365 \
  -extfile v3.ext \
  -out server.crt

## Using this certificate for nginx server

openssl genrsa \
  -out nginx-server.key 2048

openssl req \
  -new \
  -key nginx-server.key \
  -subj '/CN=bcc-ca-website.org' \
  -out nginx-server.csr

openssl x509 \
  -req \
  -in nginx-server.csr \
  -CA ca.crt \
  -CAkey ca.key \
  -CAcreateserial \
  -days 365 \
  -extfile v3.ext \
  -out nginx-server.crt

Here is my application.yml

server:  
  port: 8081  
  ssl:  
    enabled: true  
    key-store: "classpath:server.p12"  
    key-store-password: 123456  
    key-store-type: PKCS12  
    client-auth: need  
    enabled-protocols: TLSv1.2  
  
    trust-store: "classpath:server.p12"  
    trust-store-type: pkcs12  
    trust-store-password: 123456  

Note that, I am using client MTLS authentication and created client CA and certifcates using openssl in the same way.

So, I need to use nginx using passthrough mode, so that the ssl connections is to made to the spring boot server. Here is my sites-available/default


upstream node_basic {
    server                  localhost:8081;

}

server {
    listen                  80;

    location / {
        return              301 https://$host$request_uri;
    }
}

server {
    listen                  443 ssl;

    ssl_certificate         /etc/ssl/nginx-server.crt;
    ssl_certificate_key     /etc/ssl/nginx-server.key;
    ssl_protocols           TLSv1.2 TLSv1.3;
    ssl_ciphers             HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers  on;
    ssl_session_cache    shared:SSL:10m; # a 1mb cache can hold about 4000 sessions, so we can hold 40000 sessions
    ssl_session_timeout  24h;

    location / {
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_set_header X-NginX-Proxy true;

        proxy_pass           https://node_basic;
    }
}


But, I am getting error:

2023/02/02 11:37:51 [error] 22475#22475: *1 SSL_do_handshake() failed (SSL: error:0A000412:SSL routines::sslv3 alert bad certificate:SSL alert number 42) while SSL handshaking to upstream, client: 127.0.0.1, server: , request: "GET / HTTP/1.1", upstream: "https://127.0.0.1:8081/", host: "bcc-ca-website.org"
desertSniper87
  • 795
  • 2
  • 13
  • 25
  • 1
    You're NOT doing ssl passthrough. You're telling nginx to terminate the SSL/TLS connection from the client, receive (decrypt) the HTTP request, then forward the HTTP request to the backend on a _separate_ SSL/TLS connection which doesn't (and really can't) do client-auth and thus the backend app rejects it. For passthrough you need to use `stream` and then you can't do any HTTP-level `X-forwarded` functionality; the backend will see all requests as coming 'from' nginx, but with cert(s) from the client(s). – dave_thompson_085 Feb 02 '23 at 08:33
  • 1
    See e.g. https://stackoverflow.com/questions/38371840/ssl-pass-through-in-nginx-reverse-proxy https://stackoverflow.com/questions/59624481/reverse-proxy-with-nginx-ssl-passthrough https://stackoverflow.com/questions/59652707/how-to-configure-ssl-passthrough-on-nginx-where-the-nginx-reverse-proxy-is-intro https://stackoverflow.com/questions/34741571/nginx-tcp-forwarding-based-on-hostname/ – dave_thompson_085 Feb 02 '23 at 08:35

1 Answers1

0

As @dev_thompson_085 suggested, I configured nginx as a reverse stream proxy . Changed /etc/nginx/nginx.conf and added this after http block.

stream {
    upstream spring-boot {
        server localhost:8081;
    }
    server {
        listen 443;
        proxy_pass spring-boot;
    }
} 

In this way, nginx can pass through incoming request to spring boot encrypted.

desertSniper87
  • 795
  • 2
  • 13
  • 25