Skip to content

Instantly share code, notes, and snippets.

@vchoi
Forked from crashdump/check-ssl-expire.py
Last active April 17, 2018 17:00
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save vchoi/f374b3d4fceb1b975b98 to your computer and use it in GitHub Desktop.
Save vchoi/f374b3d4fceb1b975b98 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = "Adrien Pujol - http://www.crashdump.fr/"
__copyright__ = "Copyright 2013, Adrien Pujol"
__license__ = "Mozilla Public License"
__version__ = "0.3"
__email__ = "adrien.pujol@crashdump.fr"
__status__ = "Development"
__doc__ = "Check a TLS certificate validity."
import argparse
import socket
from datetime import datetime
import time
try:
# Try to load pyOpenSSL first
# aptitude install python-dev && pip install pyopenssl
from OpenSSL import SSL
import OpenSSL
if OpenSSL.__version__ >= '0.13':
PYOPENSSL = True
else:
raise ImportError('python-openssl 0.13+ needed')
except ImportError:
# Else, fallback on standard ssl lib (doesn't support SNI)
import ssl
PYOPENSSL = False
CA_CERTS = "/etc/ssl/certs/ca-certificates.crt"
def exit_error(errcode, errtext):
print errtext
exit(errcode)
def pyopenssl_check_callback(connection, x509, errnum, errdepth, ok):
''' callback for pyopenssl ssl check'''
if x509.get_subject().commonName == HOST:
if x509.has_expired():
exit_error(1, 'Error: Certificate has expired!')
else:
print pyopenssl_check_expiration(x509.get_notAfter())
if not ok:
return False
return ok
def pyopenssl_check_expiration(asn1):
''' Return the numbers of day before expiration. False if expired.'''
try:
expire_date = datetime.strptime(asn1, "%Y%m%d%H%M%SZ")
except:
exit_error(1, 'Certificate date format unknow.')
expire_in = expire_date - datetime.now()
if expire_in.days > 0:
return expire_in.days
else:
return False
def pyssl_check_hostname(cert, hostname):
''' Return True if valid. False is invalid '''
if 'subjectAltName' in cert:
for typ, val in cert['subjectAltName']:
# Wilcard
if typ == 'DNS' and val.startswith('*'):
if val[2:] == hostname.split('.', 1)[1]:
return True
# Normal hostnames
elif typ == 'DNS' and val == hostname:
return True
else:
return False
def pyssl_check_expiration(cert):
''' Return the numbers of day before expiration. False if expired. '''
if 'notAfter' in cert:
try:
expire_date = datetime.strptime(cert['notAfter'],
"%b %d %H:%M:%S %Y %Z")
except:
exit_error(1, 'Certificate date format unknow.')
expire_in = expire_date - datetime.now()
if expire_in.days > 0:
return expire_in.days
else:
return False
def main():
parser = argparse.ArgumentParser()
parser.add_argument('host', help='specify an host to connect to')
parser.add_argument('-p', '--port', help='specify a port to connect to',
type=int, default=443)
args = parser.parse_args()
global HOST, PORT
HOST = args.host
PORT = args.port
# Check the DNS name
try:
socket.getaddrinfo(HOST, PORT)[0][4][0]
except socket.gaierror as e:
exit_error(1, e)
# Connect to the host and get the certificate
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
# If handled by python SSL library
if not PYOPENSSL:
try:
ssl_sock = ssl.wrap_socket(sock, cert_reqs=ssl.CERT_REQUIRED,
ca_certs=CA_CERTS,
ciphers=("HIGH:-aNULL:-eNULL:"
"-PSK:RC4-SHA:RC4-MD5"))
cert = ssl_sock.getpeercert()
if not pyssl_check_hostname(cert, HOST):
print 'Error: Hostname does not match!'
print pyssl_check_expiration(cert)
sock = ssl_sock.unwrap()
except ssl.SSLError as e:
exit_error(1, e)
# If handled by pyOpenSSL module
else:
try:
ctx = SSL.Context(SSL.TLSv1_METHOD)
ctx.set_verify(SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
pyopenssl_check_callback)
ctx.load_verify_locations(CA_CERTS)
ssl_sock = SSL.Connection(ctx, sock)
ssl_sock.set_connect_state()
ssl_sock.set_tlsext_host_name(HOST)
ssl_sock.do_handshake()
x509 = ssl_sock.get_peer_certificate()
x509name = x509.get_subject()
if x509name.commonName != HOST:
print 'Error: Hostname does not match!'
ssl_sock.shutdown()
except SSL.Error as e:
exit_error(1, e)
sock.close()
if __name__ == "__main__":
main()
<?xml version="1.0" encoding="UTF-8"?>
<zabbix_export>
<version>2.0</version>
<date>2013-11-15T12:28:00Z</date>
<groups>
<group>
<name>Templates</name>
</group>
</groups>
<templates>
<template>
<template>Template External Check - SSL Cert Expire</template>
<name>Template External Check - 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>check-ssl-expire.py[&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 External Check - SSL Cert Expire:check-ssl-expire.py[&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 External Check - SSL Cert Expire:check-ssl-expire.py[&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 External Check - SSL Cert Expire:check-ssl-expire.py[&quot;{HOST.NAME}&quot;].last(0)}&lt;1</expression>
</dependency>
</dependencies>
</trigger>
<trigger>
<expression>{Template External Check - SSL Cert Expire:check-ssl-expire.py[&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 External Check - SSL Cert Expire:check-ssl-expire.py[&quot;{HOST.NAME}&quot;].last(0)}&lt;7</expression>
</dependency>
</dependencies>
</trigger>
<trigger>
<expression>{Template External Check - SSL Cert Expire:check-ssl-expire.py[&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 External Check - SSL Cert Expire:check-ssl-expire.py[&quot;{HOST.NAME}&quot;].last(0)}&lt;15</expression>
</dependency>
</dependencies>
</trigger>
<trigger>
<expression>{Template External Check - SSL Cert Expire:check-ssl-expire.py[&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 External Check - SSL Cert Expire:check-ssl-expire.py[&quot;{HOST.NAME}&quot;].last(0)}&lt;30</expression>
</dependency>
</dependencies>
</trigger>
<trigger>
<expression>{Template External Check - SSL Cert Expire:check-ssl-expire.py[&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 External Check - SSL Cert Expire:check-ssl-expire.py[&quot;{HOST.NAME}&quot;].last(0)}&lt;60</expression>
</dependency>
</dependencies>
</trigger>
<trigger>
<expression>{Template External Check - SSL Cert Expire:check-ssl-expire.py[&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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment