クライアント認証のために EC2 インスタンス上で Let's Encrypt の証明書で https しているサーバがあり、CloudWatch Alarm でその証明書の有効期限の監視をしたかったのでそのメモ。
CLI で証明書の有効期限のチェック
openssl s_client
の -attime
でエポック秒を指定すれば現在日時ではなくその日時で有効期限がチェックされます。さらに -verify_return_error
を付ければ検証失敗時は終了コードが非0になるので、日時指定の有効期限チェックだけなら下記でできます。
# 有効期限を10日でチェック openssl s_client -connect localhost:443 \ -attime $(( $(date +%s) + 24*60*60*10)) \ -verify_return_error </dev/null
ネットワーク越しではなくローカルの証明書をチェックするなら openssl verify
の -attime
でも同じです。ただし証明書のチェーンも検証されるため、次のように -untrusted
で中間証明書を指定する必要があります。certbot などでローカルに保存された証明書をチェックするならこれでも良いかもしれません。
# 中間証明書を -untrusted に指定して検証 openssl verify \ -untrusted intermediate.crt \ -attime $(( $(date +%s) + 24*60*60*10)) \ server.crt
openssl x509
の -checkend
でも有効期限のチェックができます。この場合は現在日時からの相対で指定します。
# ネットワーク越しにチェック openssl s_client -connect localhost:443 </dev/null | openssl x509 -checkend $((24*60*60*10)) # ローカルの証明書をチェック openssl x509 -in server.crt -checkend $((24*60*60*10))
CLI で証明書の有効期限の残日数を取得
前述の方法で日付指定の有効期限のチェックはできましたが、残りの有効期限の日数をメトリクスとして CloudWatch に保存したかったので、次のように openssl x509
の -enddate
で終了日時を抜き出して date -d
で日時をパースして現在日時からの差分を得るようにしました。
notAfter=$( openssl s_client -connect localhost:443 < /dev/null 2> /dev/null | openssl x509 -noout -enddate | sed -n -e '/^notAfter=/{ s/^notAfter=// p }' ) expire=$(date -d "$notAfter" +%s) now=$(date +%s) days=$(bc -l <<< "scale=4; ($expire - $now) / 24 / 60 / 60")
あとは次のように cloudwatch に放り込めば OK です。
aws cloudwatch put-metric-data \ --region "$region" \ --namespace 'Certificate' \ --metric-name 'ServerCertificateExpiration' \ --value "$days" \ --dimensions "InstanceId=$instance_id"
さいごに
こんな感じのメトリクスが保存されます。
Let's Encrypt の証明書で certbot で自動更新しているのなら有効期限を監視してもあまり意味がない気もする。。。