域名SSL证书到期监控告知
域名证书到期提前监控告知
通过aliyun 云解析的域名
- 对该域名SSL到期监控
- 通过钉钉 Webhook 消息通知
**相关官方文档 **
阿里云云解析SDK信息:https://next.api.aliyun.com/api/Alidns/2015-01-09/DescribeDomainRecords?sdkStyle=old¶ms={}
钉钉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¶ms={}
依赖包: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×tamp=%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()