0

Consider nginx's parameters proxy_ssl_verify and proxy_ssl_trusted_certificate that are used to secure the communication to an upstream server.

# downstream server: nginx.conf

stream {
  server {
    # ...

    proxy_ssl on;
    proxy_ssl_verify on;

    proxy_ssl_trusted_certificate /etc/nginx/ssl/upstream.example.com/chain.pem;
    proxy_ssl_verify_depth 2;

  }
}

I was under the impression that, for proxy_ssl on, nginx would verify the certificate sent by the upstream server (upstream.example.com) against the proxy_ssl_trusted_certificate.

However, I've encountered a problem where nginx can't establish a secure connection to the upstream server and reports an upstream SSL certificate verify error: (2:unable to get issuer certificate) while SSL handshaking to upstream, while verifying the certificate with openssl does work.

# fullchain.pem: certificate sent by the upstream server
# chain.pem: CA certificate for `proxy_ssl_trusted_certificate`

# openssl verify -CAfile chain.pem fullchain.pem
fullchain.pem: OK

This made me wonder how nginx actually does the verification. Is there a way to reproduce this in isolation in order to debug why the error would occur?

Documentation

https://nginx.org/en/docs/http/ngx_http_proxy_module.html

proxy_ssl_verify on | off;

Enables or disables verification of the proxied HTTPS server certificate.

proxy_ssl_verify_depth number;

Sets the verification depth in the proxied HTTPS server certificates chain.

proxy_ssl_trusted_certificate file;

pecifies a file with trusted CA certificates in the PEM format used to verify the certificate of the proxied HTTPS server.

fiedl
  • 115
  • 1
  • 1
  • 6

1 Answers1

5

As the documentation says, proxy_ssl_trusted_certificate expects the CA certificate(s) to be used to verify the upstream server's TLS certificate. You seem to have provided that upstream server's TLS certificate chain. Provide the CA certificate(s) instead.

Michael Hampton
  • 244,070
  • 43
  • 506
  • 972
  • Are you sure this is not a naming-convention issue? As far as I understand, `chain.pem` contains letsencrypt's CA (intermediate) certificate. (https://crypto.stackexchange.com/q/87205/86946). To be sure, I've verified that the issue does occur against `lets-encrypt-r3.pem` from https://letsencrypt.org/certificates/. Or is the CA certificate something different than that? Sorry, to be honest, I'm not sure that I don't confuse something here. Anyway, my question is more about how nginx does verify the certificate, and how to debug this process. Thanks! – fiedl Feb 09 '21 at 16:18
  • @fiedl The certificate chain used by a web server includes the server certificate and intermediate certificates. It is _not_ supposed to include the CA certificate. This is supplied by the client, whether it be a web browser, a command such as `curl`, or in this case nginx. So, again, you need to use the CA certificate instead. You could supply it explicitly, or just point it at the CA certificate bundle provided by your OS distribution. – Michael Hampton Feb 09 '21 at 17:21
  • Thank you, @Michael Hampton! I was under the impression that letsencrypt's intermediate certificate serves the role of the CA certificate here. Thank you for your help. including the downstream server's CA certificate (`proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;`) does resolve the configuration issue. Do you know how nginx verifies the certificates? (Why and how does the verification succeed with `openssl verify`, but does not succeed with nginx?) – fiedl Feb 09 '21 at 21:00
  • 1
    @fiedl `openssl verify` had the CA certificate already; nginx did not until you told it where to find it. – Michael Hampton Feb 09 '21 at 21:11