という話

技術ブログにしたい

Route53+DNS-01のLet'sEncryptを自動更新する

ググると日本語の記事も結構出てくるんですが、どれも私の環境ではうまく動かなかったので自分なりにやりました。

前提

  • CentOS7
  • certbotcertbot-external-authインストール済み
  • awsコマンドがインストール済み
  • aws configure 済みで、Route53の権限を持ってる

certbot-external-authは下記でインストール

https://github.com/EnigmaBridge/certbot-external-auth
上のURLを参考に

pip install certbot
pip install certbot-external-auth

でインストールできる。

コード

renew.sh

#!/bin/sh

certbot certonly \
  -d sub1.example.com \
  -d sub2.example.com \
  --email test@example.com \
  --agree-tos \
  --preferred-challenges dns \
  --keep-until-expiring \
  --text \
  --configurator certbot-external-auth:out \
  --certbot-external-auth:out-public-ip-logging-ok \
  --certbot-external-auth:out-handler /path/to/hook.sh

# apacheなら
systemctl restart httpd

# nginxなら
# systemctl restart nginx


hook.sh

#!/bin/sh

set -e
cmd="$1"
shift

case "$cmd" in
    perform)
        HOSTED_ZONE_ID="/hostedzone/YOUR_HOSTED_ZONE_ID"
        FILENAME=`date "+%Y%m%d%H%M%S"`.json
        DIR=/path/to/json_dir/

        # 環境変数チェック
        if [ -z "$domain" ] || [ -z "$validation" ]; then
                echo "Undefined environment variable"
                exit 1
        fi

        # 設定用jsonファイルを書き出し
        cat <<EOT > $DIR$FILENAME
{
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "_acme-challenge.$domain",
        "Type": "TXT",
        "TTL": 60,
        "ResourceRecords": [
          {
            "Value": "\"$validation\""
          }
        ]
      }
    }
  ]
}
EOT

        # jsonファイルをアップロードしてTXTレコードを追加
        aws route53 change-resource-record-sets --hosted-zone-id "$HOSTED_ZONE_ID" --change-batch file://$DIR$FILENAME

        # DNS反映待ち
        sleep 60
        ;;
    *)
        ;;
esac

使い方

renew.shをcronに登録して毎月1回実行すれば更新されるはず。

説明

certbot-external-authってやつがDNS-01のチャレンジを行うときに色々なタイミングでフックしてくれます。
そのフックを利用してチャレンジ前にTXTレコードを書き換えて認証してもらうって流れです。

どのタイミングでフックされるかや、どういう環境変数を渡してくれるかは下記を参考にしてください。
github.com

hook.shの方はどのフックタイミングかを見極めてperformのときにTXTレコードを書き換えます。
hosted_zone_idはRoute53にアクセスしてHosted zonesを見ればわかります。
f:id:ichiy:20180730145427p:plain

awsコマンドでRoute53の変更を行うにはjsonを使うので、設定用jsonを書き出します。
書き出したjsonawsコマンドでアップロードします。
チェレンジ前にDNSの設定が反映されてる必要があるのでTTLの60秒待ちます。

その後はcertbotが勝手にやってくれます。
最後にWebサーバーを再起動すれば新しい証明書になります。

注意点

本番でやる想定なので「--keep-until-expiring」というオプションをつけてます。
これは証明書の更新が必要ない場合は発行しないというオプションです。

証明書の有効期限にかかわらず発行させる場合は「--force-renewal」というオプションをつけます。
このオプションをつけて実行する場合Let's Encryptのレート制限に引っかからないように注意しましょう。
Rate Limits - Let's Encrypt - Free SSL/TLS Certificates