🐇

【IAM OIDC IDプロバイダーの仕組みを見てみる】GitHub ActionsからAWSに一時認証情報を使用してアクセスする

2024/07/28に公開

伝えたいこと・ねらい

IAM IDプロバイダーの利用により、AWS外部のアプリケーション(GitHub等)に認証情報を長期間保存せず、一時的な認証情報によるAWSリソースへのアクセスを可能とすることができます。

一時的な認証情報の利用はAWS Well-Architected Framework セキュリティの柱でも定義されています。

SEC02-BP02 一時的な認証情報を使用する

https://docs.aws.amazon.com/ja_jp/wellarchitected/latest/security-pillar/sec_identities_unique.html

長期的な認証情報には多くのリスクがあります。
たとえば、パブリックな場所にうっかり認証情報をアップロードしてしまうなど。一時的な認証情報であれば有効期限が切れるとその認証情報にアクセス権限がなくなるので、流出時のリスクを低減させることができます。
人力を信じないことは大切で、あらゆる「あるべき姿」には仕組みづくりが最も有効的だと考えています。

この記事では、IAM OIDC IDプロバイダーを利用したGitHubActoinsでのAWSアクセスの実装を通して、その仕組みを紐解いてみます。

実際にやったこと

GitHubActionsからAWSリソースへの一時認証によるアクセスを実装

GitHubリポジトリの特定ブランチへのpushをトリガーにS3バケットにソースコードをsyncさせるGitHubActionsワークフローの実装
oidc_id_provider_05

OIDCとは

ODIC=OpenID Connectとは、認証のための標準仕様です。
認可プロトコルであるOAuthを拡張したものになります。
過去記事にも書きました。
https://zenn.dev/mai_mizz/articles/cce2d2c764e9fc#oauthとoidc

例えばGitHubはOIDC仕様をサポートしており、外部アプリケーションからの認証リクエストのために仕様に則った公開URLを提供しています。

IAM OIDC IDプロバイダーとは

IAM OIDC ID プロバイダーは OpenID Connect (OIDC) 標準 (例: Google または Salesforce) をサポートする ID プロバイダー (IdP) サービスを表す IAM のエンティティです。OIDC 互換 IdP と AWS アカウント の間で信頼性を確立するときに IAM OIDC ID プロバイダーを使用します。
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_providers_create_oidc.html

AWSアカウントとOIDCをサポートする外部IdPとの信頼関係を確立するためのIAMエンティティと言えます。
oidc_id_provider_01
GitHub Actionsのドキュメントも分かりやすいです。
https://docs.github.com/ja/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#getting-started-with-oidc

「IAM OIDC IDプロバイダーはIAMのエンティティ」について

IAM OIDCプロバイダーはIAMユーザーでもIAMロールでもないのでは?と思いました。
しかしリソースベースのポリシーにおけるPrincipalに指定することができます。Principalに指定することができるのは、認証済みのIAMエンティティです。
この意味だと、IAM OIDC IDプロバイダーはIAMエンティティだと解釈できます。
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements_principal.html

信頼関係

IAM OIDC IDプロバイダーを作成したら、外部IdPにより認証されたアイデンティティがIAMロールを引き受けるように構成します。
oidc_id_provider_04

信頼ポリシーは以下のようになります。(例:GitHub OIDC)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::XXXXXXXXXXXX:oidc-provider/token.actions.githubusercontent.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
                },
                "StringLike": {
                    "token.actions.githubusercontent.com:sub": "repo:XXXXX/XXXXX:*"
                }
            }
        }
    ]
}

前項で説明したように、プリンシパルにはセッションプリンシパルとしてIAM OIDC IDプロバイダーを指定しています。
またActionにはsts:AssumeRoleWithWebIdentityを指定しています。WithWebIdentityがついていることに注意です。外部からのAWSリソースへのアクセスのためのAssumeRoleアクションを許可する際にはこちらのアクションを指定する必要があります。
参考:https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_temp_request.html

AssumeRoleとはロールを引き受けるアクションであり、AWS STS = Security Token Serviceという一時的な認証情報を生成するサービスのアクションの一つです。
つまり、このIAMロールによって一時的にAWSリソースへのアクセス権限を持つことが可能になります。
言い換えると、外部IdPによる認証を使用してIAMロールを引き受ける=一時的な認証情報を仕様することができます。

IAMロール周りについても過去記事あり。
https://zenn.dev/fusic/articles/1538897dd8f092

OIDC仕様を少しだけ覗いてみる

上記IAMロールで、Conditionを指定しているのもポイントです。
ここではOIDCプロバイダーから得られるクレームから検証条件として追加できます。
[参考]
https://openid-foundation-japan.github.io/draft-ietf-oauth-json-web-token-11.ja.html
条件として指定しているのはaudsubです。

"StringEquals": {
  "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
  "token.actions.githubusercontent.com:sub": "repo:XXXXX/XXXXX:*"
}

aud(Audience)クレーム

aud(audience)クレームは JWT を利用することが想定された主体の識別子一覧である

今回OIDCプロバイダーから受け取るJWTを利用するのはAWS STSなので、ここではsts.amazonaws.comを指定します。

sub(Subject)クレーム

sub(subject)クレームは JWT の主語となる主体の識別子である

GitHub OIDCプロバイダーを使用する場合、OIDCプロバイダーを「認証サーバー」という言葉で言い換えた時にサーバー側=GitHub側の主体が何か?を考えると分かりやすいです。
Organization、リポジトリ名を指定することになるのでrepo:XXXXX/XXXXX:*のように指定します。

やってみる

ここではGitHub Actionsを例にやってみます。
GitHub Actionsドキュメントに、GitHub OIDCを使用したフェデレーションIDをAWSで信頼するための設定方法が記載されています。
https://docs.github.com/ja/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services

主な流れ

  1. AWSでIAM OIDC IDプロバイダーを作成
  2. IAMロールと信頼ポリシーを作成
  3. GitHub Actionsワークフローの更新

IAM OIDC IDプロバイダーの作成

AWS IAMコンソールの左サイドバーにある「Identity Providers」内から作成します。
この時、

  • 「Provider URL」にはhttps://token.actions.githubusercontent.com
  • 「Audience」にはsts.amazonaws.com

を指定します。
oidc_id_provider_02

IAM OIDC IDプロバイダーを介して外部IdP認証ユーザーにロールを割り当てる

IAM OIDC IDプロバイダーで外部IdPにより認証されたユーザーがIAMロールを引き受けられるように設定します。
ここから作成。
oidc_id_provider_03
新規作成または作成済みのIAMロールを使用します。

ロールの信頼ポリシーは上述したもの。
そしてこのIAMロールに、S3へのアクセスを許可するポリシーをアタッチします。

これによって、【IAM OIDC IDプロバイダーが信頼関係を確立したGitHub OIDCプロバイダー】により認証されたアイデンティティが【S3へのアクセス権を持つIAMロール】を引き受けることができます。

GitHub ActionsのワークフローでIAMロールを使用する

https://docs.github.com/ja/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services#github-actions-ワークフローを更新するA
ここに書かれている内容にしたがってワークフローファイルを更新します。
ポイントは以下の二つです。

  • GitHub OIDC プロバイダーからJWTを受け取るためpermissonsを指定
  • aws-actions/configure-aws-credentialsで IAMロールを使用して一時認証情報を取得
ワークフローファイル
name: Sync to S3

on:
  push:
    branches:
      - deploy

permissions:
  id-token: write # This is required for requesting the JWT
  contents: read  # This is required for actions/checkout

jobs:
  sync:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout source
        uses: actions/checkout@v4
        with:
          ref: deploy

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ap-northeast-1
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          role-session-name: GitHubActions-to-AWS

      - name: sync src to S3
        run: |
          aws s3 sync . s3://{バケット名}/ --exclude "*" --include "src/*"

GitHub OIDCプロバイダからJWTを受け取る

GitHub Actionsドキュメントにあるように、以下をワークフローファイルに記述します。

permissions:
  id-token: write # This is required for requesting the JWT
  contents: read  # This is required for actions/checkout

ここでid-token: writeを指定することでAWS IAM OIDC IDプロバイダーを介してGitHub OIDCプロバイダーから受け取ったJWTをワークフローに書き込む権限を設定しておきます。

ワークフロー内でIAMロールを使用して一時認証情報を取得

https://github.com/aws-actions/configure-aws-credentials?tab=readme-ov-file#oidc

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ap-northeast-1
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          role-session-name: GitHubActions-to-AWS

このように記述することで一時認証情報を取得し、ワークフローでAWSリソースの操作(IAMロールにアタッチされた許可ポリシーによる)が可能になります。
IAMロールのarnはGitHubリポジトリ内でシークレットに登録しておきます。

何が起きているのか

まとめると以下の図のようになります。
oidc_id_provider_06

まとめ

IAM OIDC IDプロバイダーを利用することでOIDC仕様をサポートする外部IdP(今回はGitHub)による認証を用いてAWSへの一時的な認証情報を使用することができました。
今回はその仕組みを学ぶ記事でしたが、実装自体はとても簡単です。
AWSもベストプラクティスだとしている一時的な認証情報の使用の手段を知ってしまえば、この方法を取らない(=長期的なcredentialを利用する)理由がないなーと思いました。

認識や表現に誤りなどありましたら教えてください!
IAMおよびOIDCについても改めて学ぶことができたのでよかったです、また深掘りしたい🙏🏻

GitHubで編集を提案
Fusic 技術ブログ

Discussion