【IAM OIDC IDプロバイダーの仕組みを見てみる】GitHub ActionsからAWSに一時認証情報を使用してアクセスする
伝えたいこと・ねらい
IAM IDプロバイダーの利用により、AWS外部のアプリケーション(GitHub等)に認証情報を長期間保存せず、一時的な認証情報によるAWSリソースへのアクセスを可能とすることができます。
一時的な認証情報の利用はAWS Well-Architected Framework セキュリティの柱でも定義されています。
SEC02-BP02 一時的な認証情報を使用する
長期的な認証情報には多くのリスクがあります。
たとえば、パブリックな場所にうっかり認証情報をアップロードしてしまうなど。一時的な認証情報であれば有効期限が切れるとその認証情報にアクセス権限がなくなるので、流出時のリスクを低減させることができます。
人力を信じないことは大切で、あらゆる「あるべき姿」には仕組みづくりが最も有効的だと考えています。
この記事では、IAM OIDC IDプロバイダーを利用したGitHubActoinsでのAWSアクセスの実装を通して、その仕組みを紐解いてみます。
実際にやったこと
GitHubActionsからAWSリソースへの一時認証によるアクセスを実装
GitHubリポジトリの特定ブランチへのpushをトリガーにS3バケットにソースコードをsyncさせるGitHubActionsワークフローの実装
OIDCとは
ODIC=OpenID Connectとは、認証のための標準仕様です。
認可プロトコルであるOAuthを拡張したものになります。
過去記事にも書きました。
例えば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エンティティと言えます。
GitHub Actionsのドキュメントも分かりやすいです。
「IAM OIDC IDプロバイダーはIAMのエンティティ」について
IAM OIDCプロバイダーはIAMユーザーでもIAMロールでもないのでは?と思いました。
しかしリソースベースのポリシーにおけるPrincipal
に指定することができます。Principal
に指定することができるのは、認証済みのIAMエンティティです。
この意味だと、IAM OIDC IDプロバイダーはIAMエンティティだと解釈できます。
信頼関係
IAM OIDC IDプロバイダーを作成したら、外部IdPにより認証されたアイデンティティがIAMロールを引き受けるように構成します。
信頼ポリシーは以下のようになります。(例: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ロール周りについても過去記事あり。
OIDC仕様を少しだけ覗いてみる
上記IAMロールで、Condition
を指定しているのもポイントです。
ここではOIDCプロバイダーから得られるクレームから検証条件として追加できます。
[参考]
条件として指定しているのはaud
とsub
です。
"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で信頼するための設定方法が記載されています。
主な流れ
- AWSでIAM OIDC IDプロバイダーを作成
- IAMロールと信頼ポリシーを作成
- GitHub Actionsワークフローの更新
IAM OIDC IDプロバイダーの作成
AWS IAMコンソールの左サイドバーにある「Identity Providers」内から作成します。
この時、
- 「Provider URL」には
https://token.actions.githubusercontent.com
- 「Audience」には
sts.amazonaws.com
を指定します。
IAM OIDC IDプロバイダーを介して外部IdP認証ユーザーにロールを割り当てる
IAM OIDC IDプロバイダーで外部IdPにより認証されたユーザーがIAMロールを引き受けられるように設定します。
ここから作成。
新規作成または作成済みのIAMロールを使用します。
ロールの信頼ポリシーは上述したもの。
そしてこのIAMロールに、S3へのアクセスを許可するポリシーをアタッチします。
これによって、【IAM OIDC IDプロバイダーが信頼関係を確立したGitHub OIDCプロバイダー】により認証されたアイデンティティが【S3へのアクセス権を持つIAMロール】を引き受けることができます。
GitHub ActionsのワークフローでIAMロールを使用する
ポイントは以下の二つです。
- 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ロールを使用して一時認証情報を取得
- 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リポジトリ内でシークレットに登録しておきます。
何が起きているのか
まとめると以下の図のようになります。
まとめ
IAM OIDC IDプロバイダーを利用することでOIDC仕様をサポートする外部IdP(今回はGitHub)による認証を用いてAWSへの一時的な認証情報を使用することができました。
今回はその仕組みを学ぶ記事でしたが、実装自体はとても簡単です。
AWSもベストプラクティスだとしている一時的な認証情報の使用の手段を知ってしまえば、この方法を取らない(=長期的なcredentialを利用する)理由がないなーと思いました。
認識や表現に誤りなどありましたら教えてください!
IAMおよびOIDCについても改めて学ぶことができたのでよかったです、また深掘りしたい🙏🏻
Discussion