LetsEncrypt certificate on backend server using NS reverse proxy

Hi all,

I was wondering if the following may be of some interest in Community; I plan to partially implement it and was wondering if there is some interest or there are better ways that I did not take in consideration.

Scenario: Customer with a single public IP address; little or no control over public DNS records (just adding some A records manually if needed) but complete control on local DNS infrastructure; you need to publish multiple HTTPS services from outside, and make them valid also on the LAN side (so self-signed certificates are not accepted in LAN). Inside the LAN, we prefer the backend services to be reachable by their local addresses (via routing) instead of being proxied. FQDN of the single service should be the same both internally (from LAN) and from outside (from WAN).

Discussion: the actual implementation of the Reverse Proxy module already permits to expose from the outside multiple protected services, but LetsEncrypt certificates are to be requested for all the services on the reverse proxy host. Plus, if you want to reach backend services via routing (not proxying) from the LAN you may get a self-signed certificate. Obviously, wildcard LE certificates are excluded in my perspective, as they require an advanced and automatizable way to interact with the DNS servers.

Let’s try to explain better the scenario with an example.

The reverse proxy FQDN is proxy.example.com (192.168.1.1); we need to expose also webmail.example.com (e.g. https://192.168.1.2/), www.example.com (https://192.168.1.3/) and connect.example.com (https://192.168.1.4/) with these names both internally and on the WAN side. We set up the five DNS A records to point to the single public IP, then portforwarding ports TCP/80 and TCP/443 to 192.168.1.1 from your firewall (optionally, you may skip this if proxy.example.com is your firewall :slight_smile: ). Internally you may setup a split-DNS records on the local DNS server for the five FQDNs to point to the relative local IP addresses.

The actual implementation requires to request and obtain a single LE certificate for the five FQDNs on the proxy, then configure four reverse proxy vhost with the same certificate exposed. On the cons, the LE certificate is unique for the four FQDNs (which is not bad per se) but it is usable only on the proxy host: you may copy over the certificate (and the private key) from proxy.example.com to the other servers, but it may be difficult to use the certificate on the single service (I don’t think this is possible, for example, if webmail.example.com should provide a Webtop5 instance on a NS). Also adding/removing a service from certificate requires to renew the certificate for all the services, even if it is quite simple to do.

Proposed implementation: let each backend service request its own LE certificate, perusing its machinery (it is very simple for example with NS). The reverse proxy will forward LE requests to the single backend (if configured so; default behavior will not change and you may have some reverse proxy configuration working with the actual implementation and some with the proposed one) to allow releasing of the certificate on the backends. Once released from LetsEncrypt, a specific post renewal hook will copy back the certificate (and private key, unfortunately) to the proxy, so it can be configured as certificate assigned to the single vhost inside the reverse proxy.

Following with our example, there are now four different LE certificates (five if you consider the one already on proxy.example.com for this FQDN), one per backend service, and they are all copied over to proxy.example.com, so it can use them to secure outside connections to the relative services. Each renewal is independent and you may dismiss a service removing (or disabling) the reverse proxy configuration and shutting down the backend service. Activating a new service is a little more complex: set up an insecure/self-signed reverse proxy configuration, let the backend service request and obtain the LE certificate, then re-configure the reverse proxy to use the newly copied-over certificate.

If someone else like the proposal, I do not plan to release a Cockpit interface for it, since it would be relatively complex to code (it has some challenges, though, for a non developer) but much more complex to communicate and to use; I think some explanations on the wiki and some good old e-smith commands may do for most of the advanced users.

What do you think about it? Am I missing something (from security/scalability/whatever point of view)?

Sorry for the long post :worried:

There’s already a simple way to do this with Nethserver:
https://wiki.nethserver.org/doku.php?id=userguide:let_s_encrypt_acme-dns

This will make it easy to get a wildcard cert for your Nethserver, and also easy to get by-name individual certs for all your local/private devices without needing to copy anything back from the Nethserver to those devices.

2 Likes

Something is missing in my mind to make this part work, but I will put up some tests for your proposal soon.

Thanks for the suggestion.

In short, you run ACME clients on your LAN resources that know how to talk to acme-dns. This is what I’m doing–I’m running acme-dns on my Neth server. The Neth server itself uses that to obtain its own certs (yes, it could do HTTP validation since it’s acting as a web server anyway, but it’s using the DNS method, following the instructions I put on the wiki). My pfSense router has built-in support for Let’s Encrypt, and for acme-dns–it gets its own certs and doesn’t need to be accessible from outside the network. My FreeNAS boxen use acme.sh, with a script I wrote to deploy the script to the FreeNAS UI using its API. My Ubiquiti CloudKey does something similar. As long as you can put a shell script on the device, it can probably run acme.sh, and therefore work with acme-dns.