SSL Certificate Expiration Checker

Article summary

IT Operations teams frequently have the responsibility to ensure that SSL certificates for various websites are valid and renewed on a regular basis. While SSL certificate vendors often provide reminders and warnings when the certificates are about to expire, this is not always effective–especially when a variety of different SSL vendors have been used, or different parties are responsible for purchasing and maintaining the certificate.

To prevent SSL certificate expirations from going unnoticed, I wrote an application that checks the certificates from a variety of sites and ensures that they will remain valid for a certain number of days in the future.

In order to track the different sites, we set up integration with Dead Man’s Snitch (DMS). This ensures that SSL certificate checks are being performed and that the results are valid. If a check does not execute or does not return a valid response (because the certificate will be expiring within a configured look-ahead period), DMS creates an alert and lets me know that action is required.

The Concept

The application takes a set of hostnames and associated DMS snitch IDs, retrieves the SSL certificate for each host, evaluates if the SSL certificate’s expiration date is valid within the configured look-ahead period, and then notifies the DMS snitch if the expiration date is valid. It’s intended to be run on a regular basis–at least daily. The configured look-ahead period should be long enough to ensure that any expiring certificates can be renewed in time to avoid a service interruption.

The application uses SSLSocket from Ruby’s OpenSSL library to retrieve the SSL certificate from a given host:


tcp_socket = TCPSocket.new('atomicobject.com', 443)
ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp_socket)
ssl_socket.hostname='atomicobject.com'
ssl_socket.connect
certificate = ssl_socket.peer_cert
ssl_socket.sysclose
tcp_socket.close

It returns an OpenSSL::X509::Certificate object:


=> #<OpenSSL::X509::Certificate: subject=#<OpenSSL::X509::Name:0x007f8769015cc8>, issuer=#<OpenSSL::X509::Name:0x007f8769015ca0>, serial=#<OpenSSL::BN:0x007f8769015c78>, not_before=2015-04-24 00:00:00 UTC, not_after=2016-04-24 23:59:59 UTC>

The SSL certificate expiration date is stored in the not_after attribute:


expiration = OpenSSL::X509::Certificate.new(certificate).not_after.to_datetime

which produces:


=> #<DateTime: 2016-04-24T23:59:59+00:00 ((2457503j,86399s,0n),+0s,2299161j)>

If the certificate expiration date is further into the future than our configured look-ahead date, then the SSL certificate is considered valid, and the associated DMS snitch is notified.

For example, if we configured our look-ahead period to be four weeks (28 days), the expiration date would be considered valid:


look_ahead = DateTime.now + 28
expiration > look_ahead
=> true

If we configured our look-ahead period to be four months (120 days), the expiration date would not be considered valid:


look_ahead = DateTime.now + 120
expiration > look_ahead
=> false

The Application

I’ve published the application on GitHub. You can test it out by cloning it. All you need to do is add a config.yml following the example provided in config.yml.example.

There are two rake tasks: one that simply performs checks, and another that performs checks and notifies the configured DMS snitch. The current application only sends notifications to DMS, but it could be easily extended to notify other services. Our default look-ahead period is two weeks (14 days), but that can be altered within the Rakefile.

A config.yml like:

- host: expired.atomicobject.com
  comment: "dummy certificate"
  port: 443
  snitch: aabbccddff
- host: atomicobject.com
  comment: "primary certificate"
  port: 443
  snitch: aabbccddee

will check the SSL certificates for ‘expired.atomicobject.com’ and ‘atomicobject.com’. The following is sample output from running bundle exec rake ssl:check_and_notify:


E, [2016-01-10T13:06:13.617778 #9772] ERROR -- : Certificate for expired.atomicobject.com is expired.
I, [2016-01-10T13:06:13.807550 #9772]  INFO -- : Certificate for atomicobject.com is within expiry.
I, [2016-01-10T13:06:13.807608 #9772]  INFO -- : Notifying snitch aabbccddee
I, [2016-01-10T13:06:14.011433 #9772]  INFO -- : Notifying snitch aabbccddee succeeded.

Running bundle exec rake ssl:check will perform the checks without notifying DMS.

This application helps ensure that the SSL certificates for all of Atomic’s sites and many of our client sites are kept current and not allowed to expire. Whenever one of the checks for a SSL certificate fails, we are immediately notified. This gives us time to begin the process of renewing the certificate so that we can install it on the necessary servers well ahead of the expiration date.

This application has been extremely valuable to us, and I hope it will be useful to others as well.