import datetime from collections import namedtuple from dateutil.parser import parse as dtparse import socket import ssl CertCheckResult = namedtuple( "CertCheckResult", ["hostname", "check_successful", "expiration_date", "debug"] ) def get_cert(hostname, timeout): ctx = ssl.create_default_context() with ctx.wrap_socket(socket.socket(), server_hostname=hostname) as s: s.settimeout(timeout) s.connect((hostname, 443)) return s.getpeercert() def check_host_certificate_expiration(hostname, days_to_expiration, timeout=5): try: cert = get_cert(hostname, timeout) except ssl.SSLCertVerificationError as e: return CertCheckResult(hostname, False, None, e.strerror) expdate = dtparse(cert.get("notAfter")) curdate = datetime.datetime.now(tz=expdate.tzinfo) if expdate - curdate < datetime.timedelta(days=days_to_expiration): return CertCheckResult( hostname, False, expdate, f"Certificate expires in {(expdate - curdate).days} days - expected more than {days_to_expiration}", ) return CertCheckResult( hostname, True, expdate, f"Certificate expires in {(expdate - curdate).days} days", )