域名SSL证书到期监控告知

域名证书到期提前监控告知

通过aliyun 云解析的域名

  • 对该域名SSL到期监控
  • 通过钉钉 Webhook 消息通知

**相关官方文档 **

阿里云云解析SDK信息:https://next.api.aliyun.com/api/Alidns/2015-01-09/DescribeDomainRecords?sdkStyle=old&params={}
钉钉Webhook添加配置:https://open.dingtalk.com/document/robots/custom-robot-access

环境

Python 3.9.6 (default, Jun 29 2021, 06:20:32) 
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

**依赖包 **

pip install aliyun-python-sdk-core
pip install aliyun-python-sdk-alidns==2.6.32

详细脚本内容

#!/usr/bin/env python
# coding=utf-8
# Author    : baolin2200
# Contact   : baolin2200@gmail.com
import json
import math
import subprocess
import urllib.parse
import requests
import hmac
import hashlib
import base64
import urllib.parse
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.auth.credentials import AccessKeyCredential
from aliyunsdkalidns.request.v20150109.DescribeDomainRecordsRequest import DescribeDomainRecordsRequest
import time
"""
需求:
    使用阿里云云解析做域名解析的 域名,通过钉钉 消息的形式 告知SSL 证书到期时间,以及详情。
功能:
    1. 手动指定域名列表
    2. 根据域名循环遍历 域名的解析记录
    3. 请求解析域名,获取SSL 到期时间
    4. 即将到期的发送 钉钉推送通知
"""

# rr_domain_list = [{'rr_domain': 'www.baidu.com', 'rr_type': 'A', 'rr_Value': '111.111.111.36',
#                    'expire_date': '2022-12-23 23:59:59'}, ]
rr_domain_list = []


def get_domain(CurrentPage, domain):
    """
    阿里云云解析SDK信息:https://next.api.aliyun.com/api/Alidns/2015-01-09/DescribeDomainRecords?sdkStyle=old&params={}
        依赖包:pip install aliyun-python-sdk-core
              pip install aliyun-python-sdk-alidns==2.6.32
    :param CurrentPage:
    :param domain:
    :return:
    """
    client = AcsClient(region_id='cn-hangzhou', credential=credentials)
    request = DescribeDomainRecordsRequest()
    request.set_accept_format('json')
    request.set_DomainName(domain)
    # 当前页数
    request.set_PageNumber(CurrentPage)
    # 状态为 正常 的解析记录
    request.set_Status("Enable")
    # 每页 多少条
    request.set_PageSize(100)
    response = client.do_action_with_exception(request)
    dict_res = json.loads(response)
    Record_list = dict_res.get("DomainRecords").get("Record")
    # print(Record_list)
    for Record in Record_list:
        # 解析类型 为A记录 或 CNAME 类型
        if Record.get("Type") == "A" or Record.get("Type") == "CNAME":
            rr_domain = Record.get("RR") + "." + Record.get("DomainName")
            rr_type = Record.get("Type")
            rr_Value = Record.get("Value")
            x = {"rr_domain": rr_domain, "rr_type": rr_type, "rr_Value": rr_Value}
            rr_domain_list.append(x)

    # 获取总解析条数
    TotalCount = dict_res.get("TotalCount")
    # 获取总页数
    CurrentPage_count = math.ceil(TotalCount / 100)
    if CurrentPage == 1:
        return CurrentPage_count


# 获取 域名证书过期时间
def curl_url(dict_domain):
    """
    # 请求拼接后的域名 https://www.baidu.com
    :param domain:
    :return:
    """
    cmd = "curl -vI --connect-timeout 2 -m 2 https://%s" % dict_domain.get("rr_domain")
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout = p.stderr.read()
    stderr = p.stderr.read()
    expire_date = "null"
    ssl_verify = True
    if stderr:
        print("获取证书过期时间出错!!!!", dict_domain, )
    else:
        lines = iter(stdout.splitlines())
        for line in lines:
            line = line.decode()
            if "expire date" in line:
                expire_date_temp = line.split("date: ")[-1]
                expire_date = time.strptime(expire_date_temp, "%b %d %H:%M:%S %Y GMT")
                expire_date = time.strftime("%Y-%m-%d %H:%M:%S", expire_date)
                break
            # 证书不匹配过滤
            if "curl: (60)" in line or "curl: (51)" in line:
                ssl_verify = False
        if not ssl_verify and expire_date != 'null':
            expire_date = '0000-00-00 00:00:00'
        # 如果证书过期时间为 null 设置到期时间为 9999-12-31 00:00:00
        if expire_date == 'null':
            expire_date = '9999-12-31 00:00:00'
        # 获取证书过期时间 {'rr_domain': 'www.baidu.com', 'rr_type': 'A', 'rr_Value': '111.111.111.36', "expire_date": "2022-12-23 23:59:59"}
        dict_domain["expire_date"] = expire_date
        # print("获取证书过期时间", dict_domain)


def send_dingding():
    """
    钉钉Webhook
        参考:https://open.dingtalk.com/document/robots/custom-robot-access
    :return:
    """
    timestamp = str(round(time.time() * 1000))
    secret_enc = secret.encode('utf-8')
    string_to_sign = '{}\n{}'.format(timestamp, secret)
    string_to_sign_enc = string_to_sign.encode('utf-8')
    hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
    sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
    dd_url = "https://oapi.dingtalk.com/robot/send?access_token=%s&timestamp=%s&sign=%s" % (access_token, timestamp, sign)
    text_dist = {
     "msgtype": "markdown",
     "markdown":
         {
             "title": "SSL证书即将过期列表",
             "text": ""
             },
              "at": {
                  "atMobiles": [
                      # 需要 @ 人员手机号
                      "150XXXXXXXX"
                  ],
                  "atUserIds": [
                      # 需要 @ 人员 ID
                      "user123"
                  ],
                  # 是否 @ 全员
                  "isAtAll": False
              }
        }
    header = {
        "Content-Type": "application/json"
    }
    text = "### SSL证书即将过期列表 \n"
    for domain in rr_domain_list:
        # 当前时间戳
        now_time = time.time()
        # 证书时间戳
        domain_time_mktime = (time.mktime(time.strptime(domain.get("expire_date"), "%Y-%m-%d %H:%M:%S")))
        # 检查证书到期时间少于 43200 秒(一个月) 统计数据发送 钉钉通知。
        if domain_time_mktime - now_time < exp_time:
            detail_info = ' [详情]({})'.format(domain.get("rr_domain") + ' ' + domain.get("rr_type") + ' ' + domain.get("rr_Value"))
            text += '- ' + domain.get("rr_domain") + ' ' + "到期时间: " + domain.get("expire_date") + detail_info + ' \n'
        else:
            continue
    text_dist['markdown']['text'] = text
    if text_dist.get("markdown").get("text") != "### SSL证书即将过期列表 \n":
        resp = requests.post(dd_url, headers=header, json=text_dist)
        print("发送钉钉", resp.text)


# 获取解析记录
def cron_add_orm(domain):
    """
    CurrentPage_count 获取 阿里云云解析解析记录总页数
    :param domain:
    :return:
    """
    CurrentPage_count = get_domain(1, domain)
    for i in range(CurrentPage_count):
        if i + 1 == 1:
            continue
        get_domain(i + 1, domain)


if __name__ == '__main__':
    # 阿里云 访问 云解析权限  AccessKey
    credentials = AccessKeyCredential('<your-access-key-id>', '<your-access-key-secret>')
    # 钉钉 加签处 SEC
    secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    # 钉钉 Webhook处 access_token
    access_token = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
    # 在阿里云做解析的 域名列表
    domain_list = ["xxxxx.com", "xxxxx.cn"]
    # 即将到期时间
    exp_time = 30*24*60
    for domain in domain_list:
        cron_add_orm(domain)
    for rr_domain in rr_domain_list:
        curl_url(rr_domain)
    send_dingding()
posted @ 2018-08-29 15:18  叨客厨子  阅读(488)  评论(0编辑  收藏  举报