证书过期是网络运维里最让人窝火的事故之一。明明网站能打开,但浏览器弹个安全警告,用户第一个电话就打到你这里来。实际上证书过期这种事完全可以提前发现,写个Python脚本监控一下,到期前30天就报警,不用等到出事才救火。
Python的标准库里就有处理SSL证书的能力,不需要装第三方库:
importssl
importsocket
fromdatetimeimportdatetime, timedelta
importcsv
importsmtplib
fromemail.mime.textimportMIMEText
fromemail.mime.multipartimportMIMEMultipart
defget_cert_info(host, port=443, timeout=5):
"""获取目标站点的SSL证书信息"""
context=ssl.create_default_context()
context.check_hostname=False
context.verify_mode=ssl.CERT_NONE# 忽略证书链验证错误,照样读取证书信息
try:
withsocket.create_connection((host, port), timeout=timeout) assock:
withcontext.wrap_socket(sock, server_hostname=host) asssock:
cert=ssock.getpeercert(binary_form=True)
# 解析证书
fromcryptographyimportx509
fromcryptography.hazmat.backendsimportdefault_backend
cert_obj=x509.load_der_x509_certificate(cert, default_backend())
not_before=cert_obj.not_valid_before_utc
not_after=cert_obj.not_valid_after_utc
issuer=cert_obj.issuer.rfc4514_string()
subject=cert_obj.subject.rfc4514_string()
return {
'host': host,
'port': port,
'subject': subject,
'issuer': issuer,
'not_before': not_before,
'not_after': not_after,
'days_left': (not_after-datetime.utcnow()).days
}
exceptExceptionase:
return {'host': host, 'port': port, 'error': str(e)}
defcheck_certificate(host, warning_days=30):
"""检查证书状态,返回(是否正常, 描述信息)"""
info=get_cert_info(host)
if'error'ininfo:
returnFalse, f"连接失败:{info['error']}"
days_left=info['days_left']
ifdays_left<0:
returnFalse, f"证书已过期 {abs(days_left)} 天!"
elifdays_left<=warning_days:
returnFalse, f"证书即将过期,剩余 {days_left} 天"
else:
returnTrue, f"证书正常,剩余 {days_left} 天"
# 安装依赖:pip install cryptography
# 批量检查域名列表
SITES= [
("www.example.com", 443),
("api.example.com", 443),
("mail.example.com", 443),
("vpn.example.com", 443),
]
if__name__=="__main__":
print(f"检查时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("="*60)
warning_count=0
forhost, portinSITES:
status, msg=check_certificate(host, warning_days=30)
symbol="[OK]"ifstatuselse"[警告]"
print(f"{symbol}{host:30s}{msg}")
ifnotstatus:
warning_count+=1
print("="*60)
ifwarning_count>0:
print(f"共发现 {warning_count} 个站点的证书需要关注")
else:
print("所有站点证书状态正常")
这里用的是Python标准库里的ssl和socket,配合cryptography库来解析X.509证书。cryptography需要单独装一下:
pip install cryptography
核心逻辑就是建立SSL连接之后用getpeercert()拿到证书信息,然后计算剩余天数,和告警阈值做比较。
实际用这个脚本排查过一个遗留问题:某台VPN网关的证书还有17天到期,VPN设备本身又没法装自动续期脚本,靠人工又容易忘。用这个脚本加了定时任务,每周扫一遍内网所有HTTPS资产,提前把到期时间摸清楚,在过期前两周就安排好续期。
进阶一点的做法是把结果写到CSV文件里,再配合钉钉或者企业微信的Webhook做自动告警。脚本本身逻辑很简单,加上一个requests.post()调用把告警信息推出去就行:
defsend_dingtalk_alert(title, content):
"""发送钉钉告警"""
webhook_url="https://oapi.dingtalk.com/robot/send?access_token=你的token"
payload= {
"msgtype": "markdown",
"markdown": {"title": title, "text": f"### {title}\n{content}"}
}
requests.post(webhook_url, json=payload)
放到cron里每周跑一次,比什么监控系统都省事。