互联网服务中HTTPS 证书是保障数据传输安全的关键组件。一旦证书过期,将导致服务中断、浏览器安全警告等问题,严重影响用户体验和业务连续性。手动跟踪多个服务的证书有效期不仅繁琐,而且容易遗漏。本文介绍如何使用 Python 自动检测 HTTPS 证书的过期时间,并在证书即将过期时发送预警通知,实现运维流程的自动化与智能化。
应用场景
企业运维管理:运维团队需要集中监控公司官网、API 服务、内部系统等多个服务的证书状态,确保持续可用。
云服务与 SaaS 提供商:服务商需确保自身平台及为客户提供的服务证书有效,避免因证书问题导致的服务不可用,维护品牌信誉。
个人开发者与小型团队:管理个人项目、博客或小型企业网站的证书,在证书到期前及时收到提醒,避免因疏忽导致服务中断。
合规与审计要求:满足金融、医疗等行业对系统安全性和业务连续性的定期检查与合规要求。
通过自动化检测,运维人员可以从重复性的检查工作中解放出来,将精力集中于处理预警和解决实际问题,提升整体运维效率。
核心思路与使用说明
本方案的核心是编写一个 Python 脚本,其工作流程如下:
1、获取证书信息:向目标 URL 发起 HTTPS 请求,从 SSL/TLS 握手信息中提取证书的过期时间。
2、计算剩余天数:将证书过期时间与当前时间比较,计算出剩余有效天数。
3、判断与预警:将剩余天数与预设的预警阈值(例如 30 天)进行比较。若剩余天数小于等于阈值,则触发预警流程。
4、发送通知:通过配置好的通知渠道(如邮件、企业微信、钉钉、Slack 等)发送包含详细预警信息的消息。
使用说明
1、环境准备:确保运行脚本的设备安装有Python 3.6 及以上版本,并能够访问互联网以连接目标服务。
2、安装依赖:本示例脚本仅使用 Python 标准库,无需额外安装依赖。若需扩展其他通知渠道,可根据需要安装相应第三方库。
3、配置脚本:修改脚本中的配置部分,包括目标 URL 列表、预警阈值、通知渠道的认证信息等。
4、部署与运行:
手动运行:在本地或服务器上直接执行脚本进行一次性检查。
定时任务:利用系统的 cron(Linux)或计划任务(Windows)功能,将脚本设置为定时任务(例如每天运行一次),实现持续监控。
集成到 CI/CD:在持续集成/持续部署流水线中增加证书检查环节,确保上线服务的证书状态健康。
代码示例
以下是一个基础版本的 Python 脚本示例,实现了证书过期检测并通过电子邮件发送预警的功能。
#!/usr/bin/env python3# -*- coding: utf-8 -*-"""HTTPS 证书过期时间自动检测与邮件预警脚本"""import sslimport socketfrom datetime import datetimeimport smtplibfrom email.mime.text import MIMETextfrom email.header import Headerfrom 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.comSMTP_PORT = 587SENDER_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_datedef 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_listdef 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库构建并发送预警邮件。邮件内容清晰列出了每个预警域名的详细信息,便于接收者快速定位问题。
配置灵活:所有需要用户自定义的参数(域名列表、预警阈值、邮件服务器信息等)都集中在脚本开头的配置区域,结构清晰,修改方便。
错误处理与日志:脚本在执行过程中会输出不同级别的日志信息(INFO、ERROR、SUCCESS等),便于运行状态监控、问题调试与结果追溯。
此脚本是一个基础框架,你可以根据实际需求进行功能扩展,通过将此脚本部署为定时任务,可以构建一个低成本、高效率、可扩展的 HTTPS 证书自动监控系统,为服务的稳定运行与安全合规增添一道重要的自动化保障。
如果你觉得这篇文章有用,欢迎点赞、转发、收藏、留言、推荐❤!
------加入知识场与更多人一起学习------https://ima.qq.com/wiki/?shareId=f2628818f0874da17b71ffa0e5e8408114e7dbad46f1745bbd1cc1365277631c
https://ima.qq.com/wiki/?shareId=66042e013e5ccae8371b46359aa45b8714f435cc844ff0903e27a64e050b54b5