A few years ago I already covered how to check the expiry date of a SSL certificate using OpenSSL. When the recent global outage of Windows Azure was caused by an expired SSL certificate, this got me thinking about this topic once again.
In my previous post, I presented a mechanism to check the remaining lifetime of an SSL certificate using the PEM certificate file locally on disk. However, in the case with Azure recently, customers were dependent on the actions by Microsoft and had no access to the actual file. Thus, there might be a need to check remote certificates of services you use, e.g. your off-site backup provider. As you want to ensure you can always use this service, why not check this for expiring certificates once in a while? Maybe it’s your notification to the sysadmins who saves yourself and all other customers from being locked out.
Here is the updated script ssl-cert-check
that now not only handles x509 certificate files, but also remote addresses for various forms and protocols. For simplicity, here are the usage instruction from inside this script:
./ssl-cert-check <days> <certspec1,certspec2,...> This tool will warn you if any of the specified certificates expires in the next <days> days. The first parameter is the number of days to warn in advance for expiring certificates. All following parameters are treated as certificate specifications and can be in one of the following formats: - An absolute path to a x509 PEM certificate file For example: /etc/apache2/ssl/example.org.pem - A file://<path> URI For example: file:///etc/apache2/ssl/example.org.pem - A ssl://<host>:<port> URI For example: ssl://example.org:443 - A <proto>://<host>[:<port>] URI, this is the same as ssl://<host>:<proto>. The real port number is usually looked up in /etc/services, note that you often need the one with the 's' suffix, like "https", "imaps", etc. For example: https://example.org imaps://example.org (same as ssl://example.org:993) - A <proto>+starttls://<host>[:<port>] URI Use the STARTTLS command to start a in-protocol TLS session after opening an unencrypted connection. The openssl s_client needs to support this protocol. At time of this writing, the supported protocols are "smtp", "pop3", "imap", "ftp" and "xmpp". For example: imap+starttls://example.org smtp+starttls://example.org:587
The accompanying cronjob entry to check SSL certificates once a day hasn’t changed much, but remember to add the new parameter for the number of days:
MAILTO=root 6 6 * * * nobody /usr/local/bin/ssl-cert-check 30 /etc/apache2/ssl/*.crt /etc/ssl/certs/dovecot.pem https://localhost ssl://localhost:465
It does not harm to check certificates twice, both the local PEM file and what is served when opening a connection. Maybe this might even help to detect problems such as a missing restart after updating the certificate file on disk. In the example above, I added both the Apache certificate and the HTTPS port on localhost. To test if the script works correctly, just choose an arbitrary high value for the number of days and make sure that all certificates are reported to expire soon.
You can get ssl-cert-check as a download. You may share and use this script under the terms of a two-clause BSD license, see the file itself for details.
Update 2014-01-27
The original version used wrong argument syntax in the crontab example and also did not handle errors gracefully. A combination which lead to failures without any hint what’s going on. The new version released today improves this behavior. The error output from OpenSSL is captured and both the failing command and its error output are printed if the certificate could not be checked. You can download the new version of ssl-cert-check under the same URL as above.