Skip to content

Instantly share code, notes, and snippets.

@jbsmith86
Last active April 18, 2018 18:30
Show Gist options
  • Select an option

  • Save jbsmith86/df7d9aad39e5acf23f2caf73d17b1796 to your computer and use it in GitHub Desktop.

Select an option

Save jbsmith86/df7d9aad39e5acf23f2caf73d17b1796 to your computer and use it in GitHub Desktop.
This script returns the number of days left for validity of the certificate of a given url. Supports wildcard certs and SNI. Useful for monitoring.
#!/usr/bin/env ruby
require "optparse"
require "socket"
require "openssl"
require "time"
options = {
'port' => 443
}
arguments = OptionParser.new do |arguments|
arguments.banner = "Returns the number of valid days left for a certificate"
arguments.separator ""
arguments.separator "Usage: cert_vaildation URL [options]"
arguments.separator ""
arguments.separator "Specific options:"
arguments.on("-u", "--url URL", "URL to check certificate validity for") do |url|
options['url'] = url
end
arguments.on("-p", "--port PORT", "Port to connect on") do |port|
options['port'] = port
end
arguments.on("-c", "--ca-cert FILEPATH", "Filepath for certificate authority file if it can't be detected by ruby") do |cert|
options['cert_location'] = cert
end
arguments.on_tail("-h", "--help", "Show this message") do
print "\n"
puts arguments
print "\n"
exit
end
end
def options_check(options)
if options['url'].to_s.empty?
if url = ARGV.pop
options['url'] = url
else
puts "You need to specify a url to check in the command! (i.e. \"cert_vaildation www.example.com\") Please try again."
raise OptionParser::MissingArgument
end
end
end
def cert_days_remaining(results)
(DateTime.parse(results['valid_until'].to_s) - DateTime.parse(Time.now.utc.to_s)).to_i
end
def connect(options, arguments)
arguments.parse!(ARGV)
options_check(options)
ssl_context = OpenSSL::SSL::SSLContext.new
ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER
cert_store = OpenSSL::X509::Store.new
if options['cert_location']
cert_store.add_file options['cert_location']
else
cert_store.set_default_paths
end
ssl_context.cert_store = cert_store
tcp_client = TCPSocket.new(options['url'], options['port'])
ssl_client = OpenSSL::SSL::SSLSocket.new(tcp_client, ssl_context)
ssl_client.hostname = options['url']
ssl_client.connect
cert = OpenSSL::X509::Certificate.new(ssl_client.peer_cert)
certprops = OpenSSL::X509::Name.new(cert.issuer).to_a
issuer = certprops.select { |name, data, type| name == "O" }.first[1]
results = {
'valid_on' => cert.not_before,
'valid_until' => cert.not_after,
'issuer' => issuer,
'valid' => (ssl_client.verify_result == 0)
}
if results['valid']
puts cert_days_remaining(results)
else
puts 0
end
ssl_client.sysclose
tcp_client.close
end
connect(options, arguments)
<?xml version="1.0" encoding="UTF-8"?>
<zabbix_export>
<version>1.0</version>
<date>2017-05-04T12:00:00Z</date>
<groups>
<group>
<name>Templates</name>
</group>
</groups>
<templates>
<template>
<template>Template SSL Cert Expire</template>
<name>Template SSL Cert Expire</name>
<groups>
<group>
<name>Templates</name>
</group>
</groups>
<applications>
<application>
<name>SSL certificate</name>
</application>
</applications>
<items>
<item>
<name>SSL certificate validity</name>
<type>10</type>
<snmp_community/>
<multiplier>0</multiplier>
<snmp_oid/>
<key>cert_vaildation[&quot;{HOST.NAME}&quot;]</key>
<delay>86400</delay>
<history>14</history>
<trends>365</trends>
<status>0</status>
<value_type>0</value_type>
<allowed_hosts/>
<units>days</units>
<delta>0</delta>
<snmpv3_contextname/>
<snmpv3_securityname/>
<snmpv3_securitylevel>0</snmpv3_securitylevel>
<snmpv3_authprotocol>0</snmpv3_authprotocol>
<snmpv3_authpassphrase/>
<snmpv3_privprotocol>0</snmpv3_privprotocol>
<snmpv3_privpassphrase/>
<formula>1</formula>
<delay_flex/>
<params/>
<ipmi_sensor/>
<data_type>0</data_type>
<authtype>0</authtype>
<username/>
<password/>
<publickey/>
<privatekey/>
<port/>
<description/>
<inventory_link>0</inventory_link>
<applications>
<application>
<name>SSL certificate</name>
</application>
</applications>
<valuemap/>
</item>
</items>
<discovery_rules/>
<macros>
<macro>
<macro>{$SSL_PORT}</macro>
<value>443</value>
</macro>
</macros>
<templates/>
<screens/>
</template>
</templates>
<triggers>
<trigger>
<expression>{Template SSL Cert Expire:cert_vaildation[&quot;{HOST.NAME}&quot;].last(0)}&lt;1</expression>
<name>SSL certificate on {HOSTNAME} expired</name>
<url/>
<status>0</status>
<priority>5</priority>
<description/>
<type>0</type>
<dependencies/>
</trigger>
<trigger>
<expression>{Template SSL Cert Expire:cert_vaildation[&quot;{HOST.NAME}&quot;].last(0)}&lt;7</expression>
<name>SSL certificate on {HOSTNAME} expires in less than 7 days ({ITEM.VALUE} days remaining)</name>
<url/>
<status>0</status>
<priority>4</priority>
<description/>
<type>0</type>
<dependencies>
<dependency>
<name>SSL certificate on {HOSTNAME} expired</name>
<expression>{Template SSL Cert Expire:cert_vaildation[&quot;{HOST.NAME}&quot;].last(0)}&lt;1</expression>
</dependency>
</dependencies>
</trigger>
<trigger>
<expression>{Template SSL Cert Expire:cert_vaildation[&quot;{HOST.NAME}&quot;].last(0)}&lt;15</expression>
<name>SSL certificate on {HOSTNAME} expires in less than 15 days ({ITEM.VALUE} days remaining)</name>
<url/>
<status>0</status>
<priority>3</priority>
<description/>
<type>0</type>
<dependencies>
<dependency>
<name>SSL certificate on {HOSTNAME} expires in less than 7 days ({ITEM.VALUE} days remaining)</name>
<expression>{Template SSL Cert Expire:cert_vaildation[&quot;{HOST.NAME}&quot;].last(0)}&lt;7</expression>
</dependency>
</dependencies>
</trigger>
<trigger>
<expression>{Template SSL Cert Expire:cert_vaildation[&quot;{HOST.NAME}&quot;].last(0)}&lt;30</expression>
<name>SSL certificate on {HOSTNAME} expires in less than 30 days ({ITEM.VALUE} days remaining)</name>
<url/>
<status>0</status>
<priority>2</priority>
<description/>
<type>0</type>
<dependencies>
<dependency>
<name>SSL certificate on {HOSTNAME} expires in less than 15 days ({ITEM.VALUE} days remaining)</name>
<expression>{Template SSL Cert Expire:cert_vaildation[&quot;{HOST.NAME}&quot;].last(0)}&lt;15</expression>
</dependency>
</dependencies>
</trigger>
<trigger>
<expression>{Template SSL Cert Expire:cert_vaildation[&quot;{HOST.NAME}&quot;].last(0)}&lt;60</expression>
<name>SSL certificate on {HOSTNAME} expires in less than 60 days ({ITEM.VALUE} days remaining)</name>
<url/>
<status>0</status>
<priority>1</priority>
<description/>
<type>0</type>
<dependencies>
<dependency>
<name>SSL certificate on {HOSTNAME} expires in less than 30 days ({ITEM.VALUE} days remaining)</name>
<expression>{Template SSL Cert Expire:cert_vaildation[&quot;{HOST.NAME}&quot;].last(0)}&lt;30</expression>
</dependency>
</dependencies>
</trigger>
<trigger>
<expression>{Template SSL Cert Expire:cert_vaildation[&quot;{HOST.NAME}&quot;].last(0)}&lt;90</expression>
<name>SSL certificate on {HOSTNAME} expires in less than 90 days ({ITEM.VALUE} days remaining)</name>
<url/>
<status>0</status>
<priority>0</priority>
<description/>
<type>0</type>
<dependencies>
<dependency>
<name>SSL certificate on {HOSTNAME} expires in less than 60 days ({ITEM.VALUE} days remaining)</name>
<expression>{Template SSL Cert Expire:cert_vaildation[&quot;{HOST.NAME}&quot;].last(0)}&lt;60</expression>
</dependency>
</dependencies>
</trigger>
<trigger>
<expression>{Template SSL Cert Expire:cert_vaildation[&quot;{HOST.NAME}&quot;].nodata(86500)}=1</expression>
<name>SSL certificate on {HOSTNAME} No new data in the last 24h</name>
<url/>
<status>0</status>
<priority>2</priority>
<description>No data received for &gt; 24h. Check the script.</description>
<type>0</type>
<dependencies/>
</trigger>
</triggers>
</zabbix_export>
@kunoo
Copy link
Copy Markdown

kunoo commented Sep 21, 2017

Hey! Thx a lot! Works like a charm.

Thank you for posting it on the check-ssl-expire.py Gist!

@sereose
Copy link
Copy Markdown

sereose commented Apr 17, 2018

Zabbix 3.4.x
Latest data showing exact days remaining
from console executing script also returning current number of days left till expiration.
on a dashboard is always showing SSL certificate on example.com expires in less than 90 days (UNKNOWN days remaining)
How to fix this (UNKNOWN days remaining) issue in a dashboard panel ?
Any clue please?

@sereose
Copy link
Copy Markdown

sereose commented Apr 17, 2018

Founded the fix by myself.
just change trigger name from
SSL certificate on {HOSTNAME} expires in less than 90 days ({ITEM.VALUE} days remaining)
to
SSL certificate on {HOSTNAME} expires in less than 90 days ({ITEM.LASTVALUE} days remaining)

And you will get a correct day count in trigger name :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment