この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
CircleCIからAWSにデプロイするCI/CDを組んでいます。 その際に使っているAWS CLI(v1)をAWS CLI(v2)に変えてみようとなりました。
そこで、CircleCIでAWS CLI(v2)を簡単に使ってみました。本記事では、CircleCIでaws s3 ls
コマンドを実行してバケット一覧を取得します。
本記事よりも、下記のほうが簡単に導入できます。
おすすめの方
- CircleCIからAWSにアクセスしたい方(AssumeRoleを使う)
- CircleCIでAWS CLI(v2)を使いたい方
事前準備
アクセスキーが流出しても被害が最小限になるIAMユーザを作成して使います。
CircleCIで使うIAMユーザとIAMロールを作成
CloudFormationテンプレートを作成する
次のCloudFormationテンプレートをprepare.yaml
として作成します。
sts:ExternalId
には推測されにくい任意の文字列を設定します。これはあとでCircelCIの環境変数に設定します。
prepare.yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: IAM User and IAM Role for CircleCI
Resources:
# デプロイ用のIAMユーザ
DeployUser:
Type: AWS::IAM::User
Properties:
UserName: !Sub circleci-sample-user
# デプロイ用のIAMユーザに付与するIAMポリシー(AssumeRoleできる)
DeployUserPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: !Sub circleci-sample-policy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: sts:AssumeRole
Resource: !GetAtt DeployRoleForUser.Arn
Users:
- !Ref DeployUser
# デプロイ用のIAMユーザがAssumeRoleするIAMロール(S3に対するRead権限のみ付与)
DeployRoleForUser:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub circleci-sample-role-for-user
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
AWS:
- !GetAtt DeployUser.Arn
Condition:
StringEquals:
sts:ExternalId: any-id-foo-bar
Policies:
- PolicyName: !Sub circleci-sample-policy-for-user
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- s3:List*
Resource:
- "*"
MaxSessionDuration: 3600
Outputs:
DeployRoleArn:
Value: !GetAtt DeployRoleForUser.Arn
デプロイする
aws cloudformation deploy \
--template-file prepare.yaml \
--stack-name CircleCI-Sample-Prepare-Stack \
--capabilities CAPABILITY_NAMED_IAM
IAMユーザのアクセスキーを取得する
IAMユーザのアクセスキーを取得します。これはあとでCircelCIの環境変数に設定します。
aws iam create-access-key \
--user-name circleci-sample-user
- AccessKeyId: xxxxxx
- SecretAccessKey: yyyyyy
IAMロールのARNを取得する
作成したIAMロールのARNを取得します。これはあとでCircelCIの環境変数に設定します。
aws cloudformation describe-stacks \
--stack-name CircleCI-Sample-Prepare-Stack \
--query 'Stacks[].Outputs'
- OutputValue: arn:aws:iam::1234567890:role/circleci-sample-role-for-user
AssumeRole用のスクリプトを作成
AssumeRole用に次のスクリプトをassume_role.sh
として作成します。
このスクリプトではIAMユーザがAssumeRoleを行い、指定したIAMロールとして振る舞うための一時的なアクセスキーを取得しています。
assume_role.sh
#!/usr/bin/env bash
set -xeuo pipefail
aws_sts_credentials="$(aws sts assume-role \
--role-arn "$AWS_DEPLOY_IAM_ROLE_ARN" \
--role-session-name "$ROLE_SESSION_NAME" \
--external-id "$AWS_DEPLOY_IAM_ROLE_EXTERNAL_ID" \
--duration-seconds 900 \
--query "Credentials" \
--output "json")"
cat <<EOT > "aws-env.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
実行権限を付与しておきます。
chmod 755 assume_role.sh
CircleCIの設定ファイルを作成
.circleci
ディレクトリを作成し、その中にconfig.yml
を作成します。
mkdir .circleci
touch .circleci/config.yml
続いて、config.yml
ファイルの中身を記述します。
config.yml
version: 2.1
executors:
my-executor:
docker:
- image: circleci/python:3.8.5
working_directory: ~/work
commands:
restore:
steps:
- restore_cache:
key: work-v1-{{ .Revision }}
save:
steps:
- save_cache:
paths:
- "aws-cli"
key: work-v1-{{ .Revision }}
install:
steps:
- run:
name: install
command: |
if [[ ! -d aws-cli ]]; then
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install --install-dir ~/work/aws-cli
fi
access:
steps:
- run:
name: access
command: |
export PATH=$PATH:$HOME/work/aws-cli/v2/current/bin
aws --version
./assume_role.sh
source aws-env.sh
aws s3 ls
jobs:
setup:
executor: my-executor
steps:
- checkout
- restore
- install
- save
aws_access:
executor: my-executor
steps:
- checkout
- restore
- install
- save
- access
workflows:
version: 2.1
aws-test-workflow:
jobs:
- setup:
filters:
branches:
only:
- master
- aws_access:
requires:
- setup
filters:
branches:
only:
- master
CircleCIの設定
リポジトリのPush
まずはGitHubにリポジトリをPushしておきます。
git push origin master
プロジェクトの設定
CircleCIにログインし、先ほどのリポジトリの「Set Up Project」を選択してプロジェクト設定を行います。
環境変数の設定
Pipelineが動き出すので、右上にある「Project Settings」を選択します。
「Environment Variables」を選択し、環境変数の設定を行います。 コピペ時に空白が混ざらないように注意してください(たまに良くある)。
Name | Value |
---|---|
AWS_ACCESS_KEY_ID | 取得したAccessKeyId |
AWS_SECRET_ACCESS_KEY | 取得したSecretAccessKey |
AWS_DEPLOY_IAM_ROLE_ARN | 取得したIAMロールのARN |
AWS_DEPLOY_IAM_ROLE_EXTERNAL_ID | sts:ExternalIdで設定した値 |
AWS_DEFAULT_REGION | ap-northeast-1 |
AWS_DEFAULT_OUTPUT | json |
ROLE_SESSION_NAME | CircleCI |
いざ、実行!
既に動いて失敗しているPipelineがあると思うので、「Rerun」します。
しばらくすると、成功しました!
Jobの詳細を確認すると、S3バケットの一覧がバッチリ取得できています!
片付け
実験終了後、作成したIAMユーザなどを削除しておきます。使わないIAMユーザ(アクセスキー有)を放置するのは、セキュリティ的によろしくないからです。
aws cloudformation delete-stack \
--stack-name CircleCI-Sample-Prepare-Stack
さいごに
CircleCIでAWS CLI(v2)を使ってみました。 本記事では直接インストールしましたが、Dockerイメージを使う方式でも対応できそうです。