AWSでアプリケーションを構築・運用している場合、CI / CDサービスとAWSアカウントの連携は避けて通れません。コンテナイメージのデプロイやE2Eテスト用の環境構築の自動化、CloudFormation / AWS CDKなどを利用したアプリケーションの本番リリース作業やAmazon Bedrockを利用したCIタスクの実行など、さまざまな形でAWSアカウントとの連携が必要となります。
CircleCIとAWSアカウントの安全な連携には、 OIDC(OpenID Connect)が利用できます。この記事では、CircleCI と AWS を OIDC で連携し、ECR へのイメージ push までを自動化するパイプラインを構築します。
なぜ OIDC なのか
AWS は現在、セキュリティ上の理由から永続的なアクセスキーとシークレットキーの利用を非推奨としています。
ベストプラクティスとして、AWS アカウント内に個別に IAM ユーザーを作成するのではなく、ID プロバイダーとのフェデレーションを使用して AWS リソースにアクセスするように人間のユーザーに求めることをお勧めします。
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_providers.html
そのため、CircleCI から AWS へアクセスする際は、最新のベストプラクティスである OIDC(OpenID Connect)連携を採用します。
OIDC を採用するメリット
OIDCを利用した場合、AWSへのアクセスに利用する認証情報を使い捨てにします。CircleCI が発行した「一定時間で利用できなくなる認証情報」にてアクセスするため、万が一の漏洩リスクについても最小限に抑えることができます。
このように必要な時にだけアクセスキーを使い捨てる形を取るため、CircleCI上に保存した情報のローテーション作業なども不要となります。
より安全かつ効率的にAWSアカウントへのアクセスを実現する方法として、OIDCを利用した連携を推奨します。
AWSとCircleCIそれぞれで設定を行う
OIDCでの連携は、AWS / CircleCI両方で設定が必要です。
AWSにて指定したCircleCIの組織(Organization)へのアクセスを許可するIAMロールやIdentity Providerを発行します。
その後、作成したIAMロールをCircleCIのOrganization Contextに保存することで、連携が完了します。
ここからはstep by stepで方法を紹介します。
AWS 側の設定
まずAWS側でOIDCに利用するProviderやIAMロールを作成しましょう。
Step 1: CircleCI 組織ID を取得
CircleCI の Web アプリにログインし、Organization Settings → Overview に移動します。Organization ID(UUID 形式)が表示されていますので、コピーしましょう。
この ID は AWS 側の設定で複数回使用します。
Step 2: Identity Provider を作成
AWS Console で IAM → Identity providers → Add provider に移動し、以下を情報を入力しましょう。
| 項目 | 値 |
|---|---|
| Provider type | OpenID Connect |
| Provider URL | https://oidc.circleci.com/org/<organization_id> |
| Audience | <organization_id> |
<organization_id> には Step 1 で取得した組織ID を入れ、プロバイダーを作成しましょう。
Step 3: IAM Role を作成
Identity Provider の作成に成功すると下の画像のようなメッセージが表示されます。「ロールの割り当て」ボタンをクリックしましょう。もしメッセージが消えてしまった場合は、IAMのページからロールを新しく作成する画面操作でも、同様のアクションが行えます。
まずは「信頼されたエンティティタイプ」から「ウェブアイデンティティ」を選びます。その後下にフォームが表示されます。
以下の表を参考に情報を選択・入力しましょう。
| 項目 | 値 |
|---|---|
| Identity provider | 作成した CircleCI provider |
| Audience | 組織ID |
続いてロールに設定する権限を付与しましょう。ここで付与する権限は、CircleCI上で実行されるパイプラインにて利用するAWSリソースやアクションについて設定します。例えばECRへのpushを行う場合はAmazonEC2ContainerRegistryPowerUserなどを設定しましょう。
今回はシンプルさを優先してAWSが用意しているポリシーを選択しました。
実際のプロジェクトでは、最小限の権限に絞ったカスタムのポリシーを作成されることを推奨します。
ロールの作成後、信頼関係タブに移動します。
ここでは以下のような JSON が表示されています。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<account_id>:oidc-provider/oidc.circleci.com/org/<organization_id>"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.circleci.com/org/<organization_id>:aud": "<organization_id>"
}
}
}
]
}
各フィールドの意味は次の通りです。
-
Principal.Federated: どの Identity Provider を信頼するか -
Action: Web Identity での Role 引き受けを許可 -
Condition: CircleCI の組織ID が一致する場合のみ許可
作成したロールの ARN(例: arn:aws:iam::123456789012:role/circleci-oidc-role)をメモしておきましょう。
これでAWS側の作業は完了です。
CircleCI 側の設定
続いてCircleCI側の設定を行います。ここからは、先ほど作成したAWSのIAMロールやプロバイダーをパイプラインで利用できるようにしていきます。
Context を作成する
まずCircleCIのContextを作成しましょう。これはCircleCIにおける環境変数をプロジェクト間で共有できる仕組みです。OIDCで利用するIAMロールをContextへ保存することで、複数のプロジェクトで追加設定なくAWSアクセスができるようになります。
コンテキストは特定のチーム・ユーザーでのみ利用できる設定にすることが可能です。
これにより「本番リリースのパイプラインは特定のユーザーのみ実施できる」などの運用管理が実現できます。
詳細はドキュメントをご確認ください。
https://circleci.com/docs/guides/security/contexts/#restrict-a-context
CircleCI のダッシュボードにて、 Organization Settings → Contexts に移動しましょう。Create Contextボタンをクリックして、コンテキストを作成します。

名前は aws-oidc など、わかりやすいものにします。もし本番とテスト環境などで複数のAWSアカウントあるいはIAMポリシーを使い分けたい場合は、そのような名前にしましょう。
フォームでは環境変数の名前と値を入力します。名前にはAWS_ROLE_ARNを入力し、コピーしたIAMロールのARNを入力しましょう。
この作業を3回繰り返し、以下の表にあるデータをContextへ登録してください。
| 変数名 | 値の例 |
|---|---|
AWS_ROLE_ARN |
arn:aws:iam::123456789012:role/circleci-oidc-role |
AWS_REGION |
ap-northeast-1 |
AWS_ACCOUNT_ID |
123456789012 |
プロジェクトの環境変数に、プロジェクト固有の情報を保存する
デプロイや取得・操作を行いたいAWSリソースに関する情報は、プロジェクトごとに環境変数へ保存しましょう。ECR リポジトリ名や ECS クラスター名・S3バケット名などを保存します。
| 変数名 | 値の例 |
|---|---|
ECR_REPO_NAME |
my-app |
config.yml を実装する
最後にCircleCIのジョブを設定しましょう。.circleci/config.ymlに次のような形でジョブを定義します。
workflows:
deploy:
jobs:
- aws-ecr/build_and_push_image:
context: aws-oidc
auth:
- aws-cli/setup:
role_arn: ${AWS_ROLE_ARN}
region: ${AWS_REGION}
repo: ${ECR_REPO_NAME}
tag: ${CIRCLE_SHA1}
ポイントは、workflowsのjobsそれぞれにcontext: aws-oidcを追加することです。これにより該当のジョブでコンテキストを利用したOIDCによる認証情報の取得が行えるようになります。
実際の認証については、CircleCIが提供するorbsを組み合わせることで、AWS CLIのコマンドなどを記述せずに実行できます。
完成系の例として、NodejsのアプリをビルドしてECRにプッシュする例を用意しました。build と test を並列実行し、両方成功したら ECR に pushします。
version: 2.1
orbs:
node: circleci/node@7.2.1
aws-cli: circleci/aws-cli@5.4.1
aws-ecr: circleci/aws-ecr@9.8.1
jobs:
build:
executor: node/default
steps:
- checkout
- node/install-packages:
pkg-manager: npm
- run:
name: TypeScript ビルド
command: npm run build
test:
executor: node/default
steps:
- checkout
- node/install-packages:
pkg-manager: npm
- run:
name: Run tests with JUnit reporter
command: |
mkdir -p test-results
npm test -- --reporter=junit --outputFile=test-results/junit.xml --coverage
- store_test_results:
path: test-results
- store_artifacts:
path: coverage
workflows:
build-test-deploy:
jobs:
- build
- test
- aws-ecr/build_and_push_image:
context: aws-oidc
auth:
- aws-cli/setup:
role_arn: ${AWS_ROLE_ARN}
region: ${AWS_REGION}
region: ${AWS_REGION}
account_id: ${AWS_ACCOUNT_ID}
repo: ${ECR_REPO_NAME}
tag: ${CIRCLE_SHA1}
requires:
- build
- test
filters:
branches:
only: main
この構成では4つの orbs を使用しています。
- circleci/node: Node.js 環境と依存関係キャッシュを自動化
- circleci/aws-cli: OIDC 認証と AWS CLI セットアップ
- circleci/aws-ecr: ECR へのイメージビルド・プッシュ
orbs を使うことで、複雑な処理を数行の設定で実現できます。
例えば「Docker イメージのビルドと ECR へのプッシュ」というタスクは、aws-ecr orbにあるaws-ecr/build_and_push_image を利用しています。
region と account_id を明示的に指定しないと、ECR の URL が正しく構築されずエラーになる点に注意しましょう。
region: ${AWS_REGION}
account_id: ${AWS_ACCOUNT_ID}
repo: ${ECR_REPO_NAME}
tag: ${CIRCLE_SHA1}
tag には ${CIRCLE_SHA1}(コミットハッシュ)を使用しています。これにより、どのコミットからビルドされたイメージかを追跡できます。
トラブルシューティング
実際に構築する中で遭遇しやすいエラーと解決策を紹介します。
AccessDenied: Not authorized to perform sts:AssumeRoleWithWebIdentity
このエラーが出た場合、原因は3つ考えられます。
原因1: Context が指定されていない
OIDC トークンは Context を使用するジョブでのみ発行されます。ワークフローで context: を指定しているか確認してください。
# NG: context がない
- aws-ecr/build_and_push_image:
requires:
- build
# OK: context を指定
- aws-ecr/build_and_push_image:
context: aws-oidc
requires:
- build
原因2: Identity Provider が作成されていない
AWS IAM → Identity providers に CircleCI の Provider が存在するか確認してください。Trust Policy に ARN を書いただけでは Provider は作成されません。
原因3: Organization ID の不一致
CircleCI の Organization ID と、AWS の Identity Provider / Trust Policy に設定した ID が完全に一致しているか確認してください。余分なスペースや改行が入っていることもあります。
invalid tag / invalid reference format(ECR URL エラー)
ECR の URL にリージョンが含まれていないと発生します。
ERROR: failed to build: invalid tag "************.dkr.ecr..amazonaws.com/..."
aws-ecr/build_and_push_image に region と account_id パラメータを追加してください。
- aws-ecr/build_and_push_image:
region: ${AWS_REGION}
account_id: ${AWS_ACCOUNT_ID}
# ...
まとめ
CircleCI と AWS の OIDC 連携を設定し、ECR へのデプロイパイプラインを構築しました。OIDCを利用した連携にすることで、シークレット情報を発行・保存する必要がなくなり、よりセキュアにアプリケーションのデプロイやテストをAWSと連携して行えるようになります。
またAWSへのデプロイについては、サービスに対応したさまざまな orbs が公開されています。今回はECRを紹介しましたが、SAMやAWS CLI / CodeDeployなどにも対応していますので、ぜひお試しください。
terrafromにも対応しています。













