Use AWS SNS with Lambda function to monitor SSL Certificate Expiry.

使用AWS SNS服務搭配Lambda來定時檢查SSL憑證到期狀態。

現在大多數的網站都會使用HTTPS來做加密,未來也會變成主流。
小一點的網站並不一定會使用付費的SSL憑證,轉而使用免費然後天數少一點的免費憑證來做加密,例如Let’s encrypt。天數短的憑證缺點就是,如果忘記Renew,瀏覽器就會顯示不安全,會影響用戶端瀏覽體驗,尤其如果是政府或金融單位萬萬不可讓這件事情發生。大部分的形況下都會搭配Auto renew定期排程方式進行自動更新。但是有時候偶爾會有出錯沒Auto renew,而管理員沒有發現到造成憑證過期的窘況。
這篇主要在介紹:利用AWS SNS通知服務來檢查並且在快到期時利用Telegram Bot來發送通知,如果您會設定想發送Email也是可以的。
這一篇是參考國外原文,有興趣可以參考一下!(原文另開分頁)

會使用到的服務包含:
AWS Lambda、AWS Cloud watch、AWS SNS

運作流程:
Cloud Watch run daily rule → AWS Lambda → 條件符合透過SNS發送TG訊息,不符合沒有動作。

Prerequisites:

  1. Telegram Bot已申請,取得接收訊息的Chat id和Bot本身的Token
  2. 已經設定好AWS SNS可以發送通知到Telegram
    原文是介紹透過AWS SNS發送Email通知,你可以去這裡看看(另開分頁)

01. 登入AWS Lambda的服務然後點Create function

02.Author from scratch(預設不動)
名稱:自己決定
Runtime:Python 2.7

03. Permission下面點選Choose or create an execution role
點選Create a new role from AWS policy permissions
Role name:自己決定
Policy templates:Amazon SNS publish policy
按下Create function。

04. 建立之後到 Github的這裡去下載這一段Lambda程式碼。程式碼我貼在下方。

import socket
import ssl, boto3
import re,sys,os,datetime

def ssl_expiry_date(domainname):
    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=domainname,
    )
    # 3 second timeout because Lambda has runtime limitations
    conn.settimeout(3.0)
    conn.connect((domainname, 443))
    ssl_info = conn.getpeercert()
    return datetime.datetime.strptime(ssl_info['notAfter'], ssl_date_fmt).date()

def ssl_valid_time_remaining(domainname):
    """Number of days left."""
    expires = ssl_expiry_date(domainname)
    return expires - datetime.datetime.utcnow().date()

def sns_Alert(dName, eDays, sslStatus):
    sslStat = dName + ' SSL certificate will be expired in ' + eDays +' days!! '
    snsSub = dName + ' SSL Certificate Expiry ' + sslStatus + ' alert'
    print sslStat
    print snsSub
    response = client.publish(
    TargetArn="arn:aws:sns:ap-southeast-1:41367:ssl-expiry-alerts",
    Message= sslStat,
    Subject= snsSub
    )
    
    
#####Main Section
client = boto3.client('sns')
def lambda_handler(event, context):
    f = ['www.google.com']
    for dName in f:
        print(dName)
        expDate = ssl_valid_time_remaining(dName.strip())
        (a, b) = str(expDate).split(',')
        (c, d) = a.split(' ')
    # Critical alerts 
        if int(c) < 15:
            sns_Alert(dName, str(c), 'Critical')
      # Frist critical alert on 20 th day      
        elif int(c) == 20:
            sns_Alert(dName, str(c), 'Critical')
    #third warning alert on 30th day      
        elif int(c) == 30:
            sns_Alert(dName, str(c), 'Warning')
    #second warning alert on 40th day
        elif int(c) == 40:
            sns_Alert(dName, str(c), 'Warning')
    #First warning alert on 50th day      
        elif int(c) == 50:
            sns_Alert(dName, str(c), 'Warning')
        else:
            print('Everything Fine..')

05. 修改程式碼裡面的ARN,改成你自己的SNS Topic裡面的目標ARN,看你想用TG或是EMail可以在這裡修改。如果想同時發多目標(TG+Email之類的),可能需要修改裡面的程式碼或是另外建一個Function也可以。我就不另外敘述了。

06. 修改檢查的網址,如果有多個網址可以用逗號隔開。
例如:’www.google.com,tw.yahoo.com’
下面的檢查部分,你可以去修改天數。或是增減判斷天數項目。
Save之後停留在這個畫面

07. 打開Cloud Watch到Event / Rules,按Create rule

08. Event Source:Fixed rate of 1 Days ,或著是你可以自己決定縮短檢測時間。不建議把時間拉長,因為根據上面的程式碼判斷,如果兩天以上一次,有可能你不會收到警告通知。

09. 右側Targets下拉選擇Lambda function,選擇你剛剛做好的Function,然後按下Configure detail

10. 取個名字然後Create rule

11. 然後我們回到AWS Lambda剛剛的畫面來做一下測試,下拉選Configure test events

12. 下拉這裡選Amazon CloudWatch,然後Save起來。

13. 回到剛剛頁面由於程式碼是判斷完全等於而不是大於小於,所以先確認你的SSL憑證剩下幾天然後把其中一個判斷式先改成天數跟他一樣。完成後Save,然後按Test。你會看到下面的執行結果。

14. 如果你有設定成功,同時Telegram也會收到傳過來的訊息。

完成後記得要把天數改回去。
這個監控主要是預防SSL憑證Auto renew失效時,至少你會知道要趕快修正或手動Renew。