
Python: Send SSL Cert Expirations to Slack
If your organization uses SSL certificates for servers and websites, manually tracking their expiration dates can be time-consuming. This Python script automates this process by:
- Reading a list of URLs from a text file.
- Validating each SSL certificate’s issuer and expiration date.
- Sending alerts to a specified Slack channel for certificates nearing expiration (within a customizable timeframe).
Note: Most registrars won’t renew SSL certs more than 30 days before they expire.
Need help with the Slack webhook setup? I’ve included a brief guide below to get you started.
Create Slack Webhook
Log into your Slack workspace as an administrator. Go to the admin section of Slack. On the left menu list, scroll down to Configure Apps.
Choose the Custom Integrations. You can also utilize Slack apps for this. But for this round, we’ll use Slacks Incoming Webhooks. Choose Incoming Webhooks, then click the Add to Slack button.
Choose the Channel you want the alerts to go into. In this example I will use a private channel I created named “ssl-cert-alert”. Once you chose the channel, click “Add Incoming Webhooks integration”. This will send an alert to the channel you just chose.
Next we’ll configure the basics of the alert such as its Custom name, Label Icon, Etc. Once complete, click Save Settings. You will also notice the app name in your channel alert has updated.
Dont be a noob. The webook in this screenshot has already been removed.
Last thing you need to do is copy the Webhook URL. You will need this for the Python script.
Python Script
Now that you have your Slack Webhook URL, it’s time to setup your alert script. Below is the script you can copy. Make sure you update the .txt file path and Webhook URL with your own information.
import socket
import ssl
import datetime
import requests
# Make sure you define the path to the URL file
urls_file = "/Users/daveherrell/Desktop/urls.txt"
# Go grab your Slack Webhook URL and place it below
slack_webhook_url = "https://hooks.slack.com/YOURWEBHOOKURLHERE"
# Set the number of days to check for certificate expiration. Keep in mind that most SSL providers only allow you to renew certs within 30 days of expiration.
warning_days = 90
# Function to fetch SSL certificate information
def get_ssl_certificate_info(url):
try:
hostname = url.replace("https://", "").replace("http://", "").split("/")[0]
context = ssl.create_default_context()
with socket.create_connection((hostname, 443)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
cert = ssock.getpeercert()
not_after = datetime.datetime.strptime(cert['notAfter'], "%b %d %H:%M:%S %Y %Z")
issuer = dict(x[0] for x in cert['issuer'])['organizationName']
registrar = cert.get('subjectAltName', [(None, hostname)])[0][1]
return {
"url": url,
"issuer": issuer,
"not_after": not_after,
"registrar": registrar,
"is_valid": True
}
except Exception as e:
print(f"Failed to fetch certificate for {url}: {e}")
return None
# Function to send Slack notification
def send_slack_notification(message):
payload = {
"text": message
}
response = requests.post(slack_webhook_url, json=payload)
if response.status_code != 200:
print(f"Failed to send Slack message: {response.status_code}, {response.text}")
# Read URLs from file and process each
try:
with open(urls_file, "r") as f:
urls = [line.strip() for line in f if line.strip()]
for url in urls:
cert_info = get_ssl_certificate_info(url)
if cert_info and cert_info["is_valid"]:
days_to_expire = (cert_info["not_after"] - datetime.datetime.utcnow()).days
if days_to_expire <= warning_days:
message = (
f"SSL Certificate for {cert_info['url']} issued by {cert_info['issuer']} "
f"(Registrar: {cert_info['registrar']}) will expire in {days_to_expire} days "
f"on {cert_info['not_after'].strftime('%Y-%m-%d')}."
)
send_slack_notification(message)
print(message)
else:
print(f"Invalid certificate for {url} or unable to retrieve certificate.")
except FileNotFoundError:
print(f"URLs file not found at {urls_file}")
A couple items to note:
- You can change the date range on line 13 with whatever you wish. Just make sure it’s in days. For instance you can set it for 30 days instead of 90 days.
- Within your TXT file, you can list up to five hundred URLs before this breaks. However, make sure the file only contains one domain per line!
- You can easily set this script to run via Scheduled task on Windows server or with a cron job on any Linux setup.
- Even if the url in the txt file is no longer available, the script will still run.
Make sure the request module is installed, along with any others you may need for import.
Categories
Recent Posts
- PowerShell: How to Add an Alias to Every Users Mailbox and Groups in Microsoft 365
- Slack: Disable Entra ID User using a slash command.
- Slack: Retrieve Entra ID (MS365) User Information with a slash command.
- Jira Cloud: Disabling Entra ID User Accounts via Automation and Microsoft Runbook
- Jira Cloud: Restart an Azure VM using JSM Assets and Automation