Hi,
Hier meine Bastelrei:
import ssl
import socket
import smtplib
from datetime import datetime
from OpenSSL import crypto
from concurrent import futures
############## CONFIG ################
# EMAIL SERVER
SMTP_SERVER = "mail.mydomain1.com"
SENDER_EMAIL = ""
RECIPIENT_EMAIL = ""
SMTP_PASSWORD = ""
SMTP_PORT = 587
# DOMAINS
DOMAINES = {'MYDOMAIN1.COM': [{'domain': 'mail.mydomain1.com', 'port': 587}, {'domain': 'mail.mydomain1.com', 'port': 465}, {'domain': 'mail.mydomain1.com', 'port': 993}, {'domain': 'www.mydomain1.com', 'port': 443}], 'TEST.EU': [{'domain': 'mail.test.eu', 'port': 993}, {'domain': 'www.test.eu', 'port': 443}]}
# DIVERS
SHELL_OUTPUT = True
SEND_EMAIL = True
############## END CONFIG ################
WARNING = '\033[93m'
SUCCESS = '\033[92m'
ALERT = '\033[38;5;208m'
DANGER = '\033[91m'
INFO = '\033[96m'
ENDC = '\033[0m'
def sendMail(subject, content):
port = SMTP_PORT
smtp_server = SMTP_SERVER
sender_email = SENDER_EMAIL
receiver_email = RECIPIENT_EMAIL
password = SMTP_PASSWORD
message = f"""Subject: {subject}
From: {sender_email}
To: {receiver_email}
{content}"""
context = ssl.create_default_context()
with smtplib.SMTP(smtp_server, port) as server:
server.ehlo() # Can be omitted
server.starttls(context=context)
server.ehlo() # Can be omitted
server.login(sender_email, password)
server.sendmail(sender_email, receiver_email, message)
class PrintShell:
def __init__(self):
pass
def danger(self, text, result, width=40):
print(f' {text + " ":.<{width}}{DANGER} {result}{ENDC}')
def alert(self, text, result, width=40):
print(f' {text + " ":.<{width}}{ALERT} {result}{ENDC}')
def warning(self, text, result, width=40):
print(f' {text + " ":.<{width}}{WARNING} {result}{ENDC}')
def info(self, text, result, width=40):
print(f' {text + " ":.<{width}}{INFO} {result}{ENDC}')
def success(self, text, result, width=40):
print(f' {text + " ":.<{width}}{SUCCESS} {result}{ENDC}')
def printsh(text, result, color, width=40):
print(f' {text + " ":.<40}{color} {result}{ENDC}')
now = datetime.now()
out = PrintShell()
def CertLimitSSL(hostname, port):
"""Return standard SSL cert from hostname:port"""
ctx = ssl.create_default_context()
s = ctx.wrap_socket(socket.socket(), server_hostname=hostname)
s.settimeout(10)
s.connect((hostname, port))
cert = s.getpeercert()
s.close()
return cert
def CertLimitSTARTTLS(hostname):
"""Return SSL cert from STARTTLS connection at hostname:587"""
connection = smtplib.SMTP(hostname, timeout=10)
connection.connect(hostname,587)
connection.starttls()
cert = ssl.DER_cert_to_PEM_cert(connection.sock.getpeercert(binary_form=True))
connection.quit()
return crypto.load_certificate(crypto.FILETYPE_PEM, cert)
def get_level(limit):
if (limit-now).days <= 7:
return 'danger'
if (limit-now).days <= 14:
return 'alert'
if (limit-now).days <= 28:
return 'warning'
return 'success'
def checkOnDom(domain):
port = domain['port']
hostname = domain['domain']
url = hostname + ":" + str(port)
domain['url'] = url
domain['level'] = None
domain['status'] = None
# Check per SMTP STARTTLS connection
if port == 587:
cert = CertLimitSTARTTLS(hostname)
limit = datetime.strptime(cert.get_notAfter().decode(),"%Y%m%d%H%M%SZ")
date = limit.strftime("%d-%m-%Y %H:%M:%S")
domain['level'] = get_level(limit)
domain['status'] = date
if domain['level'] in ['warning', 'danger']:
subject = f"Update certificate {hostname} port {port}"
content = f"The cert from {hostname}:{port} will be disabled at {limit}."
domain['email_content'] = f"{subject}\n{content}"
# Check other standarts SSL cert
else:
try:
cert = CertLimitSSL(hostname, port)
limit = datetime.strptime(cert['notAfter'], "%b %d %H:%M:%S %Y GMT")
date = limit.strftime("%d-%m-%Y %H:%M:%S")
domain['status'] = date
domain['level'] = get_level(limit)
if domain['level'] in ['warning', 'danger']:
subject = f"Update certificate {hostname} port {port}"
content = f"The cert from {hostname}:{port} will be disabled at {limit}."
domain['email_content'] = f"{subject}\n{content}\n"
except ssl.SSLCertVerificationError:
domain['level'] = 'danger'
domain['status'] = 'Invalid certificate !'
subject = f"{hostname} port {port} : Certificate is not valid"
content = f"{url} has not a valid certificate !"
domain['email_content'] = f"{subject}\n{content}"
except (ConnectionRefusedError, TimeoutError, socket.timeout, OSError):
domain['level'] = 'danger'
domain['status'] = 'No response !'
subject = f"Cannot connect to {hostname} port {port}"
content = f"{url} is not reachable !"
domain['email_content'] = f"{subject}\n{content}"
return domain
def checkCertDom(domains_list):
with futures.ThreadPoolExecutor(20) as executor:
res = executor.map(checkOnDom, domains_list)
return res
email_warning = False
email_content = ''
email_subject = 'Certificate problem'
for key, dom in DOMAINES.items():
print(f'\033[96m{key:<20}{"":-<60}\033[0m')
for entry in sorted(list(checkCertDom(dom)), key=lambda d:d['url']):
if SHELL_OUTPUT:
method = getattr(out, entry['level'])
method(entry['url'], entry['status'])
if entry['level'] in ['warning', 'danger']:
email_warning = True
email_content += f"{entry['email_content']}\n\n"
if SEND_EMAIL and email_warning:
sendMail(email_subject, email_content)
print(f"""
Validity of certificates :
{SUCCESS}More than 28 days
{WARNING}Less than 28 days
{ALERT}Less than 14 days
{DANGER}Less than 7 days
{ENDC}""")
Es ist notwendig die Liste von Domains + SMTP Server zu konfigurieren.
Als mycertscript.py
speichern, und man kann es einfach mit python3 mycertscript.py
aufrufen.
Gruß
Arnaud