Apache reverse proxy with self-signed certificate

I run a Unifi hardware appliance which comes with a self-signed certificate, issued on unifi.local. For my current setup, it's not an option to import a certificate on the appliance directly for several reasons, so I tried to get rid of the invalid certificate message of my browser by using an apache2-based reverse proxy which provides access to the appliance under another domain, secured by a Letsencrypt certificate.

My current setup looks like the following:

Laptop <-> Apache Reverse Proxy (2.4.48, Debian, trusted wildcard domain certificate) <-> Unifi appliance (self-signed certificate)

My idea is to provide a secured domain called unifi.mydomain.tld which allows secure access to the appliance.

In my apache reverse proxy, I created and enabled a config file which looks like following:

<IfModule mod_ssl.c>
<VirtualHost *:443>
    Serveradmin [email protected]"
    ServerName unifi.mydomain.tld

    SSLProxyEngine On
    SSLProxyVerify none
    SSLProxyCheckPeerCN off
    SSLProxyCheckPeerName off
    SSLProxyCheckPeerExpire off

    ProxyPass "/" "https://10.0.1.1/"
    ProxyPassReverse "/" "https://10.0.1.1/"
    ProxyPreserveHost Off

    TransferLog /var/log/apache2/proxies/unifi_access.log
    ErrorLog /var/log/apache2/proxies/unifi_error.log

    <IfModule mod_headers.c>
        Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains; preload"
    </IfModule>

    SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 +TLSv1.2
    SSLCipherSuite SSL ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384
    SSLCipherSuite TLSv1.3 TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
    SSLOpenSSLConfCmd DHParameters /mnt/certificates/diffie-hellman/dhparam4096.pem
    SSLHonorCipherOrder on
    SSLCompression off
    SSLSessionTickets off

    SSLCertificateFile /etc/letsencrypt/live/mydomain.tld/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/mydomain.tld/privkey.pem
</VirtualHost>

# Originally from /etc/letsencrypt/options-ssl-apache.conf
# Written directly here because otherwise SSLProtocol etc is overwritten
# Add vhost name to log entries:
SSLOptions +StrictRequire
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined
LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common

</IfModule>

However, if I access unifi.mydomain.tld, my browser returns the certificate for unifi.local and not for unifi.mydomain.tld and hence, it creates an error that the certificate is not trusted. Several tips mentioned to turn SSLProxyVerify to none, and SSLProxyCheckPeerName, SSLProxyCheckPeerCN, and SSLProxyCheckPeerExpire to off, however, none of these tricks worked. It's not an option for me to import Unifi's self-signed snakeoil certificate on my reverse proxy server.

I'm not sure whether apache2 itself complains about the certificate or returns the wrong certificate. How am I able to get access to the appliance by browsing unifi.mydomain.tld without getting this certificate error?


Solution 1:

This worked for me!

Requirements:

  1. Apache Tomcat on :8443 with self-signed key
  2. Apache HTTPD with Reverse Proxy to localhost:8443 Tomcat
  3. Apache HTTPD REQUIRES Client Mutual Authentication. If that is not a requirement for you, then set: SSLVerifyClient none
  4. Apache HTTPD will pass along the X.509 identity of the caller through the reverse proxy to tomcat.



 ErrorLog logs/ssl_error_log
 TransferLog logs/ssl_access_log
 LogLevel warn
 ProxyRequests On
 ProxyPass /test1 https://localhost:8443/test/
 ProxyPassReverse /test1 https://localhost:8443/test/
# SSL Settings for the DMZ
 SSLEngine on
 SSLProtocol TLSv1.2
 SSLCipherSuite HIGH:!aNULL:!MD5:!SEED:!IDEA
 SSLCertificateKeyFile /home/jdoyle/sample_httpd_server_example_root_ca_.key
 SSLCertificateFile /home/jdoyle/sample_httpd_server_example_root_ca_.cer
 SSLCACertificateFile /home/jdoyle/consolidated_cacerts.cer
# SSL Settings for the Reverse Proxy
 SSLProxyEngine on
 SSLProxyVerify require
 SSLProxyProtocol TLSv1.2
 SSLProxyCheckPeerName off
 SSLProxyCACertificateFile /home/jdoyle/consolidated_cacerts.cer
 SSLVerifyClient require
 SSLVerifyDepth  10
# Pass the SSL Conext on to tomcat

RequestHeader set SSL_CLIENT_S_DN "%{SSL_CLIENT_S_DN}s"
RequestHeader set SSL_CLIENT_I_DN "%{SSL_CLIENT_I_DN}s"
RequestHeader set SSL_SERVER_S_DN_OU "%{SSL_SERVER_S_DN_OU}s"
RequestHeader set SSL_CLIENT_VERIFY "%{SSL_CLIENT_VERIFY}s"
RequestHeader set SSL_CLIENT_V_START "%{SSL_CLIENT_V_START}s"
RequestHeader set SSL_CLIENT_V_END "%{SSL_CLIENT_V_END}s"
RequestHeader set SSL_CLIENT_M_VERSION "%{SSL_CLIENT_M_VERSION}s"
RequestHeader set SSL_CLIENT_M_SERIAL "%{SSL_CLIENT_M_SERIAL}s"
RequestHeader set SSL_CLIENT_VERIFY "%{SSL_CLIENT_VERIFY}s"
RequestHeader set SSL_SERVER_M_VERSION "%{SSL_SERVER_M_VERSION}s"
RequestHeader set SSL_SERVER_I_DN "%{SSL_SERVER_I_DN}s"
....

SSLOptions +ExportCertData +StrictRequire
....




Notes:

a. SSLProxyCACertificateFile is for the httpd<->tomcat connection and contains the Public Key of the Tomcat Server's self-signed cert.

b. SSLCACertificateFile is for the DMZ <-> httpd connection, and must contain and and all of the CA Certs for any inbound connection.