Amazon Certificate Managerの証明書DNS認証を自動化するbashスクリプト

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

先日AWSの機能追加があり、Amazon Certificate Manager(ACM)の証明書認証がDNS CNAMEレコードで行えるようになったことが発表され、弊社ブログでも取り上げました。

今まではメール認証にしか対応していなかったため、自動化の障壁が少し高いというのが現実でしたが、DNS認証に対応したということで自動化がかなりしやすくなりました。

今回は、ACMの証明書リクエストからRoute53を利用してDNSの認証レコード登録を行い、実際に認証が受理されてACMの証明書が発行されるまでを自動化したbashのスクリプトを作成しました。

仕様

スクリプトの仕様および動作前提は以下のとおりです。

仕様

  • スクリプトの引数でドメイン名を指定する
  • 引数で指定されたドメインのワイルドカード証明書を発行する
  • DNSレコード登録後、認証処理が完了するまで何度かリトライを実施する

動作前提

  • AWSのクレデンシャル設定が適切に行われていること
  • Route53のHostedZoneが作成済であること
  • Route53のHostedZoneのNameが、そのAWSアカウント内でただ一つであること。言い換えると、同名のHostedZoneが存在しないこと

実装

以下のシェルスクリプトが全てです。

#!/bin/bash

set -e

# 証明書リクエストと必要なDNSレコードの取得
domainName=$1
certificateArn=$(aws acm request-certificate --domain-name *.${domainName} --validation-method DNS | jq -r '.CertificateArn')
echo "request certificate: DONE"
dnsOptions=$(aws acm describe-certificate --certificate-arn ${certificateArn} | jq -r '.Certificate.DomainValidationOptions[0].ResourceRecord')

# Route53に認証のためのDNSレコードを登録
hostedZoneId=$(aws route53 list-hosted-zones | jq -r '.HostedZones[] | select(.Name == "'${domainName}'.") | .Id')
changeBatch=$(cat << EOS
{
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": $(echo ${dnsOptions} | jq .Name),
        "Type": $(echo ${dnsOptions} | jq .Type),
        "TTL": 300,
        "ResourceRecords": [
          { "Value": $(echo ${dnsOptions} | jq .Value) }
        ]
      }
    }
  ]
}
EOS
)
aws route53 change-resource-record-sets \
  --hosted-zone-id ${hostedZoneId} \
  --change-batch "${changeBatch}" > /dev/null
echo "register DNS record: DONE"

# 証明書の認証が通るまでリトライ
DESIRED_STATUS="ISSUED"
status=""
counter=1
MAX_RETRIES=10
while [ "${DESIRED_STATUS}" != "${status}" ] ; do 
  echo "checking certificate status...(${counter}/${MAX_RETRIES})"
  status=$(aws acm describe-certificate --certificate-arn ${certificateArn} | jq -r '.Certificate.Status')
  counter=$((counter + 1))
  if [ ${counter} -gt ${MAX_RETRIES} ]; then
    >&2 echo "Failed to validate domain. Program exits in error."
    exit 1
  fi
  sleep 15
done

echo "validate DNS record: DONE."
exit 0

ACMのrequest-certificateAPIで証明書リクエストを発行した後、describe-certificateAPIを実行することで証明書認証のためのDNSレコードを取得することが可能です。

その値をRoute53 APIを利用して登録し、CertificateのステータスがPENDING(認証待ち)からISSUED(発行済み)に変わるのを待っています。

このスクリプトをissue-certificate.shとして保存して実行すると、以下のような出力となります。引数のドメイン名は適宜変更してください。

$ ./issue-certificate.sh example.com
request certificate: DONE
register DNS record: DONE
checking certificate status...(1/10)
validate DNS record: DONE.
$ 

簡単ではありますが、以上です。お役立てください。