circleci/aws-cli@3.1.5を使ったOIDC連携の自動デプロイをCIrcleCIのCI/CDに導入する

2023.04.21

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

CX事業本部 Delivery 部のアベシです。
先日投稿したこちらのブログで、CircleCIのCI/CDでLocalStackを使ったテストを実行する方法紹介しました。

今回は特定のブランチへのmergeをトリガーにしてOIDC連携よるデプロイが走るようにしてみましたので、その際の設定や手順をご紹介したいと思います。 CircleCIとAWSとのOIDC連携には便利なOrbのcircleci/aws-cli@3.1.5が使えますので導入してみました。

導入までの大まかな流れ

以下の流れでやっていきます。

  1. AWSでIDプロバイダーと信頼関係を持つIAMロールを作成
  2. CI/CDワークフローの設定ファイル(.circleci/config.yml)にデプロイのジョブを追加
  3. config.ymlにaws-cli: circleci/aws-cli@3.1.5とAWS CLIのインストールなどやってくれるコマンドのaws-cli/setupを追加
  4. デプロイ先のリージョンを環境変数に設定
  5. 変更をmainブランチにマージしてCI/CDの結果がSuccessとなり、AWSにリソースがデプロイされていればOK

AWSでIDプロバイダーとプロバイダーと信頼関係の有るIAMロールを作成

AWS側でIDプロバイダーとIAMロールの作成については以下のブログに詳しく載っていますので参考にしてください。こちらのブログでは割愛します。

IDプロバイダーを作る際にCircleCIのOrganization IDが必要になるので先にContextを作成してください。 このやり方も上記のブログに載っていますので参考にしてください。

デプロイに関する修正をconfig.ymlに追加

それではここからはconfig.ymlの修正に入っていきます。 まずはmainブランチに変更がマージされた時にデプロイが走るようにします。 前回までのconfig.ymlはこちらから確認できます。この段階ではテストまでが可能でした。
修正を加えたconfig.ymlは以下となります。ハイライトした部分が修正部位となります。

.circleci/config.yml

version: 2.1

references:
  test_and_build_container: &test_and_build_container
    docker:
      - image: cimg/node:18.16.0
      - image: localstack/localstack:2.0.1
        environment:
          DOCKER_HOST: "unix:///var/run/docker.sock"
          DEBUG: "1"

  deploy_container: &deploy_container
    docker:
      - image: cimg/node:18.16.0

  restore_npm_dependencies: &restore_npm_dependencies
    restore_cache:
      key: v1-dependencies-{{ .Branch }}-{{ checksum "package.json" }}-{{ checksum "package-lock.json" }}

  install_npm_dependencies: &install_npm_dependencies
    run:
      name: Install npm dependencies
      command: |
        set -x
        [[ -d node_modules ]] || npm ci

  save_npm_dependencies: &save_npm_dependencies
    save_cache:
      paths:
        - node_modules
      key: v1-dependencies-{{ .Branch }}-{{ checksum "package.json" }}-{{ checksum "package-lock.json" }}

  test_unit: &test_unit
    run:
      name: Test unit
      command: |
        set -x
        npm run unit-test

  deploy_to_aws: &deploy_to_aws
    run:
      name: Deploy to AWS
      command: |
        set -x
        npm run deploy

jobs:
  test_and_build:
    <<: *test_and_build_container
    steps:
      - checkout
      - <<: *restore_npm_dependencies
      - <<: *install_npm_dependencies
      - <<: *save_npm_dependencies
      - <<: *test_unit

  deploy:
    <<: *deploy_container
    steps:
      - checkout
      - <<: *restore_npm_dependencies
      - <<: *install_npm_dependencies
      - <<: *save_npm_dependencies
      - <<: *deploy_to_aws

workflows:
  test_workflows:
    jobs:
      - test_and_build:
          filters:
            branches:
              only:
                - /.*/
      - deploy:
          requires:
            - test_and_build
          filters:
            branches:
              only:
                - main

config.ymlの修正部位の説明

references:

アンカー

デプロイのjobにおいても同じ内容のstepを一部使い回すために、各々をアンカーにして扱います。 例えば以下のnode_moduleのリストアの部分はrestore_npm_dependencies の前に&を付けて&amp;restore_npm_dependenciesと記述することでアンカーとなります。

  restore_npm_dependencies: &restore_npm_dependencies
    restore_cache:
      key: v1-dependencies-{{ .Branch }}-{{ checksum "package.json" }}-{{ checksum "package-lock.json" }}

エイリアス

アンカー&amp;restore_npm_dependencies<<: *restore_npm_dependenciesと書くことでエイリアスとして使うことができます。

エイリアスはアンカーに指定したjob名の前に*を付けて*restore_npm_dependenciesと記述します。 使用したい場所で、<<:を付けて<<: *restore_npm_dependenciesと記述することでアンカーをエイリアスで呼び出せます。 アンカー化したjobを以下のように記述してstepsの中で呼び出すことができます。

jobs:
  test_and_build:
    <<: *test_and_build_container
    steps:
      - checkout
      - <<: *restore_npm_dependencies # アンカーをエイリアスで呼び出す

deploy_container: &deploy_container

デプロイ中に使用するCircleCIのNode.JS用イメージを定義します。

deploy_container: &deploy_container
  docker:
    - image: cimg/node:18.16.0

deploy_to_aws: &deploy_to_aws

デプロイのjobを定義します。 run deployはCDKデプロイコマンドをnpm スクリプト化したものでpackage.jsonに書いています。

deploy_to_aws: &deploy_to_aws
  run:
    name: Deploy to AWS
    command: |
      set -x
      npm run deploy

jobs:

node_noduleのリストア、インストール、キャッシュの保存の後にデプロイjobが作動するようにエイリアスを呼び出しています。

  deploy:
    <<: *deploy_container
    steps:
      - checkout
      - <<: *restore_npm_dependencies
      - <<: *install_npm_dependencies
      - <<: *save_npm_dependencies
      - <<: *deploy_to_aws

workflows:

デプロイのワークフローをworkflow:に追加しています。 requires:にテストとビルドのワークフローを指定することで、テストとビルドが終わってからデプロイが走るようになります。 また、テストとビルドが失敗した場合はデプロイは走らないようになります。 filters:にはjobを実行する対象のブランチを指定します。今回はmainブランチのみに指定しています。その他のブランチへのマージやプッシュではデプロイは走りません。

  deploy:
    requires:
      - test_and_build
    filters:
      branches:
        only:
          - main

OIDCに関するconfig.ymlの修正

OIDC連携によるデプロイを可能にするためconfig.ymlの修正を行います。 修正したconfig.ymlは以下の通りです。

.circleci/config.yml

version: 2.1
orbs:
  aws-cli: circleci/aws-cli@3.1.5

references:
  test_and_build_container: &test_and_build_container
    docker:
      - image: cimg/node:18.16.0
      - image: localstack/localstack:2.0.1
        environment:
          DOCKER_HOST: "unix:///var/run/docker.sock"
          DEBUG: "1"

  deploy_container: &deploy_container
    docker:
      - image: cimg/node:18.16.0

  restore_npm_dependencies: &restore_npm_dependencies
    restore_cache:
      key: v1-dependencies-{{ .Branch }}-{{ checksum "package.json" }}-{{ checksum "package-lock.json" }}

  install_npm_dependencies: &install_npm_dependencies
    run:
      name: Install npm dependencies
      command: |
        set -x
        [[ -d node_modules ]] || npm ci

  save_npm_dependencies: &save_npm_dependencies
    save_cache:
      paths:
        - node_modules
      key: v1-dependencies-{{ .Branch }}-{{ checksum "package.json" }}-{{ checksum "package-lock.json" }}

  test_unit: &test_unit
    run:
      name: Test unit
      command: |
        set -x
        npm run unit-test

  aws_cli_setup: &aws_cli_setup
    aws-cli/setup:
      profile-name: WEB-IDENTITY-PROFILE
      role-arn: arn:aws:iam::**********:role/circleci-oidc-role
      role-session-name: deploy-session

  deploy_to_aws: &deploy_to_aws
    run:
      name: Deploy to AWS
      command: |
        set -x
        npm run deploy

jobs:
  test_and_build:
    <<: *test_and_build_container
    steps:
      - checkout
      - <<: *restore_npm_dependencies
      - <<: *install_npm_dependencies
      - <<: *save_npm_dependencies
      - <<: *test_unit

  deploy:
    <<: *deploy_container
    steps:
      - checkout
      - <<: *restore_npm_dependencies
      - <<: *install_npm_dependencies
      - <<: *save_npm_dependencies
      - <<: *aws_cli_setup
      - <<: *deploy_to_aws

workflows:
  test_workflows:
    jobs:
      - test_and_build:
          filters:
            branches:
              only:
                - /.*/
      - deploy:
          requires:
            - test_and_build
          filters:
            branches:
              only:
                - main
          context: AWS-CONTEXT

修正したconfigの説明

orbs:

Orbは複数のコマンドをまとめいた再利用可能なパッケージです。 今回使用するcircleci/aws-cli@3.1.5はaws-cliを使った便利な機能提供してくれます。 この機能(Command)の内のaws-cli/setupを使うとOIDC用のIAMロールを使用してデプロイできます。 以下のリンク先の例を参考にreferences:の中にcommandを記述します。

  aws-cli_setup: &aws-cli_setup
    aws-cli/setup:
      profile-name: WEB-IDENTITY-PROFILE
      role-arn: arn:aws:iam::***********:role/circleci-oidc-role
      role-session-name: deploy-session

role-arnにはAWSのIDプロバイダーと信頼関係のあるIAMロールのARNを指定します。 リージョンの指定をしないとデプロイがコケますのでAWS_DEFAULT_REGIONという名前の環境変数にリージョンを設定しています。こちらにap-northeast-1を登録しました。

以下のようにdeployのワークフローのデプロイのjobの前にaws-cli_setupのエイリアスを追加します。

  deploy:
    <<: *deploy_container
    steps:
      - checkout
      - <<: *restore_npm_dependencies
      - <<: *install_npm_dependencies
      - <<: *save_npm_dependencies
      - <<: *aws_cli_setup
      - <<: *deploy_to_aws

workflows:

deploy:にcontextの名前を追加します。 context: AWS-CONTEXTのように書きます。 contextを作成済みであればorganization settingsのContextsから見つけられます。

動作確認

実際にマージして動作確認を行います。 以下のようにステータスがsuccessとなればデプロイは成功です。

デプロイログの確認

以下のようなログが出力されており、デプロイしたスタックのARNが表示されています。

リソースの確認

CloudFormationのコンソールからデプロイしたスタックを確認します。 デプロイログに出力されたARNと同じARNのスタックが存在していることを確認できました。

以上。