CircleCIで複数のAWSアカウントを扱う方法

# はじめに

弊社では、ソフトウェアの品質を高めるために、継続的な自動テスト・E2Eテストを実行しています。
その際、CircleCIというSaaSのCIサービスを利用しています。


また、AWSを利用しているサービスでは、開発用のAWSアカウントと本番用のAWSアカウントを分けて利用しています。
開発用アカウントでは、エンジニアが比較的自由に実験・開発を進めつつ、本番はセキュリティガチガチで守っていこうという方針です。
そのため、サービスの開発環境は開発用AWSアカウントに配置し、本番環境は本番用AWSアカウントに配置したいという要望が生まれます。

そのような複数AWSアカウントをCircleCIでどのように扱えばよいのかという記事です。

# 結論

- CircleCIのContexts機能が便利。

結果は以上です。
その過程で試した方法があるのでまとめておきます。

## 方法1: ProjectのAWS Permissionを利用する方法

![0994f46ee78528ddd9ccd1c8666adeac.png](https://qiita-image-store.s3.amazonaws.com/0/240750/4444b3cb-f53c-115c-41c0-eb0ac7f6d3e8.png)



スクショの文言通り、AWSのIAMユーザーを登録すると、よしなにやってくれる機能です。

これの問題点としては

- 1つのアカウントしか登録できない。
- 2018年8月31日でサポートが終了する。

などが上げられるかと思います。



## 方法2: ProjectのEnvironment Variablesを利用する方法

CircleCIのUI的にもEnvironment Variablesは目立つところにあるので、使っている方は多いのではないでしょうか。
Environment Variablesを使った場合には

|Name | Value|
|--------------|--------------|
|DEV_AWS_ACCESS_KEY_ID| dev-hogehoge |
|DEV_AWS_SECRET_ACCESS_KEY| dev-piyopiyo |
|PRD_AWS_ACCESS_KEY_ID| prd-hogehoge |
|PRD_AWS_SECRET_ACCESS_KEY| prd-piyopiyo |

こんな感じの環境変数を設定します。画面的にはこんな感じになります。

![d143ae8e496fbb4a9e42169b1a700715.png](https://qiita-image-store.s3.amazonaws.com/0/240750/b73b0810-8077-ae22-b94e-90c8da43f03b.png)



jobの中で環境変数の `AWS_ACCESS_KEY_ID` と `AWS_SECRET_ACCESS_KEY` を設定するか、`~/.aws/credentials` を書き換える事になると思います。

例えばこんな感じ。

```bash
mkdir  -p ~/.aws  
echo "[default]" > ~/.aws/credentials
if [[ "${CIRCLE_BRANCH}" == "master" ]]; then
    echo "aws_access_key_id = ${PRD_AWS_ACCESS_KEY_ID}" >>  ~/.aws/credentials
    echo "aws_secret_access_key = ${PRD_AWS_SECRET_ACCESS_KEY}" >>  ~/.aws/credentials
    echo "region = ap-northeast-1" >>  ~/.aws/credentials
else
    echo "aws_access_key_id = ${DEV_AWS_ACCESS_KEY_ID}" >>  ~/.aws/credentials 
    echo "aws_secret_access_key = ${DEV_AWS_SECRET_ACCESS_KEY}" >>  ~/.aws/credentials
    echo "region = ap-northeast-1" >>  ~/.aws/credentials
fi
```

この方法の問題点としては

- ステージング環境を増やす時に面倒です。
- 上記シェルスクリプトがちゃんと意図した動きするか不安。開発環境へのデプロイのつもりが、うっかり本番デプロイなんて怖すぎます。

などが上げられるかと思います。

## 方法3: CircleCIのContexts機能を利用する方法

OrganizationのSettings画面の下の方にひっそりとContexts機能があります。
Environment Variablesだとプロジェクトごとに定義するが、Contexts機能ではプロジェクト横断で環境変数を利用できます。

ここでは、こんな感じに設定します。

Context: aws-dev

|Name | Value|
|--------------|--------------|
|AWS_ACCESS_KEY_ID| dev-hogehoge |
|AWS_SECRET_ACCESS_KEY| dev-piyopiyo |


Context: aws-prd

|Name | Value|
|--------------|--------------|
|AWS_ACCESS_KEY_ID| prd-hogehoge |
|AWS_SECRET_ACCESS_KEY| prd-piyopiyo |

config.ymlでは以下の様に記述します。

```yaml
anchors:
  - &anchor-deploy
  steps:
    - deploy: 
        name: deploy 
        command: |
          echo 'hello deploy'

jobs:
  deploy-dev:
    docker:
        - image: circleci/python:3.6.1
    <<: *anchor-deploy
  deploy-prd:
    docker:
        - image: circleci/python:3.6.1
    <<: *anchor-deploy

workflows:
  version: 2
  workflow1:
    jobs:
      - deploy-dev:
          context: aws-dev
          filters:
            branches:
              only: /develop/
      - deploy-prd:
          context: aws-prd
          filters:
            branches:
              only: /master/
```

このように記述すると、同じdeployスクリプトをAWSのアカウントだけ変更して実行できます。スクリプト自体が環境ごとに異なってしまうと検証が大変なので、できるだけ設定の変更程度に抑えたいですが、この方法だとそれが実現できます。

この方法の場合だと、ステージング環境が増えた際にも修正は少なくて済みます
最近、弊社のyamlファイルがかなり大きくなってきたので、yamlファイル自体をテンプレートエンジンから作っていたりします。テンプレートエンジンを使っていると環境が増えた時の対応も少なく、安心できます。


また、実行中のjobをみて、ちゃんと想定どおりのアカウントにデプロイしているか確認できます。これもまた安心機能です。



# 参考

- https://circleci.com/docs/2.0/contexts/