Assume RoleでCircleCIからS3にデプロイする

kosa3
7 min readNov 24, 2019

--

今回はCircleCIでAssume RoleをしてReactのアプリケーションをS3にデプロイしてみました。

assume role

背景

これまでAWS外のサービスからAWSへのアクセスをする際にアクセスを許可するRoleをIAM Userにアタッチし、IAM UserのCredentialsキーを外部サービス(CircleCIなど)に保管していたが、外部サービスで何かしらのトラブルが生じキーが流出すると他者にAWSのアカウントにアクセスする権限を委ねてしまう可能性があるため、Assume Roleを利用しそのセキュリティリスクを回避してみる検証をしました。

以下はかなり参考にさせてもらった記事です。

事前準備(主にアカウント周り)

・AWSアカウント

・CircleCI

・Github

・ホスティング用のS3バケット

やること

  1. アプリケーションをホスティングするS3バケットを作成する。

2. Reactプロジェクトを作成

3. AWSアカウントにAssume RoleするUserとRoleをcfnで作成

4. CircleCIにてbuild、AssumeRoleしS3へアプリケーションを転送

5. ホスティングされているURLへアクセスして確認

#1 S3バケットを作成する

aws cliで作成するなら以下のコマンドを、コンソールマネジメントでは作成から手動で作成する。

$ aws s3 mb s3://assume-role-sample-app

ホスティングをそのまま公開するためポリシーは以下で設定する

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadForGetBucketObjects",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::バケット名/*"
]
}
]
}

#2 Reactアプリケーションを作成する

create-react-app コマンドでReactの環境を作成する

$ create-react-app assume-role-sample-app

無事作成ができればgithubでコードを管理します。

#3 AWSアカウントにAssume RoleするUserとRoleを作成

Assume RoleするためにCircleCI用のUserとRoleを作成する。
以下はcfnで作成する

iam.yml

雛形ができれば実際にAWSアカウントに反映させる。
以下コマンドはアクセス権限のあるユーザで実行する

$ aws cloudformation deploy \
--template-file iam.yml \
--stack-name CircleCI-Iam \
--capabilities CAPABILITY_NAMED_IAM

これでIAM UserとRoleをそれぞれCircleCI-Iamというスタックで作成することができました。

作成したスタックのIAMとRoleのARNを確認してみます。
RoleのARNはAssumeRoleする際に使用する。

$ aws cloudformation describe-stacks \
--stack-name CircleCI-Iam \
--query 'Stacks[].Outputs'
[
[
{
"OutputKey": "CircleCIUserName",
"OutputValue": "CIUser"
},
{
"OutputKey": "CircleCIUserArn",
"OutputValue": "arn:aws:iam::[accountID]:user/CIUser"
},
{
"OutputKey": "CircleCIRoleArn",
"OutputValue": "arn:aws:iam::[accountID]:role/CIRole"
}
]
]

4. CircleCIにて設定ファイルを作成する

.circleci/config.yml を作成し、以下のようにデプロイのワークフローを構築する

config.yml

Assume Roleする際に #3で作成したIAMユーザのCredentials情報をCircleCIの環境変数に設定する。

その後 ./assume.sh ${AWS_ASSUME_ROLE_ARN} でAssumeRoleし、S3を操作することができるCredentialsを発行。
再度環境変数に設定した上でS3にビルドファイルを配置する。

#!/usr/bin/env bash

set -xeuo pipefail

DURATION_SECONDS="1800"

aws_sts_credentials="$(aws sts assume-role \
--role-arn $1 \
--role-session-name "circle-ci-session" \
--external-id "00001" \
--duration-seconds "$DURATION_SECONDS" \
--query "Credentials" \
--output "json")"
cat <<EOT > "$(dirname $0)/aws-envs.sh"
export AWS_ACCESS_KEY_ID="
$(echo $aws_sts_credentials | jq -r '.AccessKeyId')"
export AWS_SECRET_ACCESS_KEY="
$(echo $aws_sts_credentials | jq -r '.SecretAccessKey')"
export AWS_SESSION_TOKEN="
$(echo $aws_sts_credentials | jq -r '.SessionToken')"
EOT

AssumeRoleした時のセッション時間はデフォルトで15分ですが上記のようにduration-secondsを指定することで時間を伸ばすことができます。

ワークフロー成功

5. ホスティングされているURLへアクセスして確認

無事ワークフローがPassできれば実際にホスティングしたS3のURLにアクセスしてみます。以下のように表示されていればデプロイができていることが分かります。

以上で、AssumeRoleを用いてCircleCIからS3へデプロイすることができました。外部サービスを利用する上でのリスクを避けるためにもこの方法はとても良さそうです。また、AWSアカウントが複数になっても一つのUserでアカウントのAssumeRoleを行うこともできるのがとても便利に感じました。

--

--

No responses yet