ããã«ã¡ã¯ï¼èã®ç©´ã©ãã®NSSã§ãã
ã¿ãªããã®ä¼ç¤¾ã§ã¯ãSSL証ææ¸ã®æå¹æéãã©ã®ããã«ç®¡çãã¦ããã§ããããï¼
æè¿ã§ã¯ãAWSãGCPãªã©ã®ã¯ã©ã¦ããµã¼ãã¹ã管çããSSL証ææ¸ãå©ç¨ãããã¨ã§ã
æå¹æéãåããåã«èªåæ´æ°ãã¦ããããµã¼ãã¹ãããã¾ãã
ããããã¯ã©ã¦ãããã¼ã¸ããªSSL証ææ¸ã使ç¨ã§ããªãé½åããã£ããã
å©ç¨ãã¦ããã¯ã©ã¦ããµã¼ãã¹ã«SSL証ææ¸ã®èªåæ´æ°æ©è½ããªãã£ãããããã¨ãããã¾ãã
èã®ç©´ã©ãã§ã¯ãä»ã¾ã§ã¹ãã¬ããã·ã¼ãã«ãã¡ã¤ã³åã¨æå¹æéãè¨è¼ãã
Google Apps Scriptï¼GASï¼ã使ã£ã¦ãæå¹æéããã¾ã£ããã¡ã¤ã³ãSlackéç¥ããã¨ããæ¹æ³ãã¨ã£ã¦ãã¾ããã
ä¸å¿ããã§ããã§ãã¯ãããã¨ã¯ã§ãã¾ãããæ´æ°ã«ãããã¦ã¹ãã¬ããã·ã¼ããæåã§æ´æ°ããªããã°ãªããã
å¿ããã¨éç¥ãåºç¶ãã¦ãã¾ãã¾ãã
ã¾ããä¸ãä¸ã¹ãã¬ããã·ã¼ãè¨è¼ã®æ¥ä»ãééã£ã¦ããå ´åãæ¤ç¥ã§ããé害ã®åå ã¨ãªãã¾ãã
SSL証ææ¸ã®æå¹æéã®ç¢ºèªã¯ããã®è¨¼ææ¸èªä½ã«ã¢ã¯ã»ã¹ããã®ãä¸çªç¢ºå®ã§ãã
ããã§ãSSL証ææ¸ãç´æ¥ãã§ãã¯ãããã¼ã«ãä½æãã¦ã¿ã¾ããã
1. ä»æ§ã»ã·ã¹ãã æ§æ
ä»åãå®è£ ãããã§ãã¯ãã¼ã«ã®ä¸»ãªä»æ§ã¯æ¬¡ã®éãã§ãã
- æ¯æ¥AM10:00ã«SSL証ææ¸ã®æå¹æéãã§ãã¯ããã
- SSL証ææ¸ã®æå¹æéãè¿ããã¡ã¤ã³ãæ¤ç¥ãã¦Slackã«ã¡ãã»ã¼ã¸ãéç¥ãã
- ãã§ãã¯å¯¾è±¡ã®ãã¡ã¤ã³åãã¡ãã»ã¼ã¸ãéç¥ãå§ããæ¥æ°ãSlackã®WebHookURLã¯å¤é¨ããè¨å®ã§ãã
ä»åã¯CloudWatchãããªã¬ã¼ã¨ãã¦AWS Lambdaï¼ä»¥ä¸Lambdaï¼ã®é¢æ°ãå®è¡ãã¾ãã
ã·ã¹ãã æ§æã¯ã次ã®å³ã®éãã§ãã
2. å®è£
Python3.7ã使ã£ã¦ãLambdaã®é¢æ°ãå®è£ ãã¾ãã å®è£ ããã«ããããã©ã®ããã«Pythonã§SSL証ææ¸ã®æå¹æéããã§ãã¯ããã調ã¹ã¾ããã
çµæããã¡ãã®è¨äºãé常ã«åèã«ãªãã¾ããã®ã§ã ãã¡ãããã¨ã«å®è£ ãã¾ããã qiita.com
以ä¸ãå®è£ ããå 容ã§ãã
import json import datetime import pytz import os import socket import ssl import requests import sys jst = pytz.timezone('Asia/Tokyo') # 1. å®è¡ãã³ãã©ã¼ï¼Lambdaã¯ããããéå§ def lambda_handler(event, context): domains = [x.strip() for x in str(os.getenv('Urls')).split(',')] webhook = os.getenv('IncommingWebhooks') try: # SSLæéãã§ã㯠ssl_expires = {} for domain in domains: is_ssl_expires, ssl_expires_date = ssl_expires_in(domain) if is_ssl_expires: ssl_expires[domain] = ssl_expires_date print(len(ssl_expires)) if len(ssl_expires) != 0: text = f"以ä¸ã®SSL証ææ¸ã{os.getenv('BufferDays')}æ¥ä»¥å ã«æéåãã«ãªãã¾ã" for domain, expired_date in ssl_expires.items(): text += f"\n{domain} - æå¹æé : {expired_date}" send_slack(text) except requests.RequestException as e: print(e) raise e except: print(sys.exc_info()) text = "SSLãã§ãã¯ä¸ã«ã¨ã©ã¼ãçºçãã¾ããã" send_slack(text) raise # æ®æ¥æ°ã®åå¾ def ssl_valid_time_remaining(hostname): expires = ssl_expiry_datetime(hostname) return expires - datetime.datetime.now(jst), expires # SSLãã§ãã¯é¢æ° def ssl_expires_in(hostname): buffer_days=int(os.getenv('BufferDays')) try: remaining, expires = ssl_valid_time_remaining(hostname) return valid_date(remaining, expires, buffer_days) except: return True, "SSLãã§ãã¯ã«å¤±æãã¾ãã" # æå¹æéãã¸ã£ãã¸ããé¢æ° def valid_date(remaining, expires, buffer_days): if remaining < datetime.timedelta(days=0): return True, "æå¹æéåããæé ãã§ã" elif remaining < datetime.timedelta(days=buffer_days): return True, expires.strftime("%Y/%m/%d") else: return False, "" # æå¹æéã®åãåºã def ssl_expiry_datetime(hostname): ssl_date_fmt = r'%b %d %H:%M:%S %Y %Z' utc_datetime = datetime.datetime.strptime( ssl_expiry(hostname), ssl_date_fmt) return utc_datetime.astimezone(jst) # æå¹æéã®åå¾ def ssl_expiry(hostname): print("{}ã®æ¥ç¶ãéå§ãã¾ãã".format(hostname)) context = ssl.create_default_context() with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as sock: with context.wrap_socket(sock, server_hostname=hostname) as ssock: ssock.settimeout(3.0) ssock.connect((hostname, 443)) ssl_info = ssock.getpeercert() ssock.close() print(ssl_info) return ssl_info['notAfter'] # ssl_info['notAfter'] ã証ææ¸ã®æé # Slackéç¥ def send_slack(text): webhook = os.getenv('IncommingWebhooks') print('slackéç¥') requests.post(webhook, data=json.dumps({ # éç¥å 容 'text': text }))
å®è£ ã®å 容ã«ã¤ãã¦è§£èª¬ãã¾ãã
ä¸è¨ã®å®è£
ã®ãªãã§ãos.getenv()
ã¨ãªã£ã¦ããé¨åãç°å¢å¤æ°ãåç
§ãã¦ããç®æã§ãã
ç°å¢å¤æ°ã«ã¯ã次ã®ãããªå¤ãæå®ãã¾ãã
ãã¼ | å¤ |
---|---|
Urls | SSLãã§ãã¯ããããã¡ã¤ã³åãã«ã³ãåºåãã§è¤æ°æå®ã |
BufferDays | æå¹æéãéç¥ãå§ããæ¥æ° |
IncommingWebhooks | Slackã®WebHookURL |
ç°å¢å¤æ°ã§è¨å®ãããã¡ã¤ã³ã«å¯¾ãã¦SSLã½ã±ããéä¿¡ãè¡ããJSONå½¢å¼ã§SSL証ææ¸ã®æ
å ±ãåå¾ãã¾ãã
ã½ã±ããéä¿¡ã®è©³ãã解説ã¯Pythonå
¬å¼ããã¥ã¡ã³ããåããã¦ã確èªãã ããã
åå¾ããJSONã®ãã¡æå¹æé['notAfter']ã ããåå¾ãã¾ãã
# æå¹æéã®åå¾ def ssl_expiry(hostname): print("{}ã®æ¥ç¶ãéå§ãã¾ãã".format(hostname)) context = ssl.create_default_context() with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as sock: with context.wrap_socket(sock, server_hostname=hostname) as ssock: ssock.settimeout(3.0) ssock.connect((hostname, 443)) ssl_info = ssock.getpeercert() ssock.close() print(ssl_info) return ssl_info['notAfter'] # ssl_info['notAfter'] ã証ææ¸ã®æé
åå¾ã§ããæ¥ä»ã¯Jul 19 14:59:59 2020 GMT
ã®ãããªæååã«ãªã£ã¦ããã®ã§ãæ¥ä»ã«å¤æãã¦æ®ãæ¥æ°ãè¨ç®ãã¾ãã
ãã¨ã¯ç®åºããæ®ãæ¥æ°ãå¤å®ãã¦Slackã«éç¥ããã°å®æã§ãã
ãªããä»åã¯ã¨ã©ã¼ã¨ãªã£ãæãSSLãã§ãã¯ã«å¤±æãã¾ãããã¨Slackã«éç¥ããããã«ãã¾ããã
CloudWatchã®è¨å®
é¢æ°ã®è¨å®ãçµãã£ãããããªã¬ã¼ãè¨å®ãã¾ãã
CloudWatchã³ã³ã½ã¼ã«ãéããã¤ãã³ãã®ä¸ã®ã«ã¼ã«ãé¸æãã¾ãã
ãã«ã¼ã«ã®ä½æããã¿ã³ãã¯ãªãã¯ãã¦ã«ã¼ã«ä½æç»é¢ç»é¢ãéããcronå¼ãè¨å®ãã¾ãã
æ¯æ¥AM10:00éç¥ããå ´åãæ¥æ¬æéã¯ãã©ã¹9æéã¨ãªãã®ã§ã
0 1 * * ? *
ã¨è¨å®ãã¾ãã
å¹³æ¥ã®ã¿éç¥ããå ´åã
0 1 ? * 2-6 *
ã¨è¨å®ãã¾ãã
ã¾ãã¿ã¼ã²ããã«å
ã»ã©ä½æãããLambdaé¢æ°ãæå®ãã¾ãã
æééãã«Slackéç¥ãé£ã¹ã°æåã§ãã
ã¾ã¨ã
ä»åã¯ãSSL証ææ¸ã®æå¹æéãã§ãã¯ã«ã¤ãã¦ãç´¹ä»ãã¾ããã
SSL証ææ¸ã®æ´æ°ã¯ãï¼ã¤å¿ããã ãã§ã·ã¹ãã ãåããªããªã£ã¦ãã¾ããã¨ãããã®ã§ã
éè¦ãªãã¨ãªã®ã§ãããæ¤ç¥ãã¥ããã®ãåé¡ã§ãã
èªåæ´æ°ã§ããã°è¨ããã¨ã¯ãªãã§ããããããããªé½åã§ã§ããªãã¨è¨ãå ´åã«ä»åã®æ¹æ³ã試ãã¦ã¿ã¦ããã ããã¨å¹¸ãã§ãã
P.S.
åãã¦æå¹ã§æ¡ç¨èª¬æä¼ãå®æ½ãããã¨ã«ãªãã¾ããï¼è¿é£ã«ãä½ã¿ã®æ¹ã¯ãã²ãç³ãè¾¼ã¿ãã ããï¼
ä»å¹´ãLTä¼ãéå¬ãã¾ãï¼
ä»ã«ãã«ã¸ã¥ã¢ã«é¢è«ã¯éæåä»ä¸ã§ãã®ã§ãæ°ã«ãªãæ¹ã¯ãã²ãç³ãè¾¼ã¿ãã ãã