追記 2017/7/4 githubにうp
github.com
先週は会社の社長賞研修でサンフランシスコ、シリコンバレーに行ってきて書きたいことは山ほどあるけど、忘れてしまいそうな作業メモ。
研修中に証明書の期限が切れてしまい、リモートで更新するのが非常にストレスだったので、SSL証明書を自動化したい。
以前も考えたけど、GAEの証明書はまだgcloudコマンドからは変更できなかったので諦めた。
調べなおしてみると、2017/6/14のgcloudのアップデートで、コマンドラインからGAE用のSSL証明書をアップできるようになって、実現できるようになったので早速つくってみる。
とりあえずコマンド一発で
TOKENの作成
DNSの変更
AppEngineの証明書をアップデート
まで動いた。
あとcronで回して、念のため有効期限の監視も付ければ完璧?
監視は、デフォルトでは期限まで30日以上あったら更新されないので、期限が30日を切ったタイミングでアラート出せば何らかの原因で止まっているのが確認できるはず。
証明書にはLet's Encrypt
letsencrypt.org
やり取りは、おなじみの↓DNS認証ができるdehydratedを使う。
GitHub - lukas2511/dehydrated: letsencrypt/acme client implemented as a shell-script – just add water
前提として使うドメインはCloud DNSに入れておく必要がある。また、実行ユーザーはGoogle Cloud SDKをインストールして、最新のgcloudコマンドを使えるようにしておく。GAE使ってる環境と同じであれば大丈夫だとは思うけど。
元になるドメイン(bizocean.jp)は、AWS Route53で管理していたけど、今回使うサブドメイン(s.bizocean.jp)のNSレコードだけCloud DNSのものに向けておけば、問題なく動いた。
オリジナルのhook.shをベースに作る。とりあえず変更が必要そうなのは頭にまとめた。
gae_hook.sh
#!/usr/bin/env bash
DNS_PROJECT="oceanus-dev"
GAE_PROJECT="oceanus-gae"
CERT_ID=`gcloud beta app --project $GAE_PROJECT ssl-certificates list | awk 'NR==2 {print $1}'`
CERT_NAME="letsencrypt-auto`date "+%Y%m%d"`"
TARGET_DOMAIN="s.bizocean.jp"
ZONE_NAME="s-bizocean-jp"
ACME_TTL=60
SLEEP_SECOND=60
function deploy_challenge {
local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}"
if [ $DOMAIN = $TARGET_DOMAIN ];then
echo "Set TXT record of _acme-challenge.$DOMAIN to $TOKEN_VALUE"
echo "dns update start"
gcloud dns --project=$DNS_PROJECT record-sets transaction start -z=${ZONE_NAME}
gcloud dns --project=$DNS_PROJECT record-sets transaction remove \
`gcloud --project=$DNS_PROJECT dns record-sets list -z=${ZONE_NAME} --name="_acme-challenge.${DOMAIN}." | awk 'NR==2 {print $4}'` \
-z=${ZONE_NAME} --name="_acme-challenge.${DOMAIN}." --type=TXT --ttl=${ACME_TTL}
gcloud dns --project=$DNS_PROJECT record-sets transaction add $TOKEN_VALUE -z=${ZONE_NAME} --name="_acme-challenge.${DOMAIN}." --type=TXT --ttl=${ACME_TTL}
gcloud dns --project=$DNS_PROJECT record-sets transaction execute -z=${ZONE_NAME}
echo "dns update end sleep ${SLEEP_SECOND}"
sleep $SLEEP_SECOND
else
echo "Don't match $TARGET_DOMAIN and $DOMAIN"
echo "Set TXT record of _acme-challenge.$DOMAIN to $TOKEN_VALUE manually"
read
fi
}
function clean_challenge {
local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}"
}
function deploy_cert {
local DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" CHAINFILE="${5}" TIMESTAMP="${6}"
if [ $DOMAIN = $TARGET_DOMAIN ];then
echo "update ssl cert start"
gcloud beta app --project ${GAE_PROJECT} ssl-certificates update $CERT_ID \
--display-name=$CERT_NAME \
--certificate=$FULLCHAINFILE \
--private-key=$KEYFILE
else
echo "Don't match $TARGET_DOMAIN and $DOMAIN"
fi
}
function unchanged_cert {
local DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" CHAINFILE="${5}"
}
HANDLER=$1; shift; $HANDLER $@全体的にひたすらgcloudコマンドを並べただけで汚い。
更新後のsleepは10秒程度だと安定しなかったので、長めに60秒とした。TTLと合わせてもっと短くできるかもしれない。もしくはステータスを確認してからやるか。
ドメインチェック以外、例外処理もやってないが、それは死活監視の方に任せるつもり。
次に必要な設定。
鍵の長さはデフォが4096、GAEは2048以下しか対応していないのでアップ時に怒られる。
実行するディレクトリにconfigというそのままの名前のファイルを作成して変更する。
config
KEYSIZE="2048"
実行コマンド。-xを追加すれば残り期限にかかわらず強制定期にアップデートする。
./dehydrated -c -d s.bizocean.jp --challenge dns-01 -k ./gae_hook.sh
こんな感じで実行されればおk。
途中でこけるとトランザクションが残っちゃうので実行前にabortした方がいいかもしれない。
# INFO: Using main config file /home/yu_yamazaki/letsencrypt/dehydrated/config Processing s.bizocean.jp + Checking domain name(s) of existing cert... unchanged. + Checking expire date of existing cert... + Valid till Oct 2 00:26:00 2017 GMT (Longer than 30 days). Ignoring because renew was forced! + Signing domains... + Generating private key... + Generating signing request... + Requesting challenge for s.bizocean.jp... Set TXT record of _acme-challenge.s.bizocean.jp to RsMwB34gCgdfmks-2LGpsH0MVpBZVYkdveANiAcTXlk dns update start ERROR: (gcloud.dns.record-sets.transaction.start) transaction already exists at [transaction.yaml] Record removal appended to transaction at [transaction.yaml]. Record addition appended to transaction at [transaction.yaml]. Executed transaction [transaction.yaml] for managed-zone [s-bizocean-jp]. Created [https://www.googleapis.com/dns/v1/projects/oceanus-dev/managedZones/s-bizocean-jp/changes/21]. ID START_TIME STATUS 21 2017-07-04T01:44:46.816Z pending dns update end sleep 60 + Responding to challenge for s.bizocean.jp... + Challenge is valid! + Requesting certificate... + Checking certificate... + Done! + Creating fullchain.pem... + Done!
期限内だったら何もせずに終了する
% ./dehydrated -c -d s.bizocean.jp --challenge dns-01 -k ./gae_hook.sh # INFO: Using main config file /home/BIZOCEAN/yu_yamazaki/letsencrypt/dehydrated/config Processing s.bizocean.jp + Checking domain name(s) of existing cert... unchanged. + Checking expire date of existing cert... + Valid till Oct 2 00:46:00 2017 GMT (Longer than 30 days). Skipping renew!
- 作者: Dan Sanderson,玉川竜司
- 出版社/メーカー: オライリージャパン
- 発売日: 2011/01/24
- メディア: 大型本
- 購入: 5人 クリック: 414回
- この商品を含むブログ (27件) を見る
- 作者: 吉積礼敏,福田潔
- 出版社/メーカー: インプレスR&D
- 発売日: 2016/03/25
- メディア: Kindle版
- この商品を含むブログを見る