表題の通り,GCP(Google Cloud Platform) でいうところの default-allow-ssh
などに特定のIPアドレスが指定されているケースで,Circle CI(など)から自動デプロイさせたいと思ったらちょっと困ったという話です.
方針
公開しているサーバに対して,社内など一部の場所からのみ ssh アクセスできるようにすることが多いと思います.
GCP だと例えばこんな感じになると思います.
その場合,外部のCIサービスから自動デプロイさせたい場合,CIサービスのIPアドレスに対して ssh 接続を許可しないといけないですが,Circle CI の場合,IPアドレスが固定されていません.
そこで,デプロイの都度,自身の IP アドレスを取得して,デプロイ先の許可アドレスに追加することにします.
また,その IP アドレスは次回は使用されない可能性が高いので,デプロイが完了したら許可アドレスから削除することにします.
gcloud コマンドを利用する
Circle CI では gcloud
コマンドが使用できるので,それを使用します.
=> cite: https://circleci.com/docs/google-auth/
※ 上記の内容には init
は書かれていないのですが,使用できなかったため,最初に gcloud init
をしています
setup_gcloud() {
echo $GCP_CLIENT_SECRET | base64 --decode > ${HOME}/client-secret.json
yes no | gcloud init
gcloud --quiet components update
gcloud auth activate-service-account --key-file ${HOME}/client-secret.json
gcloud config set project $GCP_PROJECT
}
ここで, $GCP_CLIENT_SECRET
, $GCP_PROJECT
の環境変数はあらかじめウェブ上から Circle CI に登録しておきます.
setup_gcloud
を実行すると,gcloud への認証が済むので,続いて GCP の firewall-rules の変更ができるようにします.
GCP のファイアウォールルールを動的に変更する
まずは,実行時の circle ci サーバの GLOBAL_IP を dig
コマンドで取得しておきます.
GLOBAL_IP=`dig +short myip.opendns.com @resolver1.opendns.com`
IPアドレスの変更ができるようにしますが,この時,デプロイ前の設定値を取得しておくと,元に戻すのが楽です.
(↓ 変数が雑に書かれてますが,関数呼び出し前に定義してある想定です)
fetch_default_source_ranges() {
gcloud compute firewall-rules describe default-allow-ssh --format json | jq -r '.sourceRanges | join(",")'
}
update_gcp_firewall() {
gcloud compute firewall-rules update default-allow-ssh --source-ranges "${DEFAULT_SOURCE_RANGES},${GLOBAL_IP}"
}
rollback_gcp_firewall() {
gcloud compute firewall-rules update default-allow-ssh --source-ranges $DEFAULT_SOURCE_RANGES
}
※ default-allow-ssh
は各自の設定名に読み替えてください.
デプロイ前に update_gcp_firewall
で許可IPを追加し,終了時(エラー時)に rollback_gcp_firewall
で,設定を戻します.
この時,あらかじめデプロイ前の許可IPを fetch_default_source_ranges
によって取得しておきます.
Circle CI では jq
が使えたので使ってます.
使えるコマンドがいろいろと用意されている良いですね.
まとめ
まとめると,以下のようになります(関数定義は除く).
setup_gcloud
GLOBAL_IP=`dig +short myip.opendns.com @resolver1.opendns.com`
DEFAULT_SOURCE_RANGES=fetch_default_source_ranges
update_gcp_firewall
// デプロイ: bundle exec cap dev deploy など
if [ $? -eq 0 ]
then
rollback_gcp_firewall
// slack 通知など
true
else
rollback_gcp_firewall
// slack 通知など
false
fi
実行すると,デプロイ直前と完了後に,このようなちょっとわかりづらいログが出ているのが分かります.
以上です