Python脚本
# -*- coding: utf-8 -*-
import ssl
import socket
import datetime
def get_host_port(domain):
host, port = domain.split(':', 1) if ':' in domain else (domain, 443)
return (host, int(port))
def get_remaining_days(domain):
try:
host, port = get_host_port(domain)
context = ssl.create_default_context()
conn = context.wrap_socket(socket.socket(socket.AF_INET), server_hostname=host)
conn.connect((host, port))
conn.settimeout(3)
# 获取 peer(对方)的证书
cert = conn.getpeercert()
# 证书结束日期
if cert and 'notAfter' in cert:
conn.close()
notAfter = str(cert['notAfter'])
# 日期时间字符串解析为一个 datetime 对象
expiry_date = datetime.datetime.strptime(notAfter, '%b %d %H:%M:%S %Y %Z')
remaining_days = (expiry_date - datetime.datetime.now()).days
print(f"{domain} 的证书剩余有效期为 {remaining_days} 天。")
return remaining_days
except Exception as e:
print(f"获取 {domain} 的证书时出错:{e}")
return None
if __name__ == "__main__":
# get_remaining_days('www.baidu.com:443')
remaining_days = get_remaining_days('www.baidu.com')
增加推送钉钉群通知完整示例
pip3 install pyyaml
pip3 install requests
- domain_config.yml配置文件
- ding-talk:
secret: 'xxxx'
access-token: 'xxxx'
- project:
name: '百度官网'
domain-name:
- 'www.baidu.com'
- 'fanyi.baidu.com'
- project:
name: '360官网'
domain-name:
- 'www.360.cn'
# -*- coding: utf-8 -*-
from os import access
import ssl
import datetime
import socket
import yaml
import time
import hashlib
import base64
import hmac
import requests
from urllib.parse import quote
def read_yaml(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
try:
data = yaml.safe_load(file)
return data
except yaml.YAMLError as e:
print(f"读取 YAML 文件时出错:{e}")
return None
def get_host_port(domain):
host, port = domain.split(':', 1) if ':' in domain else (domain, 443)
return (host, int(port))
def get_remaining_days(domain):
try:
host, port = get_host_port(domain)
context = ssl.create_default_context()
conn = context.wrap_socket(socket.socket(socket.AF_INET), server_hostname=host)
conn.connect((host, port))
conn.settimeout(3)
# 获取 peer(对方)的证书
cert = conn.getpeercert()
# 证书结束日期
if cert and 'notAfter' in cert:
conn.close()
notAfter = str(cert['notAfter'])
# 日期时间字符串解析为一个 datetime 对象
expiry_date = datetime.datetime.strptime(notAfter, '%b %d %H:%M:%S %Y %Z')
remaining_days = (expiry_date - datetime.datetime.now()).days
print(f"{domain} 的证书剩余有效期为 {remaining_days} 天。")
return remaining_days
except Exception as e:
print(f"获取 {domain} 的证书时出错:{e}")
return None
def dingTalkSign(dingTalkSecret):
# 获取当前时间戳,并将其转换为毫秒级
timestamp = int(time.time() * 1000)
# 将时间戳和钉钉应用的密钥拼接在一起,将拼接后的字符串转换为字节数组
signBefore = ('%s\n%s' % (timestamp, dingTalkSecret)).encode('utf-8')
# 用HMAC-SHA256算法对字节数组进行签名
hsha256 = hmac.new(dingTalkSecret.encode('utf-8'), signBefore, hashlib.sha256)
# 将签名进行Base64编码,将编码后的签名进行URL编码
sign = quote(base64.b64encode(hsha256.digest()))
return {"timestamp": timestamp, "sign": sign}
def sendMessage(dingTalkUrl='', dingTalkSecret=None, message='', atMobiles=[], isAtAll=False):
print("发送内容:", message, atMobiles, isAtAll)
json = {
"msgtype": "text",
"text": {
"content": message,
},
"at": {
"atMobiles": atMobiles,
"isAtAll": isAtAll
}
}
sign = dingTalkSign(dingTalkSecret)
response = requests.post(url=dingTalkUrl, params=sign, json=json)
print("响应内容:", response.json())
if __name__ == "__main__":
file_data = read_yaml("domain_config.yml")
if file_data:
for entry in file_data:
if 'ding-talk' in entry:
dingTalkSecret = entry['ding-talk']['secret']
access_token = entry['ding-talk']['access-token']
if dingTalkSecret is None:
print("未配置钉钉机器人密钥")
if access_token is None:
print("未配置钉钉机器人Token")
else:
# 自定义机器人推送地址
dingTalkUrl = f"https://oapi.dingtalk.com/robot/send?access_token={access_token}"
if dingTalkSecret is not None and 'project' in entry:
project_name = entry['project']['name']
domain_names = entry['project']['domain-name']
print(f"项目名称: {project_name}")
print("域名地址:")
for domain in domain_names:
print(f"{domain}")
remaining_days = get_remaining_days(domain)
if remaining_days is None:
sendMessage(dingTalkSecret=dingTalkSecret, dingTalkUrl=dingTalkUrl, isAtAll=True, message=f'项目名称:{project_name}\n域名地址:{domain}\n无法获取SSL证书有效期!')
# 域名证书有效期剩余天数小于3天推送报警
if remaining_days is not None and remaining_days < 3:
# 发送消息不@任何人
# sendMessage('SSL证书即将过期,请注意续期!')
# 发送消息并@指定人员
# sendMessage(message='SSL证书即将过期,请注意续期!', atMobiles=['13888888888'])
# 发送消息并@所有人员
# 每个机器人每分钟最多发送20条消息到群里,如果超过20条,会限流10分钟。
sendMessage(dingTalkSecret=dingTalkSecret, dingTalkUrl=dingTalkUrl, isAtAll=True, message=f'项目名称:{project_name}\n域名地址:{domain}\n剩余天数:【{remaining_days}天】\nSSL证书即将过期,请注意续期!')
定时任务
- 在线生成CRON:https://tool.lu/crontab
crontab -e
# 定时执行Python脚本,根据自己需求配置执行时间
0 9 * * * /usr/bin/python3 /u01/setup.py
注意: read_yaml(“/u01/domain_config.yml”)必须要用绝对路径,否则crontab执行时报找不到文件