GitHub Actions のIDトークンを使ってAWSリソースにアクセスする
追記(2021-11-01)
正式にリリースされたようです!🎉🎉🎉
追記(2021-10-13)
Issuer が https://vstoken.actions.githubusercontent.com
から https://token.actions.githubusercontent.com
に変更になったようです。
まだ GitHub から何もアナウンスがされていない機能なのでしょうがないですね。
逆に言えば、リリースに向けて動いているからなのかもしれないですね。
はじめに
このツイートを見て、どういう風に認証を通しているのかが気になったので、実際に試してみた結果のメモをまとめた記事になります。
何をやっているのか理解したいので、そのまま試すのではなく、1つずつ順番に紐解いてやっています。
なお、調査の過程はこちらのスクラップに書いています。
調査した内容の概要
- GitHub Actions の環境変数の情報からIDトークンを取得する
- IDトークンからAWSの一時的な認証情報を取得できる設定をする
- 一時的な認証情報を取得しAWSリソースにアクセスする
GitHub Actions の環境変数の情報からIDトークンを取得する
まずは GitHub Actions 上でIDトークンを取得する方法を順番に試しました。
テスト用のワークフローファイル(YAML)
GitHub Actions 上にある環境変数を表示するために、以下の最小限のワークフローファイルを作成しました。
name: "test_github_oidc"
on:
push:
branches:
- "test-github-oidc"
jobs:
test_github_oidc:
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
- name: Show env
run: env | grep 'ACTIONS_ID_TOKEN'
ポイントは permissions.id-token: write
の部分です。
これを指定することでIDトークンの取得に必要な情報を環境変数に設定してもらえます。
この id-token
という項目は、現時点では公式ドキュメントに書かれていません。
これが公式にアナウンスされれば実用的に使えるようになる、というのが現状かと思います。
GitHub Actions での実行結果
実行すると以下の2つの環境変数が出力されます。
-
ACTIONS_ID_TOKEN_REQUEST_TOKEN
: IDトークンを取得するためのトークン -
ACTIONS_ID_TOKEN_REQUEST_URL
: IDトークンを取得するためのリクエストURL
2段構えになっているのは、全部の実行でIDトークンが必要になるわけではないので、無駄に発行しないためとかかなと想像しています。
(私は当初IDトークンそのものが環境変数に入っていると思っていたので、ちょっとハマりました)
IDトークンの取得
GitHub Actions 内で以下のように curl
コマンドを実行するとIDトークンが取得できます。
$ curl --silent -H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" "${ACTIONS_ID_TOKEN_REQUEST_URL}"
{
"count": 1390,
"value": "eyJ0e...AB3w"
}
value
がIDトークンになります。(値はマスクしています)
IDトークンからAWSの一時的な認証情報を取得できる設定をする
IDトークンさえ取得できてしまえば、既存のAWSの機能を使ってAWSの一時的な認証情報を取得できます。
具体的な作業としては OpenID Connect のプロバイダを設定し、IAMロールを作成します。
AWSコンソールで設定したので、キャプチャをベースで簡単に説明します。
1. 新しいプロバイダの設定
- プロバイダの URL:
https://vstoken.actions.githubusercontent.com
-
https://token.actions.githubusercontent.com
に変わりました(2021-10-13 追記)
-
- 対象者:
https://github.com/(OWNER)/(REPO_NAME)
これは「GitHub から対象のリポジトリに向けたIDトークンを信頼する」といった意味合いになります。
他のリポジトリ向けに発行されたIDトークンでは使うことができないので安心ですね。
2. ロールの作成
プロバイダの情報が選べるようになっているので、以下のように選択します。
3. 権限の設定
それぞれの要件に応じた最小限の権限を設定します。
今回は list-bucket でもやってみようかと思うので AmazonS3ReadOnlyAccess を選択してみました。
4. 作成
補足
こちらの記事の CloudFormation の定義の以下の部分に当たる作業です。
これで、GitHub から発行されたIDトークンを使って、AWSにアクセスするための設定ができました。
一時的な認証情報を取得しAWSリソースにアクセスする
あとは実際にアクセスする処理を書いていきます。
一時的な認証情報を取得する方法
調べてみたところ AssumeRoleWithWebIdentity
というAPIでIDトークンからAWSの一時的な認証情報を取得できるようです。
AWS CLI のヘルプはこちらです。
あるいは CLI のヘルプでも見られます。
$ aws sts assume-role-with-web-identity help
(ちなみに STS のヘルプを見ている時に見つけました)
$ aws sts help
AWS CLI でAWSの一時的な認証情報を取得する
CLI を使って取得する場合は以下のようなコマンドで取得できます。
(※一部マスクしてます)
$ aws sts assume-role-with-web-identity \
--role-arn 'arn:aws:iam::000000000000:role/GitHub_OIDC_test' \
--role-session-name 'SESSION_NAME' \
--web-identity-token 'eyJ0...ds5BA'
{
"Credentials": {
"AccessKeyId": "AS...FP",
"SecretAccessKey": "Td...xD",
"SessionToken": "IQ...PA",
"Expiration": "2021-09-18T03:03:56Z"
},
"SubjectFromWebIdentityToken": "repo:mryhryki/*****:ref:refs/heads/test-github-oidc",
"AssumedRoleUser": {
"AssumedRoleId": "ARXXXXXXXXXXXXXXXXXTS:SESSION_NAME",
"Arn": "arn:aws:sts::000000000000:assumed-role/GitHub_OIDC_test/SESSION_NAME"
},
"Provider": "arn:aws:iam::000000000000:oidc-provider/vstoken.actions.githubusercontent.com",
"Audience": "https://github.com/mryhryki/*****"
}
-
--role-arn
は先程作ったIAMロールのARNを指定します。 -
--web-identity-token
はIDトークンを指定します。 -
--role-session-name
はセッションを識別できる情報を入れます。(分かれば何でも良さそう)
GitHub Actions 上で実行する
最終的にこのようなワークフローを作って実行してみました。
(ほとんどシェルスクリプト・・・)
name: "test_github_oidc"
on:
push:
branches:
- "test-github-oidc"
jobs:
test_github_oidc:
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
- run: |
export AWS_DEFAULT_REGION="ap-northeast-1"
ID_TOKEN="$(curl --silent -H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" "${ACTIONS_ID_TOKEN_REQUEST_URL}" | jq -r '.value')"
ACCESS_KEY_JSON="$(aws sts assume-role-with-web-identity --role-arn "arn:aws:iam::000000000000:role/GitHub_OIDC_test" --role-session-name "${GITHUB_RUN_ID}" --web-identity-token "${ID_TOKEN}" --output json)"
export AWS_ACCESS_KEY_ID="$(echo "${ACCESS_KEY_JSON}" | jq -r '.Credentials.AccessKeyId')"
export AWS_SECRET_ACCESS_KEY="$(echo "${ACCESS_KEY_JSON}" | jq -r '.Credentials.SecretAccessKey')"
export AWS_SESSION_TOKEN="$(echo "${ACCESS_KEY_JSON}" | jq -r '.Credentials.SessionToken')"
aws s3 ls
実行すると、無事S3バケットの一覧が取得できました!🎉
補足
こちらの記事では $AWS_WEB_IDENTITY_TOKEN_FILE
のパスにIDトークンを入れているので何やってるんだろうと思ったんですが、IDトークンを入れたファイルのパスを $AWS_WEB_IDENTITY_TOKEN_FILE
(と AWS_ROLE_ARN
)に指定しておくと自動的に取得してくれる仕組みがCLIあるんですね。
全然知らなかった・・・。
It works because the AWS SDKs (and AWS CLI) support using the AWS_WEB_IDENTITY_TOKEN_FILE and AWS_ROLE_ARN environment variables since AWS EKS needed this.
EKSもこの機能を使っているのかぁ。
ドキュメントも見つけました。
まとめ
GitHub Actions からセキュアにAWSにアクセスできる、本当に嬉しい機能で、早く公式にアナウンスされないかな〜、という気持ちになりました。
GitHub が発行したIDトークンで、AWSの一時的な認証情報を取得できるというシンプルさも好印象です。
参考リンク
-
AWS federation comes to GitHub Actions | Aidan Steele’s blog (usually about AWS)
- 最初に見つけた方の記事のようです。(Tweet)
- GitHub ActionsでAWSの永続的なクレデンシャルを渡すことなくIAM Roleが利用できるようになったようです | DevelopersIO
- takanabe/github-actions-oidc-test
-
GitHub ActionsのOIDC id tokenでGCPにアクセスしてみた - ryotarai's blog
- AWS 専用とかではないので、同様なことは GCP でもできるようですね。(GCP はほとんど知らないので詳しくはわかりません)
Discussion