监控域名SSL证书剩余有效期天数Python脚本(推送钉钉群通知)

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证书即将过期,请注意续期!')

定时任务

crontab -e
# 定时执行Python脚本,根据自己需求配置执行时间
0 9 * * * /usr/bin/python3 /u01/setup.py

注意: read_yaml(“/u01/domain_config.yml”)必须要用绝对路径,否则crontab执行时报找不到文件

  • 11
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: import ssl import socket import datetimedomain_list = ["domain1.com", "domain2.com", "domain3.com"]for domain in domain_list: print("查看域名 " + domain + " 的 SSL 证书过期时间:") ssl_date_fmt = r'%b %d %H:%M:%S %Y %Z' try: hostname = domain context = ssl.create_default_context() s = context.wrap_socket(socket.socket(), server_hostname=hostname) s.connect((hostname, 443)) certificate = s.getpeercert() expire_date = datetime.datetime.strptime(certificate['notAfter'], ssl_date_fmt) print(expire_date) except Exception as e: print(e) ### 回答2: 您好!以下是一段可以从客户端批量查看域名SSL证书过期时间的Python脚本: ```python import ssl import socket from datetime import datetime # 客户端域名列表 domain_list = ['example.com', 'google.com', 'facebook.com'] def get_ssl_expiry(domain): try: # 获取SSL证书有效期 cert = ssl.get_server_certificate((domain, 443)) x509 = ssl.PEM_cert_to_X509(cert) cert_info = x509.get_notAfter().decode('utf-8') # 将日期字符串转换为日期对象 expiry_date = datetime.strptime(cert_info, '%Y%m%d%H%M%SZ') return expiry_date except Exception as e: print(f"无法获取域名 {domain} 的SSL证书信息:{e}") # 批量查看域名SSL证书过期时间 for domain in domain_list: expiry_date = get_ssl_expiry(domain) if expiry_date: days_left = (expiry_date - datetime.now()).days print(f"域名 {domain} 的SSL证书将于 {expiry_date} 过期,还有 {days_left} 天。") ``` 请注意,以上代码仅限于检查域名SSL证书过期时间,且仅适用于默认的HTTPS端口(443)。此外,需要确保您的计算机已安装了Pythonssl模块。 希望对您有帮助! ### 回答3: 以下是一个可以从客户端批量查看域名SSL证书过期时间的Python脚本示例: ```python import ssl import socket import datetime def get_ssl_expiry(hostname): try: ssl_date_fmt = r'%b %d %H:%M:%S %Y %Z' context = ssl.create_default_context() conn = context.wrap_socket(socket.socket(socket.AF_INET), server_hostname=hostname) conn.settimeout(2) # 设置连接超时时间为2秒 conn.connect((hostname, 443)) ssl_info = conn.getpeercert() # 解析证书过期日期 expiry_date = datetime.datetime.strptime(ssl_info['notAfter'], ssl_date_fmt) conn.close() return expiry_date except ssl.SSLError: return '获取SSL证书失败' except socket.gaierror: return '无法解析主机名' except socket.timeout: return '连接超时' if __name__ == '__main__': # 输入要查看的域名列表 domains = ['example.com', 'google.com', 'github.com'] for domain in domains: expiry_date = get_ssl_expiry(domain) # 打印结果 if isinstance(expiry_date, datetime.datetime): print(f'{domain} SSL证书过期时间:{expiry_date}') else: print(f'{domain} 错误信息:{expiry_date}') ``` 脚本的工作原理是使用`ssl`和`socket`库与服务器建立安全连接,并获取SSL证书的过期日期。脚本首先通过`wrap_socket`方法将socket连接包装成SSL连接,然后通过`getpeercert`方法获取证书信息,包括过期日期。最后,脚本打印出每个域名SSL证书过期时间。 请注意,脚本使用了固定的端口443来与服务器建立连接,这是HTTPS默认的端口。如果你想要使用不同的端口,可以修改`conn.connect`的参数。 由于获取SSL证书需要与服务器进行通信,所以需要有网络连接。如果无法建立连接,脚本会返回适当的错误信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逢生博客

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值