Lambda を使って SSL サーバ証明書の有効期限をチェックする
Posted on
- #aws
SSL サーバ証明書の更新は何かと忘れがちで、大手サイトでもたまに有効期限切れで事故ったりしています。常時 SSL/TLS が当たり前となった現在では、機会損失だけでなく信用も失いかねません。
ドメイン認証 (DV) 証明書であれば更新作業のいらない AWS Certificate Manager が使えるのですが、EV SSL 証明書だとそういうわけにもいきません。
更新を忘れないために Zabbix などの監視ソフトウェアでチェックしている人が多いと思いますが、サーバを立てずにもっと手軽に導入できる方法として今回は Lambda を使ってみました。監視ソフトウェアと比べてサーバの運用が不要で、かつ 0 円で構築できるというメリットがあります。
openssl コマンドで証明書の有効期限を取得する
証明書の有効期限を取得するには openssl
コマンドを使うのが手っ取り早いです。
$ openssl s_client -connect www.google.co.jp:443 -servername www.google.co.jp < /dev/null 2> /dev/null | openssl x509 -text | grep 'Not After'
Not After : Sep 28 08:03:00 2016 GMT
OpenSSL 0.9.8 系だと SNI の実装に問題があるようで -servername
オプションをつけないと "sslv3 alert handshake failure" というエラーになります。
Python で監視スクリプトを書く
子プロセスでさっきのコマンドが叩ければいいので Node.js や Java でもいいのですが、日時計算が簡単な Python で書いてみます。
有効期限が 60 日を切ったら SNS へ通知して、そこからメールを送信しています。
from datetime import datetime
import boto3
import re
import subprocess
threshold_days = 60
topic_arn = "arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:cert_expire_alert"
domains = [
"www.google.co.jp",
"..."
]
def get_datetime(string):
date = re.search(r"Not After : (.+)", string)
return datetime.strptime(date.group(1), '%b %d %H:%M:%S %Y %Z')
def get_cert_expire_date(domain):
command = "openssl s_client -connect %s:443 -servername %s < /dev/null " \
"2> /dev/null | openssl x509 -text | grep 'Not After'" % (domain, domain)
output = subprocess.check_output(command, shell=True)
expire_date = get_datetime(output)
return expire_date
def publish_sns(topic_arn, subject, message):
client = boto3.client("sns")
response = client.publish(
TopicArn = topic_arn,
Subject = subject,
Message = message
)
return response
def lambda_handler(event, context):
for domain in domains:
expire_date = get_cert_expire_date(domain)
delta_date = expire_date - datetime.now()
print "%s: %s days" % (domain, delta_date.days)
if delta_date.days < threshold_days:
subject = "Cert Expire Alert: %s" % domain
message = "Warning: The SSL server certificate is disabled after %s days." % delta_date.days
publish_sns(topic_arn, subject, message)
SNS へ通知する必要があるので、
- Lambda に紐付けるロールに SNS の権限を追加
- No VPC かインターネットに出れる VPC で実行
という点に気をつける必要があります。あとは Triggers の設定から CloudWatch Events のスケジュール機能を追加して 1 日おきに実行します。
まとめ
有効期限までの残日数で処理を分岐すれば、例えば 1 週間を切ると Twilio 経由で電話をかけることも簡単に実装できそうです。
サーバレスという文脈で語られることが多い Lambda ですが、ちょっとした運用ツールでも Lambda は活用できそうです。