
互联网服务中HTTPS 证书是保障数据传输安全的关键组件。一旦证书过期,将导致服务中断、浏览器安全警告等问题,严重影响用户体验和业务连续性。手动跟踪多个服务的证书有效期不仅繁琐,而且容易遗漏。本文介绍如何使用 Python 自动检测 HTTPS 证书的过期时间,并在证书即将过期时发送预警通知,实现运维流程的自动化与智能化。
通过自动化检测,运维人员可以从重复性的检查工作中解放出来,将精力集中于处理预警和解决实际问题,提升整体运维效率。
本方案的核心是编写一个 Python 脚本,其工作流程如下:
1、获取证书信息:向目标 URL 发起 HTTPS 请求,从 SSL/TLS 握手信息中提取证书的过期时间。
2、计算剩余天数:将证书过期时间与当前时间比较,计算出剩余有效天数。
3、判断与预警:将剩余天数与预设的预警阈值(例如 30 天)进行比较。若剩余天数小于等于阈值,则触发预警流程。
4、发送通知:通过配置好的通知渠道(如邮件、企业微信、钉钉、Slack 等)发送包含详细预警信息的消息。
1、环境准备:确保运行脚本的设备安装有 Python 3.6 及以上版本,并能够访问互联网以连接目标服务。
2、安装依赖:本示例脚本仅使用 Python 标准库,无需额外安装依赖。若需扩展其他通知渠道,可根据需要安装相应第三方库。
3、配置脚本:修改脚本中的配置部分,包括目标 URL 列表、预警阈值、通知渠道的认证信息等。
4、部署与运行:
以下是一个基础版本的 Python 脚本示例,实现了证书过期检测并通过电子邮件发送预警的功能。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
HTTPS 证书过期时间自动检测与邮件预警脚本
"""
import ssl
import socket
from datetime import datetime
import smtplib
from email.mime.text import MIMEText
from email.header import Header
from typing import List, Tuple
# ============ 用户配置区域 ============
# 需要监控的域名列表
DOMAINS_TO_CHECK = [
" www.example.com ",
"api.example.com",
"blog.example.org",
]
# 预警阈值(天):证书剩余有效期少于等于此值时触发预警
WARNING_THRESHOLD_DAYS = 30
# 邮件服务器配置
SMTP_SERVER = "smtp.office365.com" # 例如:smtp.gmail.com, smtp.qq.com
SMTP_PORT = 587
SENDER_EMAIL = "your_monitor@example.com"
SENDER_PASSWORD = "your_app_password" # 注意:建议使用应用专用密码,而非邮箱登录密码
RECIPIENT_EMAILS = ["admin@example.com", "ops@example.com"]
# ============ 配置结束 ============
def get_cert_expiry_date(hostname: str, port: int = 443) -> datetime:
"""
获取指定主机和端口的 SSL 证书过期日期。
Args:
hostname: 目标主机名
port: 端口号,默认为 443
Returns:
datetime: 证书过期时间(UTC)
"""
context = ssl.create_default_context()
with socket.create_connection((hostname, port), timeout=10) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
cert = ssock.getpeercert()
# 证书中的日期格式为:'Aug 28 12:00:00 2025 GMT'
expire_str = cert['notAfter']
# 解析字符串为 datetime 对象
expire_date = datetime.strptime(expire_str, '%b %d %H:%M:%S %Y %Z')
return expire_date
def check_domains(domains: List[str]) -> List[Tuple[str, datetime, int]]:
"""
检查域名列表,返回需要预警的域名及其信息。
Args:
domains: 待检查的域名列表
Returns:
List[Tuple]: 每个元素为 (域名, 过期时间, 剩余天数) 的元组,仅包含需要预警的域名。
"""
warning_list = []
current_time = datetime.utcnow()
for domain in domains:
try:
expiry_date = get_cert_expiry_date(domain)
days_left = (expiry_date - current_time).days
print(f"[INFO] 域名: {domain:20s} 过期时间: {expiry_date.date()} 剩余天数: {days_left:3d}")
if days_left <= WARNING_THRESHOLD_DAYS:
warning_list.append((domain, expiry_date, days_left))
except socket.gaierror:
print(f"[ERROR] 无法解析域名: {domain}")
except (socket.timeout, ConnectionRefusedError, ssl.SSLError) as e:
print(f"[ERROR] 连接 {domain} 失败: {e}")
except Exception as e:
print(f"[ERROR] 检查 {domain} 时发生未知错误: {e}")
return warning_list
def send_warning_email(warning_list: List[Tuple[str, datetime, int]]) -> None:
"""
发送证书过期预警邮件。
Args:
warning_list: 由 check_domains 函数生成的预警列表。
"""
if not warning_list:
print("[INFO] 没有证书需要预警,邮件未发送。")
return
# 构建邮件正文
email_body_lines = ["【重要】HTTPS 证书过期预警通知\n"]
email_body_lines.append(f"以下服务的 SSL/TLS 证书将在 {WARNING_THRESHOLD_DAYS} 天内过期,请及时处理!\n")
email_body_lines.append("-" * 50)
for domain, expiry_date, days_left in warning_list:
email_body_lines.append(f"域名: {domain}")
email_body_lines.append(f"过期时间: {expiry_date.strftime('%Y-%m-%d %H:%M:%S UTC')}")
email_body_lines.append(f"剩余天数: {days_left} 天\n")
email_body_lines.append("-" * 50)
email_body_lines.append(f"生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
email_body = "\n".join(email_body_lines)
# 构建邮件
subject = f"HTTPS 证书过期预警 ({len(warning_list)} 个服务)"
msg = MIMEText(email_body, 'plain', 'utf-8')
msg['From'] = Header(f"证书监控系统 <{SENDER_EMAIL}>", 'utf-8')
msg['To'] = Header(",".join(RECIPIENT_EMAILS), 'utf-8')
msg['Subject'] = Header(subject, 'utf-8')
# 发送邮件
try:
with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server:
server.starttls() # 启用 TLS 加密
server.login(SENDER_EMAIL, SENDER_PASSWORD)
server.sendmail(SENDER_EMAIL, RECIPIENT_EMAILS, msg.as_string())
print(f"[SUCCESS] 预警邮件已发送至 {RECIPIENT_EMAILS}")
except Exception as e:
print(f"[FAILED] 邮件发送失败: {e}")
def main():
"""主函数"""
print("=" * 60)
print("开始执行 HTTPS 证书过期检查...")
print("=" * 60)
# 1. 检查所有配置的域名
need_warning_domains = check_domains(DOMAINS_TO_CHECK)
# 2. 如果有需要预警的域名,则发送邮件
if need_warning_domains:
send_warning_email(need_warning_domains)
else:
print("[INFO] 所有证书状态正常,无需预警。")
print("=" * 60)
print("检查完成。")
print("=" * 60)
if __name__ == "__main__":
main()get_cert_expiry_date:使用 Python 标准库 ssl 和 socket 建立安全的 TLS 连接,并直接从连接中获取对等方的证书信息,解析出过期时间。这种方法无需安装额外依赖(如 requests),更加轻量且高效。check_domains:遍历所有配置的域名,获取其证书过期时间,计算剩余天数,并与阈值比较。该函数还包含了基本的错误处理(如网络错误、域名解析失败),增强了脚本的健壮性。send_warning_email:使用 smtplib 和 email 库构建并发送预警邮件。邮件内容清晰列出了每个预警域名的详细信息,便于接收者快速定位问题。此脚本是一个基础框架,你可以根据实际需求进行功能扩展,通过将此脚本部署为定时任务,可以构建一个低成本、高效率、可扩展的 HTTPS 证书自动监控系统,为服务的稳定运行与安全合规增添一道重要的自动化保障。
“无他,惟手熟尔”!有需要的用起来!
如果你觉得这篇文章有用,欢迎点赞、转发、收藏、留言、推荐❤!
本文分享自 Nicholas与Pypi 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!