一、背景概要:
公司里有很多https域名,证书都是使用的ssl免费证书,需要手动运维。 经常会遇到证书过期导致项目无法访问的问题,所以写了一个脚本自动检测已有域名里,哪些域名要过期了,发送邮件通知运维。
二、需求描述:
- 每日检查特定域名的SSL证书到期情况
- 到期不足7天的域名收集
- 邮件发送通知
三、运行要求:
- 需要有一个smtp邮箱服务,用于邮件发送,这个主流的邮件公司基本都支持。如 QQ SMTP怎么配置?怎么使用
- 收集目前正在使用的https域名
- 修改配置,搭建Python运行环境,在服务器里运行
四、脚本代码:
脚本名称:ssl_validate.py
import smtplib
import socket
import ssl
import time
from datetime import datetime
from email.mime.text import MIMEText
import schedule
# 发件人
ENTRY_EMAIL_SENDER = 'xx@qq.com'
# 授权码
ENTRY_EMAIL_PWD = 'xxx'
# 设置发件服务器地址
ENTRY_EMAIL_HOST = 'smtp.exmail.qq.com'
# 设置发件服务器端口
ENTRY_EMAIL_PORT = 465
def send_email(subject, receiver, body):
"""
:param receiver: 设置邮件接收人,可以是QQ邮箱
:param body:正文
:param subject 标题
:return:
"""
msg = MIMEText(body, _charset="utf-8")
# 设置邮件标题
msg['subject'] = u'系统通知' if not subject else subject
# 设置发送人
msg['from'] = ENTRY_EMAIL_SENDER
# 设置接收人
msg['to'] = receiver
try:
# 注意!如果是使用SSL端口,这里就要改为SMTP_SSL
s = smtplib.SMTP_SSL(ENTRY_EMAIL_HOST, ENTRY_EMAIL_PORT)
# 登陆邮箱
s.login(ENTRY_EMAIL_SENDER, ENTRY_EMAIL_PWD)
# 发送邮件!
s.sendmail(ENTRY_EMAIL_SENDER, receiver, msg.as_string())
return True, ''
except smtplib.SMTPException as e:
print('发生邮件失败,具体原因是 %s', e)
return False, str(e)
def check_ssl_expiry(hostname, port=443, buffer_days=7):
"""
检查给定主机名的SSL证书到期情况。
:param hostname: 要检查的主机名或IP地址
:param port: 端口号,默认为443(HTTPS)
:param buffer_days: 到期前开始通知的天数
:return: 表示SSL证书状态的消息
"""
try:
context = ssl.create_default_context()
with socket.create_connection((hostname, port)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
cert = ssock.getpeercert()
# 提取过期日期并与当前日期比较
expiry_date = datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y %Z')
current_date = datetime.now()
days_remaining = (expiry_date - current_date).days
# 检查证书是否接近过期
if days_remaining < 0:
return hostname, f"SSL证书已经过期!"
elif days_remaining <= buffer_days:
return hostname, f"SSL证书将在 {days_remaining} 天后过期。"
else:
return None, None
# return hostname, f"SSL证书还有 {days_remaining} 天过期。"
except ssl.CertificateError as e:
return hostname, f"SSL证书过期 "
except ssl.SSLError as e:
return hostname, f"SSL证书不存在 "
except Exception as e:
print(e)
return hostname, f"SSL获取发生错误 "
def daily_check():
"""
每日检查特定域名的SSL证书到期情况。
"""
domain_dict = {'xx.com': ['xxx.xxx.com' ]}
hostnames = []
for key in domain_dict.keys():
val_list = domain_dict.get(key)
for val in val_list:
hostnames.append(val)
# 替换为要检查的域名列表
info = "以下域名SSL证书即将过期,请及时更新:\n"
need_send = False
for hostname in hostnames:
result = check_ssl_expiry(hostname)
if result and result[0]:
need_send = True
info += (result[0] + "," + result[1] + "\n")
print(info)
notification_email_list = ["xx@qq.com"] # 收件人邮箱
if need_send:
for notification_email in notification_email_list:
send_email("SSL 证书到期通知", notification_email, info.encode("utf-8"))
# 设置定时任务,每天执行一次
schedule.every().day.at("10:00").do(daily_check) # 每天10:00执行
# 运行定时任务
while True:
schedule.run_pending()
time.sleep(60) # 每60秒检查一次任务