LoginSignup
57

More than 3 years have passed since last update.

CircleCIから安全にAWSのプロダクション環境へデプロイする

Last updated at Posted at 2019-06-20

CircleCIから複数のAWSアカウント、たとえばステージング環境とプロダクション環境(本番環境)へ、安全にデプロイする方法を記載します。

課題

  • CircleCIはAWSのCodePipeline等より使い勝手が良いのでAWSのプロダクション環境へのデプロイに使いたい
    • しかしステージング環境とプロダクション環境は別のAWSアカウントで構築しておりIAMのアクセスキーの切り替えが必要
    • そしてIAM権限をAWSの外に出すのはセキュリティ上の懸念がある

対策

  • 別アカウントなので認証情報の切り替えが必要
  • IAM権限をAWSの外に出すのはセキュリティ懸念がある
    • => 利用するときだけIAMアクセスキーを有効化する
      • Slackから簡単にキーの有効/無効を切り替えられるようにしておきましょう

順に説明してゆきます。

ブランチごとにAWS認証情報を切り替え

AWSの別アカウントで構築したプロダクションへデプロイするために、ブランチごとにAWS認証情報を切り替える手順を記載します。

ここではmasterブランチへの更新をプロダクション環境、その他のブランチへの更新をステージングへデプロイすると想定します。
まず前提として、CircleCIの環境変数を利用してステージングへのデプロイを実現できます。
手順の詳細は割愛しますが、環境変数に AWS_DEFAULT_REGIONAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY(シークレットキー) を登録した後にOrbsを利用します。
※従来の設定項目であるAWS Permissionsは非推奨となり、将来的に廃止される予定です。
image.png

この状態から、masterブランチへの更新時のみ別のIAM認証を使いたい場合、以下の手順で実現できます。

  • プロダクション環境へのデプロイ用にContextを作成し、AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY を登録
    • ここでは例として production_deployment という名前で作成します context.gif
  • 登録した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アクセスキーを有効化する 運用を行うための手順を記載します。

手順

  1. まず、circleciという名前でCircleCIからのデプロイ専用のIAMユーザを作成し、アクセスキーを作成します(手順割愛)。
  2. そのアクセスキーを上記手順に従いCircleCIのContextへ登録します。

以上の操作で、マネコンからアクセスキーの有効/無効を切り替えることで運用が可能となりました。これでも良いのですが、いちいちマネコンを開くのは面倒です。
そこで、ここではSlackを利用してみましょう。

IAMアクセスキーの有効/無効 切り替えSlackコマンドの作成

Slackを利用して簡単かつ安全にアクセスキーの有効/無効を切り替える環境を構築します。

SlackのユーザIDを取得

まずコマンドを実行できる(=強力なIAMアクセスキーの有効/無効を切り替えられる)Slackユーザーを決め、そのユーザIDを取得します。sot528 のような ユーザ名 ではなく U8FS891QA というような ユーザID です。SlackのAPIトークンがあればここでメンバーのユーザIDを取得できます。

ここでは例として、U1234567U89ABCDEという2人のユーザに権限を割り当てるものとします。

SlackのOutgoing Webhookを作成

Outgoing WebhookはDuplicatedになっているようです。知らなかった..まあ今回は気にせず使いましょう。

Outgoing Webhookを 2件 作成し、そのトークンを取得しておきます。作成画面↓の赤枠部分です。作成画面は開いておいてください。
スクリーンショット 2019-06-20 1.09.19.png

ここでは例として、XXXXXXXXYYYYYYYYという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件控えておきます。

スクリーンショット 2019-06-20 1.20.26.png

さきほど開いておいた2つのOutgoing Webhookの作成画面で、このendpointsを1つずつ URL(s) に設定します。末尾が enable がIAMキーを有効化するもので、disableが無効化するものです。

それぞれ適当な Trigger Word(s) も設定しましょう。ここではenableに key!、 disableにkey_disable!を割り当てます。

image.png

これは必須ではないですが、お好みで、Customize NameIAMCustomize IconIAMのアイコンとか登録しておくとわかりやすくてGoodです。

image.png

さて、準備が整いました。SlackからIAMアクセスキーの開閉をしてみましょう。Outgoing Webhookは公開チャンネルしか有効ではないのでご注意。

toggle.gif

鍵の開閉ができましたね。これでだいぶ楽に運用できそうです。
ちゃんとマネコンでアクセスキーが有効化/無効化されていることを確認しておきましょう。

ちなみに許可されていないIDのSlackユーザがコマンドを叩くと。

image.png

(:point_up:՞ਊ ՞):point_up:ウェーイ!

備考

  • 今回の手順では割愛していますが、CircleCIのプロダクション環境用のContextにはグループによる制限を付加した方が良いでしょう。
  • 現状、CircleCIのContextを複数指定することはできないようです。
  • 重要なリポジトリは本番環境への反映前にCircleCIのワークフローで承認(approve)を挟むと良いかと思います
  • CodePipelineやCodeBuildなど、AWSのCode兄弟達とも格闘しましたが、私の結論は CircleCI最強 です..
    • もちろん要件によりCode兄弟の方が適している場合もありますが
  • TODO: 全ビルドが終わったら勝手にIAMを無効化する まで自動化したい
  • ご参考までに: だいたいのリポジトリでCircleCI使用していてほとんどコード公開してます
  • もっとよろしい運用をご存知でしたらご教示ください🙏

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
57