写了一个简单的类封装用作 SSL 证书到期检查,最近的需求有提到,经常因为证书到期导致网站访问异常或者小程序接口异常等等奇怪的问题。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# -*- coding:utf-8 -*-
"""
@Author : haauleon
@Contact : 753494552@qq.com
@File : ssl_check.py
@Date : 2021-08-20 16:56:00
@Function: SSL 证书过期检查
"""
import socket
import ssl
import datetime
class SSLCheck:
'''SSL 证书过期检查'''
def __init__(self, hostname):
self.hostname = hostname
self.ssl_date_fmt = r'%b %d %H:%M:%S %Y %Z'
self.expired_time = None
def ssl_expiry_datetime(self):
'''获取证书到期时间'''
context = ssl.create_default_context()
conn = context.wrap_socket(
socket.socket(socket.AF_INET),
server_hostname=self.hostname,
)
# 5 秒超时,因为 Lambda 有运行时限制
conn.settimeout(5.0)
conn.connect((self.hostname, 443))
ssl_info = conn.getpeercert()
# 将证书中的字符串解析为 Python datetime 对象
return datetime.datetime.strptime(ssl_info['notAfter'], self.ssl_date_fmt)
def ssl_valid_time_remaining(self):
'''获取证书生命周期中剩余的天数'''
expires = self.ssl_expiry_datetime()
#logger.debug(
# 'SSL cert for %s expires at %s',
# hostname, expires.isoformat()
#)
return expires - datetime.datetime.utcnow()
def ssl_expires_in(self, buffer_days=20):
'''
检查 `hostname` SSL 证书是否在 `buffer_days` 内过期。
如果证书过期,则引发 AlreadyExpired 异常
'''
remaining = self.ssl_valid_time_remaining()
# print(remaining)
# print(type(remaining))
self.expired_time = str(remaining).split(',')[0]
# 如果证书在两周内到期,我们应该重新颁发
if remaining < datetime.timedelta(days=0):
# 证书已经过期
raise Exception('证书已经过期 %s 天' % remaining.days)
elif remaining < datetime.timedelta(days=buffer_days):
# 比缓冲期 buffer_days 更早到期
return True
else:
# 一切都很好
return False
class SSLMonitor:
'''SSL 证书监控类'''
def __init__(self):
self.content = None
self.hosts = [
'baidu.com',
'haauleon.com',
]
def check_all_hosts_ssl(self):
'''检查所有域名的证书到期情况'''
for host in self.hosts:
# print(host)
ssl_check = SSLCheck(host)
is_expired = ssl_check.ssl_expires_in(100) # 自定义缓冲期为100天
self.content = '域名: %s\nSSL证书剩余: %s\n' %(host, ssl_check.expired_time)
# print(self.content)
yield is_expired
if __name__ == '__main__':
s = SSLMonitor()
c = s.check_all_hosts_ssl()
ssl_msg = []
for _ in range(len(s.hosts)):
if next(c):
ssl_msg.append(s.content)
ssl_msg = ''.join(ssl_msg)
print(ssl_msg)
# 域名: haauleon.com
# SSL证书剩余: 73 days