CircleCI2.0からEC2にアクセスするときだけ特定のIPを許可したい

[Yper株式会社](https://www.yper.co.jp/) でエンジニアをやっています。
個人情報とかも扱うのでセキュリティを固めていて、CircleCIのお便利さとバッティングしたときのメモです。

# やりたいこと
EC2にCircleCIからSSHしてなんかしらやりたい、っていうことありませんか？
適当にcapistranoサーバ叩いてデプロイしたいとか、なんかありませんかね。
私は結構あります。

![スクリーンショット 2018-12-17 13.37.07.png](https://qiita-image-store.s3.amazonaws.com/0/217483/ef76b659-6feb-d101-725c-33944fb71acf.png)

ところがどっこい、大体の場合は22番ポートを無制限で許可したりはしていない。
踏み台サーバからだけとか、オフィスのIPじゃないとだめとか、そんなセキュリティグループを設定してなんかいい感じでホワイトリスト作りますよね。

ですがCircleCIはジョブを起動するたびにIPアドレスが変わるわけで、こんな感じになるわけですよ。
![スクリーンショット 2018-12-17 13.44.24.png](https://qiita-image-store.s3.amazonaws.com/0/217483/2bff1379-c3c3-6efc-c3b9-dbdc94c9a9a2.png)

というわけで、CircleCIのスクリプトの中に動的にアクセス元IPを許可するような処理を書いてあげるといい感じでいろんな作業が捗るようになります。

# CircleCI用のIAMとかをごねごね
<b>何でもかんでもEC2FullAccessとかしてませんよね？</b>
ちゃんとセキュリティグループを変更するためだけのポリシーを作っておきましょう。
とりあえず全部許可ダメ絶対。

IAMのところに飛んで
![スクリーンショット_2018-12-17_14_08_11.png](https://qiita-image-store.s3.amazonaws.com/0/217483/4ee753e2-b59b-09db-4a4c-b21e76ee33e6.png)

ポリシーの作成に進んで
![スクリーンショット_2018-12-17_14_11_19.png](https://qiita-image-store.s3.amazonaws.com/0/217483/7d069562-f33a-dff6-04db-ec26b20e73ad.png)

ポリシーをJSONで入力しよう
![スクリーンショット_2018-12-17_14_08_40.png](https://qiita-image-store.s3.amazonaws.com/0/217483/70cb63b9-4f9a-b1b4-e5ec-032a5e68eda3.png)

はいコピペ用

```json:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:RevokeSecurityGroupIngress"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:ec2:*:*:security-group/*"
        }
    ]
}
```

適当に名前とか入れて登録
![スクリーンショット_2018-12-17_14_09_00.png](https://qiita-image-store.s3.amazonaws.com/0/217483/62564540-36a7-6d54-ef0c-5885d9204aef.png)

ユーザ名を適当につけて
![スクリーンショット_2018-12-17_14_19_03.png](https://qiita-image-store.s3.amazonaws.com/0/217483/cc46a8c7-b03a-aefe-4bce-84f3e9831cdf.png)

さっき作ったポリシーをアタッチして
![スクリーンショット_2018-12-17_14_19_46.png](https://qiita-image-store.s3.amazonaws.com/0/217483/bd7f57a5-1382-54ef-6f26-05dfa3dda4da.png)

タグはとりあえず空
![スクリーンショット_2018-12-17_14_19_54.png](https://qiita-image-store.s3.amazonaws.com/0/217483/8592dd63-efe0-7a96-17c7-09cf15132345.png)

ユーザの作成をポチッと
![スクリーンショット_2018-12-17_14_20_21.png](https://qiita-image-store.s3.amazonaws.com/0/217483/1fa1a418-c3ab-c501-146d-5ed1c977113c.png)

なくさないようにメモるかCSVをダウンロードしておきます
![スクリーンショット_2018-12-17_14_20_35.png](https://qiita-image-store.s3.amazonaws.com/0/217483/f46094d7-f870-0d1a-0910-6938f87ce9e3.png)

# CircleCIの設定画面でアクセスキーを環境変数に入れておく
config.ymlに直接書いたりしたらダメだ。絶対にだ。

対象のプロジェクトの設定画面へ行く
![スクリーンショット_2018-12-17_14_28_15.png](https://qiita-image-store.s3.amazonaws.com/0/217483/4c304ed5-4b72-47d7-6463-40dfbf37f4aa.png)


環境変数の設定を開く
![スクリーンショット_2018-12-17_14_26_44.png](https://qiita-image-store.s3.amazonaws.com/0/217483/6f52715c-7943-e76a-d271-e08eec469644.png)

`AWS_ACCESS_KEY_ID` と `AWS_SECRET_ACCESS_KEY` をNameに設定して、先ほど作成したユーザの情報をそれぞれ登録しておく
![スクリーンショット_2018-12-17_14_27_10.png](https://qiita-image-store.s3.amazonaws.com/0/217483/588ce114-22eb-4ad0-1966-21bf98de0bd9.png)


# CircleCIのconfig.ymlを書いてみる

わざと1行ずつ書いてみるとこんな感じ

```yaml:config.yml
version: 2
jobs:
  deploy:
    docker:
      - image: circleci/python:3.6-jessie
      - image: buildpack-deps:trusty
    working_directory: ~/
    steps:
      - run: sudo pip install awscli
      - run:
          name: "authorize-security-group-ingress"
          command: |
            IP=`curl -s ifconfig.me`
            echo "#!/bin/bash" > ./sg.sh
            echo "aws configure set region ap-northeast-1" >> ./sg.sh
            echo "aws ec2 authorize-security-group-ingress --group-id sg-xxxxxxxxxxxxxx --protocol tcp --port 22 --cidr ${IP}/32" >> ./sg.sh
            bash ./sg.sh
      - add_ssh_keys:
          fingerprints:
            - "xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"
      - run:
          name: deploy
          command: ssh -oStrictHostKeyChecking=no circleci@xxx.xxx.xxx.xxx "bash /home/circleci/script/deploy.sh"
      - run:
          name: "revoke-security-group-ingress"
          command: |
            IP=`curl -s ifconfig.me`
            echo "#!/bin/bash" > ./sg.sh
            echo "aws configure set region ap-northeast-1" >> ./sg.sh
            echo "aws ec2 revoke-security-group-ingress --group-id sg-xxxxxxxxxxxxxx --protocol tcp --port 22 --cidr ${IP}/32" >> ./sg.sh
            bash ./sg.sh

workflows:
  version: 2
  test:
    jobs:
      - deploy:

```

aws-cliのコンテナとかも用意はされていたものの、何故かコケることが多かったので結局 `pip install` で入れてます。

`aws ec2 authorize-security-group-ingress --group-id sg-xxxxxxxxxxxxxx --protocol tcp --port 22 --cidr ${IP}/32`
この部分の `sg-xxxxxxxxxxxxxx` はアクセスしたいEC2インスタンスに紐付いてるセキュリティグループのIDを入れてやってください。

イメージ的にはこんな流れ
![スクリーンショット 2018-12-17 15.02.11.png](https://qiita-image-store.s3.amazonaws.com/0/217483/5561b9e6-ac0b-471a-4265-877ef527f1f7.png)
ただし <b>デプロイ中にジョブが落ちるとセキュリティグループの閉め忘れが発生する</b> のでそこらへんは色々やって監視してあげてる必要があります。

aws-cliは環境変数にアクセス用の情報を入れておくと勝手に読んでくれるので楽ですね。
[(参考:AWS CLI 環境変数チートシート)](https://qiita.com/n-oshiro/items/4a7774ee6e1d11bb55d2)

SSH用の設定のフィンガープリント云々とか、特定のブランチにプッシュしたら云々、とかは↓の記事がわかりやすかったのでおすすめです。
ホストも環境変数入れとけよ！とかは突っ込まないでください。すいません。
[Circle CIでwebサイトを自動デプロイ](https://esnetk6.com/2018/04/circle-ci-deployment/)