GitHub ActionsのOIDCを使ってAWS公式のActionsを動かす方法
はじめに
GitHub ActionsからOIDC経由でAWSのAssume Roleをすることで、色々と便利になりました。[1]
公式にアナウンスされたこともあり導入に向けて動いていました。
ところで、以下のようなGitHub Actionsの例はよく見ると思います。[2]
- name: Configure AWS
env:
ACCOUNT_ID: ${{ secrets.ACCOUNT_ID }}
ROLE_NAME: ${{ secrets.ROLE_NAME }}
run: |
export AWS_ROLE_ARN="arn:aws:iam::${ACCOUNT_ID}:role/${ROLE_NAME}"
export AWS_WEB_IDENTITY_TOKEN_FILE=/tmp/awscreds
export AWS_DEFAULT_REGION=us-east-1
echo AWS_WEB_IDENTITY_TOKEN_FILE=$AWS_WEB_IDENTITY_TOKEN_FILE >> $GITHUB_ENV
echo AWS_ROLE_ARN=$AWS_ROLE_ARN >> $GITHUB_ENV
echo AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION >> $GITHUB_ENV
curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL" | jq -r '.value' > $AWS_WEB_IDENTITY_TOKEN_FILE
- run: aws sts get-caller-identity
上記のGitHub Actionsを動かすためには、IDプロバイダとそのIDプロバイダからAssumeできるIAM Roleが必要となります。
ActionsAWSのIDプロバイダ側の対象者(ClientID)はhttps://github.com/${GitHubOrg名}
としています。
この状態で、AWSの公式のActions[3]を利用したときに色々つまづいたので、ここにまとめます。
動かしたい人向けの結論
-
AWS公式クレデンシャル設定のActionsを使用しましょう
role-to-assume
のパラメタのみを設定することで、AWS公式のActionsが利用するクレデンシャル情報を払い出してくれています。 - AWS OIDCプロバイダの設定の対象者(ClientID, audience)に
sts.amazonaws.com
を許可するように設定する必要があります。
調査の流れ
以下発生したエラーとそれに付随する情報等を記載しています。
最初のエラー(No credentials) と AWS_WEB_IDENTITY_TOKEN_FILE の話
最初に以下のような状態で動かすとNo credentials. Try adding @aws-actions/configure-aws-credentials earlier in your job to set up AWS credentials.
というエラーが出ました
- name: Configure AWS
env:
ACCOUNT_ID: ${{ secrets.ACCOUNT_ID }}
ROLE_NAME: ${{ secrets.ROLE_NAME }}
run: |
export AWS_ROLE_ARN="arn:aws:iam::${ACCOUNT_ID}:role/${ROLE_NAME}"
export AWS_WEB_IDENTITY_TOKEN_FILE=/tmp/awscreds
export AWS_DEFAULT_REGION=us-east-1
echo AWS_WEB_IDENTITY_TOKEN_FILE=$AWS_WEB_IDENTITY_TOKEN_FILE >> $GITHUB_ENV
echo AWS_ROLE_ARN=$AWS_ROLE_ARN >> $GITHUB_ENV
echo AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION >> $GITHUB_ENV
curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL" | jq -r '.value' > $AWS_WEB_IDENTITY_TOKEN_FILE
- name: Run CodeBuild
uses: aws-actions/aws-codebuild-run-build@v1
with:
project-name: CodeBuildProjectName
なぜaws sts get-caller-identity
だと動作するのに、公式のActionsだと失敗するのかは、それぞれのクレデンシャル情報取得処理に鍵があります。
AWS CLIとAWS_WEB_IDENTITY_TOKEN_FILEの話
awsコマンドで実行されるAWS CLIでは設定を行うことで、自動的にAssumeRoleWithWebIdentityの呼び出しが行われています。
その設定方法の1つとして、環境変数AWS_WEB_IDENTITY_TOKEN_FILE
の設定があります。
そのため、上記でaws sts get-caller-identity
を動作させたときには、内部的にAssumeRoleWithWebIdentity
が実行され、その実行結果から得られる一時的なクレデンシャル情報が使われています。
aws-codebuild-run-buildとaws-sdkのクレデンシャル取得の処理
詳細はところまで終えていませんが、結局aws-sdk
を実行しているだけのため、aws-sdkのドキュメントに従うと考えられます。
ドキュメントによると、AWS_WEB_IDENTITY_TOKEN_FILE
はサポートされておらず、AWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
, AWS_SESSION_TOKEN(optional)
がサポートされているようです。
自前で書く
最初のエラーはAssumeRoleWithWebIdentity
を、AWS CLIは勝手にやってくれているが、AWS SDKはやってくれていないことに起因しています。
そのため、勝手にやってくれていることを、自分で書くことで、動作することが確認できました。
- name: Configure AWS
env:
ACCOUNT_ID: ${{ secrets.ACCOUNT_ID }}
ROLE_NAME: ${{ secrets.ROLE_NAME }}
run: |
export AWS_ROLE_ARN="arn:aws:iam::${ACCOUNT_ID}:role/${ROLE_NAME}"
export AWS_WEB_IDENTITY_TOKEN_FILE=/tmp/awscreds
export AWS_DEFAULT_REGION=ap-northeast-1
echo AWS_WEB_IDENTITY_TOKEN_FILE=$AWS_WEB_IDENTITY_TOKEN_FILE >> $GITHUB_ENV
echo AWS_ROLE_ARN=$AWS_ROLE_ARN >> $GITHUB_ENV
echo AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION >> $GITHUB_ENV
curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL" | jq -r '.value' > $AWS_WEB_IDENTITY_TOKEN_FILE
- name: Configure Manually
run: |
AWS_WEB_IDENTITY_TOKEN=$(cat $AWS_WEB_IDENTITY_TOKEN_FILE)
CREDENTIALS=$(aws sts assume-role-with-web-identity --role-arn ${AWS_ROLE_ARN} --role-session-name MySessionName --web-identity-token ${AWS_WEB_IDENTITY_TOKEN})
export AWS_ACCESS_KEY_ID=$(echo $CREDENTIALS | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo $CREDENTIALS | jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo $CREDENTIALS | jq -r '.Credentials.SessionToken')
echo AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID >> $GITHUB_ENV
echo AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY >>$GITHUB_ENV
echo AWS_SESSION_TOKEN=$AWS_SESSION_TOKEN >> $GITHUB_ENV
- name: Run CodeBuild
uses: aws-actions/aws-codebuild-run-build@v1
with:
project-name: CodeBuildProjectName
@aws-actions/configure-aws-credentialsを使用時のエラー(Incorrect token audience)
自前で書くのは流石に辛いなぁと思っていたところ、AWS公式のクレデンシャル設定Actionsに入っていることを知りました。
ドキュメントによるとrole-to-assume
のパラメタだけ指定すると動作するようです。[4]
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-region: ap-northeast-1
role-to-assume: arn:aws:iam::${{ secrets.ACCOUNT_ID }}:role/${{ secrets.ROLE_NAME }}
role-session-name: MySessionName
これで記述が楽になったと思いきや、実行すると以下のようなエラーが出ました。
An error occurred (InvalidIdentityToken) when calling the AssumeRoleWithWebIdentity operation: Incorrect token audience
Audience(ClientID)について
Actionsのサンプルに書いてあるのですが、AWS側のOIDC Providerの設定において、許可するClientIdにsts.amazonaws.com
を指定する必要があります。
しかし、最初の例だとhttps://github.com/${GitHubOrg名}
というClientIdを許可しないと動作しなかったので、気になって調査しました。
調査したところ、OIDCについて詳しくないのですが、少なくともGitHub OIDCにおいては、任意のaudフィールドを持つトークンを発行することが可能なようです。
以下のようにURLのクエリパラメタとして、audienceを指定することで実現できます。
curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=hogehoge"
AWSの公式Actions上ではここのコードで設定されています。
最終的に呼び出されるコードは上記で説明したようなaudience
クエリを使ったトークン取得が行われています。
本記事の最初の例のように指定しなかった場合、https://github.com/${GitHubOrg名}
が入ってくるようです。
本設定を行うことで、GitHub OIDCを使って、AWS公式のActionsの利用が可能となりました。
セキュリティの話
上記で書いたように、GitHub OIDCのaudフィールドが任意のものを発行可能です。
そのため、Assume対象のRoleの条件に気をつけなければなりません。
ClientIDとして、sts.amazonaws.com
を許可するIDプロバイダを作成し、そのIDプロバイダを無条件に信頼している場合、AWSアカウントIDとIAMロール名のみで、そのロールへのAssumeRoleが可能となってしまいます。
StringLike token.actions.githubusercontent.com:sub repo:${GitHubOrg名}/${リポジトリ名}:*
のような条件を追加し、必ず実行を許可するリポジトリを制限しましょう。[5]
またクレデンシャル情報の扱いについて、AWS公式Actionsでは、Cleanup処理で環境変数の消去を行なってくれています。
こういったものは忘れがちですので、できるだけ自分では書かずに利用するようにしましょう。
リポジトリ
本記事で扱ったAWSの設定を行うTerraformファイルとGitHub Acionsの例(AWS公式アクションを使う or 自分で設定)は以下のリポジトリにあります。
参考
-
特に大きいのはIAM Userが不要になることですね ↩︎
-
一番早くアナウンスしていたhttps://awsteele.com/blog/2021/09/15/aws-federation-comes-to-github-actions.htmlより引用(ARNの箇所は改変) ↩︎
-
自分はaws-codebuild-run-buildを利用 ↩︎
-
結構無理矢理感ある実装ですがv2で解消されそうですhttps://github.com/aws-actions/configure-aws-credentials/blob/8eba69932f928f2bc1b9837d16a095e7e1cb0845/index.js#L263-L269 ↩︎
-
mainブランチのみの制限などは今回の話では扱いません ↩︎
Discussion