Automated SSL Certificate Renewal and Installation

With Ignition 7.9 and the early versions of Ignition 8, the certificate renewal process could be accomplished outside of the Ignition Gateway configuration screens. Files could simply be copied to the correct folders/directories and would be effective after a restart. Starting with about Ignition 8.0.15, this process no longer worked and the gateway config web server screens needed to be used to generate and renew certificates. We would like to be able to manually install files. This will facilitate scripting (external to Ignition) that can automatically request, renew and install certificates prior to expiration. Perhaps, all that is needed is an accurate list of where all updated cert related files need to be placed.

The Web Server config page was added back in 8.0.3, but it is still possible to automate the cert renewal / installation process like you mention. In fact, whatever process you used in 7.9 should work in 8.

If you haven’t already, check out this guide: Let's Encrypt Guide for Ignition | Inductive Automation

Also see: NEW Web Server Config Page and SSL / TLS Setup Wizard

@jspecht we are looking into automating SSL cert renewal on our VM deployed gateways.

I just wanted to check that the above guides/info is still state of the art?

Thanks,

Nick

Yep - the Let's Encrypt guide can still be used as inspiration for how you can automate renewal of your SSL certs today. Some of the versions of software I used when writing that guide are now a bit outdated, but the general idea and patterns still apply.

@jspecht this is very helpful, thanks. So essentially, if we can get back an SSL cert that has the full root chain and the private key, we can package those up as a PKCS12 and replace the ssl.pfx file in webserver.

A question: if I wanted to automate a check afterwards to see if the new SSL cert is functioning, if I do this call to the SSL port and can get a response would that prove it or would there be a better way?

curl "https://{address}:8043/system/gwinfo"

Thanks,

Nick

Correct.

If your curl instance is configured to trust the root CA cert used in the cert chain you installed in the Gateway, and the {address} exists on the Gateway server cert's subject common name or subject alternative names, then that should work. You should get an HTTP 200 OK response which means the TLS handshake through which the HTTP connection is tunneled was successfully established.

@jspecht if we have a module installed on the machine of SSL install that is doing the SSL cert management and renewal for that machine, I think the method mentioned above (gwinfo) is not a valid way to check if the cert has been properly installed (i.e. self calling to self). Is there a suggested method to check after install of the new ssl.pfx file that everything is kosher?

PS: I realize this is module dev forum talk, so apologies.

Thanks,

Nick

If you want to verify that the certificate chain is installed in the Gateway's web server from a module running on that same Gateway, you could open a TLS client connection targeting localhost and the Gateway's HTTPS port. Java's JSSE APIs expose hooks to inspect the certificate chain presented by the server (in this case, the Gateway web server) during the authentication portion of the TLS handshake. Use this hook to compare the chain presented by the Gateway matches what you expect (the chain you just installed).

2 Likes

Something like this seems like it would work:

import javax.net.ssl.HttpsURLConnection;
import java.net.URL;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;

public class CertVerify {
    public static void main(String[] args) {
        try {
            String expectedSerialNumber = "";
            String CN = "";
            String url = String.format("https://%s:8043", CN);
            URL destinationUrl = new URL (url);
            HttpsURLConnection conn = (HttpsURLConnection) destinationUrl.openConnection();
            conn.connect();
            Certificate[] certs = conn.getServerCertificates();

            for (Certificate cert : certs) {
                if (cert instanceof X509Certificate) {
                    String DN = ((X509Certificate) cert).getSubjectDN().toString();
                    if(DN.contains(CN)) {
                        System.out.println(DN);
                        System.out.println("Expires: " + ((X509Certificate) cert).getNotAfter());
                        String SN = ((X509Certificate) cert).getSerialNumber().toString();
                        System.out.println(SN);
                        Boolean matches = SN.equals(expectedSerialNumber);
                        System.out.println("Cert Serial Number matches expected value: " + matches);
                    }
                }
            }
        } catch (Exception e) {
            System.out.println(e.getCause());
        }


    }
}

3 Likes

That works. As an even stronger check - you could load the certificate chain from disk (or wherever you have it stored) that you expect to be installed on the Gateway, and then grab the certificate chain from the connection like you have above, then assert that java.util.Arrays.equals(expectedChain, connectionChain) returns true.

Yes, the plan would be to get the SN from the actual cert ( ssl.pfx ), here it is just statically typed for example.

We also have this convenience API option which may be used to grab the serial number:

That will return the SN of the cert held by the provider, but not the actual installed cert. So we could actually do a 3 way match assertion of cert provider + what is in ssl.pfx + what is returned from a call to the web server.

Thanks for the advice as always.

Rgds,

Nick

1 Like