阿里云证书过期时间监测

我只监控了slb下使用的ssl证书的过期时间,然后以prometheus能读取的metrics格式供prometheus采集。因为我们是prometheus-operator,通过helm发布的时候添加一个servicemonitor即可。想要监控所有证书调用阿里云证书系列产品api即可。

  1 #!/usr/bin/python
  2 # -*- coding: UTF-8 -*-
  3 
  4 '''
  5 Date: 2019-11-26
  6 Blog: www.cnblogs.com/qinghe123
  7 '''
  8 
  9 import re,sys
 10 import base64
 11 import json
 12 import time
 13 from datetime import datetime
 14 import hmac
 15 import urllib
 16 
 17 import argparse
 18 from pprint import pprint
 19 from urllib import request
 20 import uuid
 21 import os
 22 from sys import exit
 23 
 24 import dateutil.parser
 25 from prometheus_client import start_http_server, Summary
 26 from prometheus_client.core import GaugeMetricFamily, REGISTRY
 27 from hashlib import sha1
 28 
 29 DEBUG = int(os.environ.get('DEBUG', '0'))
 30 #DEBUG = True
 31 aliyun_access_key = os.environ.get('AccessKeyID',None)
 32 aliyun_access_secret = os.environ.get('AccessKeySecret',None)
 33 
 34 COLLECTION_TIME = Summary('request_aliyun_api_seconds', 'Time spent to collect metrics from aliyun')
 35 
 36 
 37 class AliyunSignature():
 38     """获取阿里云签名和数据"""
 39     Timestamp = datetime.utcnow().isoformat()
 40     SignatureNonce = str(uuid.uuid1())
 41 
 42     def __init__(self,config,Id=None,key=None):
 43         '''
 44             this is aliyun api auth single, now, any api request parame to main
 45         '''
 46         assert config['Action'], "Value error"
 47 
 48         self.config = config
 49         self.url = 'http://slb.aliyuncs.com'
 50         self.id = Id
 51         self.Key = key
 52         self.__data = dict({
 53             "AccessKeyId": self.id,
 54             "SignatureMethod": 'HMAC-SHA1',
 55             "SignatureVersion": "1.0",
 56             "SignatureNonce": self.SignatureNonce,
 57             "Timestamp": self.Timestamp,
 58             "Version": "2014-05-15",
 59             "Format": "JSON"
 60         }, **self.config)
 61 
 62     @classmethod
 63     def reload(cls, body):
 64         cls.Timestamp = datetime.utcnow().isoformat()
 65         cls.SignatureNonce = str(uuid.uuid1())
 66         return cls(config=body)
 67 
 68     @property
 69     def data(self):
 70         return self.__data
 71 
 72     @data.setter
 73     def data(self, value):
 74         if self.__data:
 75             raise AssertionError("not allow opeartion")
 76         self.__data = value
 77 
 78     @staticmethod
 79     def percent_encode(encodeStr):
 80         if isinstance(encodeStr, bytes):
 81             encodeStr = encodeStr.decode(sys.stdin.encoding)
 82         res = urllib.parse.quote_plus(encodeStr.encode('utf-8'), '')
 83         res = res.replace('+', '%20').replace('*', '%2A').replace('%7E', '~')
 84         return res
 85 
 86     def auth(self):
 87         base = sorted(self.data.items(), key=lambda data: data[0])
 88         canstring = ''
 89         for k, v in base:
 90             canstring += '&' + self.percent_encode(k) + '=' + self.percent_encode(v)
 91         self.Key += "&"
 92         data = 'GET&%2F&' + self.percent_encode(canstring[1:])
 93         self._salt(data)
 94         return self.data
 95 
 96     def _salt(self, data):
 97         result = data.encode(encoding='utf-8')
 98         uri = hmac.new(self.Key.encode("utf-8"), result, sha1).digest()
 99         key = base64.b64encode(uri).strip()
100         self.data['Signature'] = key
101         return self.data
102 
103     def generate_url(self):
104         parameters = self.auth()
105         url = self.url + '/?' + urllib.parse.urlencode(parameters)
106         return url
107 
108     def do_action(self):
109         url = self.generate_url()
110         request = urllib.request.Request(url)
111         try:
112             conn = urllib.request.urlopen(request)
113             response = conn.read().decode()
114         except  urllib.error.HTTPError as e:
115             print(e.read().strip())
116             raise SystemExit(e)
117 
118         try:
119             res = json.loads(response)
120         except ValueError as e:
121             raise SystemExit(e)
122         return res
123 
124 class AliyunResourceConllector():
125     """prometheus metrics"""
126     def __init__(self,product=None):
127         self.prodct = product
128 
129     def format_metric_name(self):
130         return 'aliyun_%s' % self.prodct
131 
132     def collect(self):
133         config = {
134             "Action": "DescribeServerCertificates",
135             "RegionId": "cn-shanghai"
136         }
137         auth_obj = AliyunSignature(config=config, Id=aliyun_access_key, key=aliyun_access_secret)
138         auth_obj.reload(config)
139         response = auth_obj.do_action().get('ServerCertificates').get('ServerCertificate')
140 
141         sub_metric_list = ["CreateTime","ExpireTime"]
142         for instance in response:
143             for sub_metric in sub_metric_list:
144                 snake_case = re.sub('([A-Z])', '_\\1', sub_metric).lower()
145                 date_time = self.getDateTimeFromISO8601String(instance.get(sub_metric))
146                 uninx_time = int(time.mktime(date_time.timetuple()))
147                 gauge = GaugeMetricFamily(self.format_metric_name() + snake_case, 'aliyun ssl certificate',labels=['domainname','sslname'])
148                 gauge.add_metric([instance.get('CommonName'),instance.get('ServerCertificateName')],uninx_time)
149                 yield gauge
150 
151     def _info(self,obj):
152         config = {
153             "Action": "DescribeServerCertificates",
154             "RegionId": "cn-shanghai"
155         }
156 
157         response = obj.do_action().get('ServerCertificates').get('ServerCertificate')
158         obj.reload(config)
159         return response
160 
161     @staticmethod
162     def getDateTimeFromISO8601String(s):
163         d = dateutil.parser.parse(s)
164         return d
165 
166 def parse_args():
167     parser = argparse.ArgumentParser(
168         description='jenkins exporter args jenkins address and port'
169     )
170     parser.add_argument(
171         '-k', '--keyid',
172         metavar='key',
173         required=False,
174         help='aliyun access key Id',
175         default=os.environ.get('AccessKeyID', 'LTAIdmc9wg0MxRD7')
176     )
177     parser.add_argument(
178         '-s', '--secret',
179         metavar='secret',
180         required=False,
181         help='aliyun access key secret',
182         default=os.environ.get('AccessKeySecret')
183     )
184     parser.add_argument(
185         '-p',
186         metavar='project',
187         required=False,
188         help='aliyun project type(ecs,slb,ssl...)',
189         default=os.environ.get('PROJECT_TYPE','ssl')
190     )
191     parser.add_argument(
192         '-r',
193         metavar='RegionId',
194         required=False,
195         help='aliyun resource region(cn-hangzhou,cn-shanghai...)',
196         default=os.environ.get('REGION_ID','cn-shanghai')
197     )
198 
199     return parser.parse_args()
200 
201 if __name__ == "__main__":
202     config = {
203         "Action": "DescribeServerCertificates",
204         "RegionId": "cn-shanghai"
205     }
206     collector = AliyunResourceConllector('ssl')
207     REGISTRY.register(collector)
208     print("Polling . Serving at port: 8000")
209     start_http_server(8000)
210     while True:
211         time.sleep(1)

 

posted @ 2019-12-04 10:42  一米八大高个儿  阅读(418)  评论(0编辑  收藏  举报