CircleCIから複数のAWSアカウント、たとえばステージング環境とプロダクション環境(本番環境)へ、安全にデプロイする方法を記載します。
課題
- CircleCIはAWSのCodePipeline等より使い勝手が良いのでAWSのプロダクション環境へのデプロイに使いたい
- しかしステージング環境とプロダクション環境は別のAWSアカウントで構築しておりIAMのアクセスキーの切り替えが必要
- そしてIAM権限をAWSの外に出すのはセキュリティ上の懸念がある
対策
- 別アカウントなので認証情報の切り替えが必要
- => CircleCIのContextsを利用する
- IAM権限をAWSの外に出すのはセキュリティ懸念がある
- => 利用するときだけIAMアクセスキーを有効化する
- Slackから簡単にキーの有効/無効を切り替えられるようにしておきましょう
- => 利用するときだけIAMアクセスキーを有効化する
順に説明してゆきます。
ブランチごとにAWS認証情報を切り替え
AWSの別アカウントで構築したプロダクションへデプロイするために、ブランチごとにAWS認証情報を切り替える手順を記載します。
ここではmasterブランチへの更新をプロダクション環境、その他のブランチへの更新をステージングへデプロイすると想定します。
まず前提として、CircleCIの環境変数を利用してステージングへのデプロイを実現できます。
手順の詳細は割愛しますが、環境変数に AWS_DEFAULT_REGION
、AWS_ACCESS_KEY_ID
、AWS_SECRET_ACCESS_KEY
(シークレットキー) を登録した後にOrbsを利用します。
※従来の設定項目であるAWS Permissionsは非推奨となり、将来的に廃止される予定です。
この状態から、masterブランチへの更新時のみ別のIAM認証を使いたい場合、以下の手順で実現できます。
- プロダクション環境へのデプロイ用にContextを作成し、
AWS_ACCESS_KEY_ID
とAWS_SECRET_ACCESS_KEY
を登録 - 登録したContext
production_deployment
は、以下のような感じで利用できます。
version: 2.1 # Contextを利用するにはWorkflowsを使う必要があるので`2.1`を指定しています
orbs: # Orbs, CircleCIのスニペットみたいなものです
aws-cli: circleci/aws-cli@0.1.13
executors:
default:
working_directory: ~/repo
docker:
- image: circleci/python:3.7.1-node
jobs:
deploy:
executor:
name: default
steps:
- checkout
- restore_cache:
keys:
- v1-npm-dependencies-{{ checksum "package-lock.json" }}
- v1-npm-dependencies-
- run:
command: npm ci
- save_cache:
paths:
- ./node_modules
key: v1-npm-dependencies-{{ checksum "package-lock.json" }}
# Orbsを使用してaws-cliのインストールとAWS認証情報の反映を行う
- aws-cli/install
- aws-cli/configure
- deploy:
command: npm run deploy
workflows:
deploy:
jobs:
- deploy: # このjobはfiltersによりmasterブランチ「以外」で実行される
filters:
branches:
ignore:
- master
- deploy: # このjobはfiltersによりmasterブランチ「のみ」で実行される
context: production_deployment # ここで先程作成したcontextのAWS認証情報を指定
filters:
branches:
only:
- master
このように config.yml
を記述することで、masterブランチへの更新はContextのAWS認証情報、それ以外は環境変数の認証情報と切り分けることができます。
この例では環境変数を使用していますが、今後はステージング環境などへの認証情報もContextで管理するのが保守性の観点で筋が良いでしょう。
プロダクション環境のIAMアクセスキーは利用時のみ有効化
CircleCIをプロダクション環境へのデプロイに利用する時、どうしてもネックとなるのが AWS外にそこそこ強力なIAMアクセスキーを出さなければならないこと です。
もちろんCircleCIでContextを利用すれば外部に公開されることはなく、そのContextもグループによる制限を指定することできめ細やかなパーミッションの管理ができます。しかしCircleCIがクラックされたり、何か不足の事態が起こらないとも限りません。
なのでここでは、 プロダクションへのデプロイ時のみデプロイ用のIAMアクセスキーを有効化する 運用を行うための手順を記載します。
手順
- まず、
circleci
という名前でCircleCIからのデプロイ専用のIAMユーザを作成し、アクセスキーを作成します(手順割愛)。 - そのアクセスキーを上記手順に従いCircleCIのContextへ登録します。
以上の操作で、マネコンからアクセスキーの有効/無効を切り替えることで運用が可能となりました。これでも良いのですが、いちいちマネコンを開くのは面倒です。
そこで、ここではSlackを利用してみましょう。
IAMアクセスキーの有効/無効 切り替えSlackコマンドの作成
Slackを利用して簡単かつ安全にアクセスキーの有効/無効を切り替える環境を構築します。
SlackのユーザIDを取得
まずコマンドを実行できる(=強力なIAMアクセスキーの有効/無効を切り替えられる)Slackユーザーを決め、そのユーザIDを取得します。sot528
のような ユーザ名 ではなく U8FS891QA
というような ユーザID です。SlackのAPIトークンがあればここでメンバーのユーザIDを取得できます。
ここでは例として、U1234567
とU89ABCDE
という2人のユーザに権限を割り当てるものとします。
SlackのOutgoing Webhookを作成
※ Outgoing WebhookはDuplicatedになっているようです。知らなかった..まあ今回は気にせず使いましょう。
Outgoing Webhookを 2件 作成し、そのトークンを取得しておきます。作成画面↓の赤枠部分です。作成画面は開いておいてください。
ここでは例として、XXXXXXXX
とYYYYYYYY
という2つのトークンを利用するものとします。
IAM操作用のserverlessアプリをデプロイ
この運用を行うためにシンプルなツールを作りましたのでこちらを使います。serverlessフレームワークを使用してAPI Gateway => Lambdaの構築を行っています。
使い方
git clone https://github.com/AlisProject/toggle-iam-access-key.git
npm ci
環境変数を設定します。ここではdirenvを使っています。
cp .envrc.sample .envrc
direnv edit
今回の例では、設定する値は以下のとおりです。
複数の値が存在するものはカンマ区切りで指定します。
- SLACK_ACCESS_TOKENS:
XXXXXXXX,YYYYYYYY
- ACCEPTED_SLACK_USERS:
U1234567,U89ABCDE
- AWS_IAM_USER_NAME:
circleci
- AWS_IAM_ACCESS_KEY_ID: IAMユーザ
circleci
のアクセスキーのID - その他、AWSの認証情報: このツールをデプロイするのに必要なAWSの認証情報です
デプロイします。
npm run deploy:production
成功したら以下のような表示が出るので、 endpoints
を2件控えておきます。
さきほど開いておいた2つのOutgoing Webhookの作成画面で、このendpointsを1つずつ URL(s)
に設定します。末尾が enable
がIAMキーを有効化するもので、disable
が無効化するものです。
それぞれ適当な Trigger Word(s)
も設定しましょう。ここではenableに key!
、 disableにkey_disable!
を割り当てます。
これは必須ではないですが、お好みで、Customize Name
に IAM
、Customize Icon
に IAMのアイコンとか登録しておくとわかりやすくてGoodです。
さて、準備が整いました。SlackからIAMアクセスキーの開閉をしてみましょう。Outgoing Webhookは公開チャンネルしか有効ではないのでご注意。
鍵の開閉ができましたね。これでだいぶ楽に運用できそうです。
ちゃんとマネコンでアクセスキーが有効化/無効化されていることを確認しておきましょう。
ちなみに許可されていないIDのSlackユーザがコマンドを叩くと。
(՞ਊ ՞)ウェーイ!
備考
- 今回の手順では割愛していますが、CircleCIのプロダクション環境用のContextにはグループによる制限を付加した方が良いでしょう。
-
現状、CircleCIのContextを複数指定することはできないようです。これができると大変に便利なんですが。Jobを細かく分けろという話ですかね- 2020/09/15にこの機能が追加されました。これは嬉しい!
- 重要なリポジトリは本番環境への反映前にCircleCIのワークフローで承認(approve)を挟むと良いかと思います
- CodePipelineやCodeBuildなど、AWSのCode兄弟達とも格闘しましたが、私の結論は CircleCI最強 です..
- もちろん要件によりCode兄弟の方が適している場合もありますが
- TODO: 全ビルドが終わったら勝手にIAMを無効化する まで自動化したい
- ご参考までに: だいたいのリポジトリでCircleCI使用していてほとんどコード公開してます
- もっとよろしい運用をご存知でしたらご教示ください🙏