Skip to content

Instantly share code, notes, and snippets.

@jbsmith86
Last active April 18, 2018 18:30
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jbsmith86/df7d9aad39e5acf23f2caf73d17b1796 to your computer and use it in GitHub Desktop.
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

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

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

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