GitHub Actions から OIDC 経由で AWS の複数アカウントに Switch Role する

記事を御覧いただきありがとうございます。

株式会社アドウェイズ 技術本部 インフラストラクチャーDiv 第三ユニット インフラエンジニアの田口です。

AWS 等のクラウド環境のセキュリティに関しての仕事や、エンジニア全体の開発体験を向上させる取り組み等を行っています。

本稿では GitHub Actions から OIDC 経由で AWS の複数アカウントに Switch Role し Terraform を実行する方法についてお話しようと思います。

一口感覚の記事ですが知ってると割と幸せになれる系の記事だと思いますので是非ご覧くださいませ。

背景

皆さん IAM アクセスキーの撲滅はしていらっしゃいますか?

弊社では最近 VCS を GitLab Self-Managed から GitHub Enterprise Cloud に移行しようと動いています。

我々の部署はセキュリティ関係の推進も行いますので、 CI から AWS への接続は OIDC 使う方針に切り替えて IAM アクセスキーを減らすための調査を行いました。

今までは GitLab CI での AWS へのアクセスは IAM アクセスキーを CI/CD Variables に設定し、それを使って Switch Role するという仕組みだったのですが、下記の記事で紹介している通り、 AWS の認証情報は90日ごとにローテーションを行っています。

作業自体は簡単なんですが、使っている IAM アクセスキーが多いだけにめんどくさい結構な手間だったんですよね。

OIDC 使って IAM アクセスキー撲滅したろ!と意気揚々とワークフローを組み始めるのですが、2023年2月時点ではインターネットで調査を行っても OIDC 接続をしつつ他アカウントに Switch Role を行う方法は見つかりませんでした。

何かしら方法はあるんじゃないかなーと四苦八苦しながらベテランの大先輩と調査を行った結果、OIDC 接続のみで Switch Role することができたので筆を執りました。

同じ事をしたいけど方法がわからず断念した方、丁度こういう情報を探していた方、IAM アクセスキーを撲滅したい方等の参考になれば幸いです。

解決方法

事前準備

OIDC 接続用の IAM ロールの作成を完了させてください。OIDC 接続用 IAM ロールには Switch Role を行う権限をアタッチするのをお忘れなく。

本稿では OIDC 接続から Switch Role を行う方法のみ説明するため、OIDC ロールの作成方法については記載しません。

OIDC ロールの作成方法については以下の記事が参考になると思います。

ソースコード

OIDC 接続から Switch Role を行うためには、ワークフローファイルによる環境変数の操作と .aws/config を作成するシェルスクリプトでスイッチロールの権限設定を適切に行う必要があります。

まずはワークフローファイルと .aws/config を作成するシェルスクリプトをご覧ください。

# .github/workflow/OIDC_switch_role.yml
name: switch role on OIDC
on:
  - push
  - workflow_dispatch

env:
  TF_WORK_DIR: "./terraform/aws"
  AWS_PROFILE: aws_profile

jobs:
  run_terraform_aws:
    permissions:
      id-token: write
      contents: read
    runs-on: ubuntu-22.04
    steps:
      - name: repository checkout
        uses: actions/checkout@v3

      - name: AWS OIDC setting
        uses: aws-actions/configure-aws-credentials@v1-node16
        with:
          role-to-assume: arn:aws:iam::000000000000:role/github_actions_OIDC_role
          role-session-name: github_actions_OIDC_role
          aws-region: ap-northeast-1

      - name: setup terraform
        uses: hashicorp/setup-terraform@v2.0.3
        with:
          terraform_version: 1.3.9

      - name: make_aws_config
        run: |
          bash ./bash/make_aws_config.sh

      - name: terraform init
        working-directory: ${{ env.TF_WORK_DIR }}
        run: |
          unset AWS_ACCESS_KEY_ID
          unset AWS_SECRET_ACCESS_KEY
          unset AWS_SESSION_TOKEN
          terraform init

      - name: terraform plan
        working-directory: ${{ env.TF_WORK_DIR }}
        run: |
          unset AWS_ACCESS_KEY_ID
          unset AWS_SECRET_ACCESS_KEY
          unset AWS_SESSION_TOKEN
          terraform plan -out outfile

      - name: terraform apply
        working-directory: ${{ env.TF_WORK_DIR }}
        run: |
          unset AWS_ACCESS_KEY_ID
          unset AWS_SECRET_ACCESS_KEY
          unset AWS_SESSION_TOKEN
          terraform apply outfile
#!/usr/bin/env bash
# ./bash/make_aws_config.sh

mkdir ~/.aws

{
    echo "[source_profile]"
    echo "aws_access_key_id = ${AWS_ACCESS_KEY_ID}"
    echo "aws_secret_access_key = ${AWS_SECRET_ACCESS_KEY}"
    echo "aws_session_token = ${AWS_SESSION_TOKEN}"
    echo ""
} > ~/.aws/credentials

{
    echo "[profile dist_profile]"
    echo "source_profile = source_profile"
    echo "role_arn = arn:aws:iam::000000000000:role/aws_profile"
    echo "output = json"
    echo "region = ap-northeast-1"
    echo ""
} > ~/.aws/config

ワークフローファイルの説明

ワークフロー設定に関する部分について

name: switch role on OIDC
on:
  - push
  - workflow_dispatch

この部分はワークフローの名前と実行タイミングを設定しているだけですね。


env:
  TF_WORK_DIR: "./terraform/aws"
  AWS_PROFILE: aws_profile

環境変数の設定を行う部分になります。

AWS_PROFILE は Switch Role 先のプロファイル名を設定してください。

TF_WORK_DIR は terraform のコードが置いてあるディレクトリを設定しているだけなので必須ではありません。


jobs:
  run_terraform_aws:
    permissions:
      id-token: write
      contents: read
    runs-on: ubuntu-22.04

権限設定と runner の設定です。

permissionsconfigure-aws-credentials を動作させるために必要な権限を設定しています。

runner として何を使うかはお好みでどうぞ。


各 step について

      - name: repository checkout
        uses: actions/checkout@v3

ソースコードのチェックアウトです。定型文レベルで使われてますね。


      - name: AWS OIDC setting
        uses: aws-actions/configure-aws-credentials@v1-node16
        with:
          role-to-assume: arn:aws:iam::000000000000:role/github_actions_OIDC_role
          role-session-name: github_actions_OIDC_role
          aws-region: ap-northeast-1

Switch Role 元への OIDC 接続です。


      - name: setup terraform
        uses: hashicorp/setup-terraform@v2.0.3
        with:
          terraform_version: 1.3.9

Terraform を使いたかったのでアクションを使ってサクッとインストールしています。

OIDC 接続の Switch Role では必須ではありません。


      - name: make_aws_config
        run: |
          bash ./bash/make_aws_config.sh

今回の肝になる部分です。

シェルスクリプトの内容は先程お見せしましたがもう一度見てみましょう。

#!/usr/bin/env bash
# ./bash/make_aws_config.sh

mkdir ~/.aws

{
    echo "[source_profile]"
    echo "aws_access_key_id = ${AWS_ACCESS_KEY_ID}"
    echo "aws_secret_access_key = ${AWS_SECRET_ACCESS_KEY}"
    echo "aws_session_token = ${AWS_SESSION_TOKEN}"
    echo ""
} > ~/.aws/credentials

{
    echo "[profile dist_profile]"
    echo "source_profile = source_profile"
    echo "role_arn = arn:aws:iam::000000000000:role/aws_profile"
    echo "output = json"
    echo "region = ap-northeast-1"
    echo ""
} > ~/.aws/config

スクリプト自体は単純で ~/.aws/credentials~/.aws/config を作成して設定しているだけですね。

~/.aws/config を作成する部分の role_arn には Switch Role 先のプロファイルを設定してください。

~/.aws/credentials はこのままコピーで大丈夫です。(プロファイル名だけ変えたほうが良いかも)


      - name: terraform init
        working-directory: ${{ env.TF_WORK_DIR }}
        run: |
          unset AWS_ACCESS_KEY_ID
          unset AWS_SECRET_ACCESS_KEY
          unset AWS_SESSION_TOKEN
          terraform init

      - name: terraform plan
        working-directory: ${{ env.TF_WORK_DIR }}
        run: |
          unset AWS_ACCESS_KEY_ID
          unset AWS_SECRET_ACCESS_KEY
          unset AWS_SESSION_TOKEN
          terraform plan -out outfile

      - name: terraform apply
        working-directory: ${{ env.TF_WORK_DIR }}
        run: |
          unset AWS_ACCESS_KEY_ID
          unset AWS_SECRET_ACCESS_KEY
          unset AWS_SESSION_TOKEN
          terraform apply outfile

terraform init 等を行っています。

ここでは Switch Role 先の AWS アカウントに Terraform からリソースを作成することを想定しています。

Switch Role 先のアカウントに操作を行う場合、必ず AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKENunset してください。

解説

コードを見てもらったのでもうわかる方もいらっしゃるかもしれませんが、何故これで Switch Role できるのか解説します。

ざっくり言ってしまえば aws-actions/configure-aws-credentials が設定している AWS 認証関係の環境変数を手動で unset することで、 シェルスクリプトが作成した認証情報ファイルが AWS への接続として利用できる様になるからです。

上記のリファレンスにも記載されている通り、 AWS への接続する際の認証情報には優先順位があります。

aws-actions/configure-aws-credentials は内部的に認証情報を環境変数で設定するため、 unset で環境変数を削除しない限り --profile 等のコマンドラインオプション以外の認証情報よりも強くなってしまいます。

なので環境変数を認証情報ファイルにソースプロファイルとして書き出し、環境変数自体は削除してしまうことで OIDC 接続先の IAM ロールを利用しつつ Switch Role も可能になるというわけです。

わかってしまえばこれだけなんですが aws-actions/configure-aws-credentials が何をしているのか、環境変数をどうすればソースプロファイルとして扱えるのかがよくわからず結構な時間悩んでいました。

AWS の認証関係むずかしいねんな。

ユニットの宣伝

インフラストラクチャー Div 第三ユニットは SRE, DevSecOps, セキュリティに興味のある方を募集しております。

僕はインフラ関係完全未経験で入ったのですが、やりたい仕事をアピールすれば近い仕事をさせてくれますし難易度が高そうな仕事も先輩方が手厚くサポートしてくれますのでストレスなく成長できるユニットです。

もちろん経験者の方も他ユニットのサポートやアドバイス、新しい技術の調査や検証などやりがいのある仕事ができると思います。

面白そうやんけ!と思っていただけた方は是非採用ページからご応募ください。

おわりに

いかがでしたか?(定型文)

調べるのにはかなり時間がかかったんですが、文章としてまとめると意外とシンプルでした。

この記事を見て問題解決できる方がいれば幸いです。

良ければブックマークの方も何卒〜。