AWS CLIでACMのSSL証明書の有効期限切れアラームを一括で設定してみた

こんにちは。ガジュマル育ててる人です。
SSL証明書の有効期限切れって怖いですよね。AmazonSSLは基本的に自動で更新されますが誤ってCNAMEレコードを消してしまうと更新できないなんてことも。。

そこで今回はAWSのACMに登録されているSSL証明書の有効期限切れ30日前と7日前、1日前など一度に複数のアラームを設定する方法をご紹介します。
コンソールからポチポチの方法は他のサイトでも紹介されていますが、ACMに登録されたSSL証明書が多いとその数だけ設定するのは大変だと思いますので、今回はcliでやってみようと思います。

ステップ① SNSトピックを設定する

※注意
CloudwatchAlarmはリージョンごとに必要なので、リージョンごとに作業が必要なのでその点だけご注意ください。

それではまず、メールで通知させるためにSNSのトピックを作成します。
AWSにログインしてCloudshellを開き、下記を入力します。
example-topicは好きなトピック名に変更してください。

$ aws sns create-topic --name example-topic

実行するとTopicArnが返ってくるので、arnから始まる文字列をコピーします。
{
    "TopicArn": "arn:aws:sns:ap-northeast-1:123456789012:example-topic"
}

コピーした文字列を利用して下記を実行します。
example@example.comは通知したいメールアドレスを入力

$ aws sns subscribe --topic-arn [ここにコピーしたarnから始まる文字列を入れる] --protocol email --notification-endpoint example@example.com

example@example.com宛に「AWS Notification - Subscription Confirmation」という件名のメールが届くので、Confirm subscriptionのリンクをクリックすると準備完了です。

ステップ② ACMに登録されているSSL証明書の情報を取得する

次にACMで使用中のSSL証明書一覧を取得します。
取得にはaws acm list-certificatesコマンドを使用します。

$ aws acm list-certificate
s
        {
            "CertificateArn": "arn:aws:acm:ap-northeast-1:123456789012:certificate/b9e8aafc-e2a5-4a4f-95fd-d0174805d3e4",
            "DomainName": "example.com",
            "SubjectAlternativeNameSummaries": [
                "*.{
    "CertificateSummaryList": [
        {
            "CertificateArn": "arn:aws:acm:region:account:certificate/certificate_ID",
            "DomainName": "example.com"
        "SubjectAlternativeNameSummaries": [
                "example.com",
                "other.example.com"
            ],
            "HasAdditionalSubjectAlternativeNames": false,
            "Status": "ISSUED",
            "Type": "IMPORTED",
            "KeyAlgorithm": "RSA-2048",
            "KeyUsages": [
                "DIGITAL_SIGNATURE",
                "KEY_ENCIPHERMENT"
            ],
            "ExtendedKeyUsages": [
                "NONE"
            ],
            "InUse": false,
            "RenewalEligibility": "INELIGIBLE",
            "NotBefore": "2022-06-14T23:42:49+00:00",
            "NotAfter": "2032-06-11T23:42:49+00:00",
            "CreatedAt": "2022-08-25T19:28:05.531000+00:00",
            "ImportedAt": "2022-08-25T19:28:05.544000+00:00"
        },...
    ]
}

今回必要なのはこの証明書のCertificateArnなので、Arnと該当のドメインを抜き出せるようにqueryをコマンドに挿入します。
※ついでにステータスがISSUSEに絞って、使用されていない証明書は省くようにしてます。

使用の有無にかかわらず出力したい場合は
queryを'CertificateSummaryList[*].[CertificateArn,DomainName]'に変更して実行してください。

$ aws acm list-certificates --query 'CertificateSummaryList[?InUse==`true`].[CertificateArn,DomainName]' --output text

aws:acm:ap-northeast-1:123456789012:certificate/b9e8aafc-e2a5-4a4f-95fd-d0174805d3e4        example.com
aws:acm:ap-northeast-1:123456789012:certificate/5ad6ad9a-839f-4ece-b9cd-975062445521      test.example.com

複数ある場合は複数行出力されるかと思いますので、
このリストをもとに後程ループ処理かけるためこれをlistとして保存してします。

$ aws acm list-certificates --query 'CertificateSummaryList[?InUse==`true`].[CertificateArn,DomainName]' --output text >> list

 

ステップ③ CloudwatchでACMのアラートを設定する

最後にCloudwatchで有効期限切れのアラートを設定していきます。

まずは、準備で作成したsnsのトピックのarnを設定します。

$ export snsarn=(作成したsnsトピックのarnを入力)

最後にループ処理で設定していきます。あまりきれいな処理ではありませんが、
whileループでドメインと証明書のarnを取得したあと、forループで1日、7日、30日それぞれのアラーム設定をいれております。
閾値の日を変更したい方はl5の数値を調整してください。
黄色文字のところはメール通知にかかわる件名や文面にかかわる部分なので、お好みに調整してみてください。

while read line
do
    ACMARN=$(echo ${line}|awk '{print $1}')
    DOMAIN=$(echo ${line}|awk '{print $2}')
    for days in 1 7 30
    do
        aws cloudwatch put-metric-alarm \
        --alarm-name "SSL certificate expires ${days} days (${DOMAIN})" \
        --alarm-description "
        対象ドメイン:${DOMAIN}
        ここにメールにいれたい内容を書き込みます" \
        --alarm-actions ${SNSARN} \
        --namespace AWS/CertificateManager \
        --dimensions Name=CertificateArn,Value=${ACMARN} \
        --metric-name DaysToExpiry \
        --threshold ${days}.0 \
        --comparison-operator LessThanOrEqualToThreshold \
        --evaluation-periods 1 \
        --datapoints-to-alarm 1 \
        --period 86400 \
        --statistic Average
    done
done <list

cloudwatchのcli詳細情報は下記のような設定になっております。
詳しく知りたい方はAWS公式のドキュメントをご覧ください。

aws cloudwatch put-metric-alarm \
コンソール上での表示名(メールの件名にも入る) 
--alarm-name "" \ 
アラームの説明(メールの本文にも入る)
--alarm-description "" \ 
アラーム時に通知されるメールのSNSトピックARN
--alarm-actions ${SNSARN} \ 
cloudwatchのメトリクスを設定(namespace,dimensions,metric-name)を合わせて一意に取得するデータを指定
--namespace AWS/CertificateManager \ 
--dimensions Name=CertificateArn,Value=${ACMARN} \ 
--metric-name DaysToExpiry \
アラートの閾値
--threshold ${days}.0 \
閾値のルール(以上、以下など)
--comparison-operator LessThanThreshold \
アラートの評価 1日(86400秒)の平均値が閾値を1回下回るとアラートとなります。
--evaluation-periods 1 \
--datapoints-to-alarm 1 \
--period 86400 \
--statistic Average


長々と書きましたが、
リージョンごとに①SNSトピック作成、②ACMからARNのリストを作成、③アラームの設定の3ステップをするだけなので、大量に対象があるときはコンソール上の操作よりは早くできそうですね。

最後に

個人的に50件くらい一気に入れることがあったので、今回は一括で入れてしまうためにcliでやりましたが、数件ならやらなかったかもしれません、、
沢山繰り返す作業は、cliなどを使って簡単に設定ができると人為的なミスを減らしていきましょう!

それでは、また!