Trusted Self-Signed Certificates for variable IP addresses

My team has modules which will ultimately be used to host their own web apps. Without going into too much detail, you can think of them as IoT devices hosting a Blazor web app. We are using SSL encryption, and have self-signed our certificates for testing. However, this gives us a certificate warning in Chrome and Edge at least- "Your connection is not private, attackers might be trying to steal your information from 192.168.1.101" for instance.
In the research we've done, it seems like you generally need to prove that you own a domain and then a CA will issue you a certificate and gain trust that way. In our case, though, we'll only have an IP address. Is there a way we can make this warning go away? In our set up, the host IP address can change potentially frequently depending on the DHCP settings and even with static IP addresses, they can be changed arbitrarily by the end-user. So we would need an automated solution to re-sign a trusted certificate.
I've looked into Let's Encrypt/CertBot and while they seem promising, I wanted to know if something like this is possible or if we're just barking up the wrong tree?

There is, but self-signed certs isn't the way to do it. What you want to do is set up an internal CA, trust that CA on any relevant devices, and then issue certs from that CA. Here's one way you can do it:

And of course, it doesn't have to be a Raspberry Pi; the software will run under your Linux flavor of choice. I've been running one of these at home for a while, and it works very well.

7 Likes

Thanks for the prompt response! We wouldn't be able to use a Yubi-key, but conceptually I think that approach makes sense, and it seems like there are alternatives to that approach. Getting all of our users to trust the CA could be a challenge- potentially dozens of different users would be exposed to the web app via cell phone. Can you think of an approach that minimizes that hurdle? Again, thank you very much for your time.

1 Like

Both the Yubi-Key and the hardware RNG are optional, but I like the way they're used in that system--essentially a poor man's HSM. But I'd understood this was something for internal use, which is where an internal CA would kind of make sense. If outside users were accessing via an app, it'd be easy enough to include your root CA cert in that app. But if the objective is that J. Random User will be able to pull out his cell phone and access the web UI of your device via HTTPS, that's kind of a different scenario than I'd envisioned.

I know Plex was able to make this work, but I don't recall exactly how--might want to Google around, because I know I've seen articles describing it in some detail.

5 Likes

No CA will issue you a certificate for a private IP.

You should use some kind of domain, it would make things a lot easier. Ie 127.1.2.3 becomes 127-1-2-3.nodes.example.com

Because the first won't get a certificate, the second it can and with a wildcard cert for *.nodes.example.com (if you don't put dots in the string which translates to the IP)

4 Likes

I like the idea, but I'm not sure how I'd go about it- as far as I can tell, the only way to register a domain is to go through a registrar, correct? But I can see how I'd do a wildcard cert with a domain like that.

You can use a wildcard with 127-1-2-3.nodes.example.com but not with 3.2.1.127.nodes.example.com

4 Likes

Plex, and other vendors, typically implement a variation on the following:

They set up their own internal DNS server. The apps/devices connect to the Vendor (Plex) Cloud system with information on their device and internal ip, usually it's a serial or mac address or something. The Cloud system then edits/updates their DNS entry for the device and provisions them a certificate if needed. SSL communications then get routed to the device through the public hostname.

The general logic is:

  • Device tells cloud "My internal IP is 192.168.1.18; my unique id is foobarbiz".
  • Cloud sets a DNS record of 192-168-1-18.foobarbiz.vendor.com resolving to 192.168.1.18, sends SSL cert if needed
  • All communication goes through 192-168-1-18.foobarbiz.vendor.com, which resolves to the lan address
9 Likes

Interesting solution- I can see it working, but would I be able to do it without access to the Cloud? If I understand correctly, I should be able to set up a mini-DNS server right on the module, and handle the domains there. Does that sound right?

Potentially. It's exponentially harder.

The "module" would need to have it's own IP maintained in public DNS, and then be used to obtain certificates from an ACME server -- which means answering HTTP-01 or DNS-01 challenges. There's a lot of configuration involved, and many places for things to go wrong.

I should ask - how many "modules" are you talking about? Is this a small number of things used by your team for internal stuff and you can manage their info, or are you planning to sell the modules?

If it's just internal usage and you can control the public DNS and firewall for these things, you could install acme-dns on them -- or just use http-01 challenges. If these things are being shipped to others, coordinating everything with a cloud service is the only sane option.

6 Likes

I should have put the above in some context: the ACME protocol enables automated SSL certificate provisioning. LetsEncrypt has implemented ACME by supporting three challenges - HTTP-01, DNS-01, TLS-ALPN-01 - all of which require proving the requesting entity controls a domain. With HTTP-01 and TLS-ALPN-01, the webserver will be queried directly; with DNS-01, the domain's authoritative nameservers will be queried.

All methods require having a HTTP, TLS-ALPN or DNS service available on the public internet during the certificate provisioning process. Device and App developers have found it MUCH easier to coordinate all of the ACME stuff in the cloud. People with complex organizational networking setups have often found using DNS-01 challenge easier, and often delegate their "_acme_challenge' records to a dedicated acme-dns server (https://github.com/joohoi/acme-dns - an API based dns server designed specifically for LetsEncrypt/ACME challenges)

7 Likes

We are planning on selling these modules, so we wouldn't have a lot of control over downstream IT, and, to make things worse, many of our customers are Cloud-averse. Worse, there could be multiple modules on the same network, which is making this sound even more... problematic. It could potentially be dozens of modules across a single network, or spread across multiple networks. It could also be a single module on a network depending on the customer.

If you don't control the downstream IT and networking, your only real option is having an API in the cloud coordinate DNS and/or ACME.

Everything COULD happen on your modules, it's just going to be difficult to configure and you'll have a lot more customer support to ensure the modules work with their firewall setup. To get an idea, search this forum for topics on "NAS" - a handful of Network Storage vendors have integrated LetsEncrypt certificates into their systems. Some have an ACME client built in, others let certificates be uploaded. All have endless problems.

Alternately, you can look for a commercial CA that uses different authorization systems

6 Likes

if I remember currectly rest api of zerossl will allow to sign certificate for public ip (it does cost you though)

5 Likes

It seems like you will be forced into having to create your own CA and have your "devices" use it to obtain their certs [which will require the users to trust your CA - BAD for business].

It's a catch 22:

  • the devices need to be "secured" [which required some rigidity]
  • the devices are to be used in infinitely complex scenarios [zero rigidity]

If you send them out with a pre-installed public cert, it will expire in (maximum) 13 months.
[short lifespan and still leaves a local DNS issue to overcome - especially when multiple devices are being used within the same network/DHCP/DNS system]

7 Likes

You don't even need to do wildcard certs, you could even do that you have like 1.nodes.example.org that return:

Your public webserver IP when queried externally. (like 1.nodes.example.org => 123.123.123.123, 2.nodes.example.org => 123.123.123.123, 3.nodes.example.org => 123.123.123.123)

Your internal node IP (like 1.nodes.example.org => 192.168.0.1, 2.nodes.example.org => 192.168.0.2, 3.nodes.example.org => 192.168.0.3 and so on) when queried internally.

This is called a split-horizon DNS.
Then you simply do ACME validation as usual. Even your nodes could perform the ACME validation themselves. You simply have to, in your webserver, wire the /.well-known/acme-challenge folder to the last node's acme folder.

"Last node" here could be the last node that did a HTTP request to a endpoint on your main server. Like:

If something requests http://nodes.example.org/api/acme-validate.php AND their IP start on 192.168.0.(*), then the webserver config will be automatically be updated so:

http://nodes.example.org/.well-known/acme-challenge/* is a reverse proxy of http://192.168.0.$1/acme/*

And if you want better security, ergo when certificate is fetched, then fetch http://nodes.example.org/api/acme-unvalidate.php , which will, IF the config IP is == source IP, delete the config and wire the http://nodes.example.org/.well-known/acme-challenge/* folder to a 403.

(This can be done with rewriterule and proxy module in apache, and the actual IP config could be a alias that is in a .htaccess if you don't want your acme-validate.php/acme-unvalidate.php script to be able to write your webserver's main config)

Now, all your nodes need to do, is to run, first a HTTP request to acme-validate.php, then their own acme client and webserver, and then a HTTP request to acme-unvalidate.php. And the best thing: Your nodes don't even need to be publicity reachable except for a very short duration for while the acme client runs.

You obviously then need to issue the certificate in such a order so 2 nodes don't do their certificate stuff at the same time, because then they will step on each other's toe's. This could be done by having the script sleep for a few seconds if the fetch to acme-validate.php fails, and then have the acme-validate.php intentionally fail, if the config is already populated with another source IP than the one requesting it.

Obviously, when administrating the nodes, you would need to use their domain name, and not IP adress.

The advantage of this solution, is that each node has their own private key, which is important if the nodes are spread out over the world, in this way if a node is stolen and disassembled or similiar, then it won't compromise the security of all other nodes. This is especially important if you are sending out nodes to random customers/end-users.

@sebastiannielsen
Although I applaud your ingenuity, the solution provided requires much more than is provided.

I read that as ZERO CONTROL.

5 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.