GitHub Actions で AWS Federation を試す
これの記事を自分でも試してみる。
試してわかったこと
- ワークフローファイルに
permissions.id-token
を入れる必要がある(公式ドキュメントには書かれていない) - 環境変数
ACTIONS_ID_TOKEN_REQUEST_URL
の値を使ってACTIONS_ID_TOKEN_REQUEST_TOKEN
のURLにアクセスするとid_token
が取得できる - IAM ロールにGitHub OIDC プロバイダーの情報を設定しておくと
id_token
でAWSアクセスキーが取得できる-
AssumeRoleWithWebIdentity
という API を使う
-
とりあえず仮説を立てる
ポイント
おそらく GitHub Actions の実行ごとに id_token (OIDCトークン) が発行されていて、環境変数 ACTIONS_ID_TOKEN_REQUEST_TOKEN に設定されているのかな。
これはドキュメントにも書かれていなさそう。
GitHub Actions に限った話ではなく、AWS IAM には OpenID Connect (OIDC) でのフェデレーションに対応しているので、その設定をすれば OIDC を使っての一時的な認証情報を使える、ということのよう。
シンプルな環境変数を確認するだけのワークフローを作ってみる
name: "test_github_oidc"
on:
push:
branches:
- "test-github-oidc"
jobs:
test_github_oidc:
runs-on: ubuntu-latest
steps:
- name: Show env
run: env
あれ ACTIONS_ID_TOKEN_REQUEST_TOKEN
はないのか・・・。
あ、このあたりが必要っぽいな。
permissions:
id-token: write
contents: read
steps:
- run: sleep 5 # there's still a race condition for now
出た!
- run: sleep 5
の部分は消してもちゃんと環境変数に入っているな・・・。
大事なのはこの部分。
permissions:
id-token: write
contents: read
当然というか id-token
はまだ定義されていない。
curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL"
の戻り値はこんな感じだった。
(value
は念のためマスク済み)
{
"count": 1390,
"value": "eyJ0e...AB3w"
}
パースするとこんな感じのペイロードが入ってた。
(※一部マスク済み)
$ jwt decode 'eyJ0e...AB3w'
Token header
------------
{
"typ": "JWT",
"alg": "RS256",
"kid": "DA6DD449E0E809599CECDFB3BDB6A2D7D0C2503A",
"x5t": "2m3USeDoCVmc7N-zvbai19DCUDo"
}
Token claims
------------
{
"actor": "mryhryki",
"aud": "https://github.com/mryhryki/*****",
"base_ref": "",
"event_name": "push",
"exp": 1631927673,
"head_ref": "",
"iat": 1631927373,
"iss": "https://vstoken.actions.githubusercontent.com",
"job_workflow_ref": "mryhryki/*****/.github/workflows/test_github_oidc.yml@refs/heads/test-github-oidc",
"jti": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"nbf": 0000000000,
"ref": "refs/heads/test-github-oidc",
"ref_type": "branch",
"repository": "mryhryki/*****",
"repository_owner": "mryhryki",
"run_attempt": "1",
"run_id": "1247514736",
"run_number": "14",
"sha": "bf66eb2650f774efd4361fcb6848b3b6e1723f5b",
"sub": "repo:mryhryki/*****:ref:refs/heads/test-github-oidc",
"workflow": "test_github_oidc"
}
この記事と同じ感じなので間違ってなさそう。
AWS Console で設定してみる。
- テスト用の IAM Role を作成
- フェデレーションの設定
プロバイダの URL: https://vstoken.actions.githubusercontent.com
対象者: https://github.com/(REPO_NAME)
実験したい権限なら何でもよいが、今回は list-bucket
でもやってみようかと思うので AmazonS3ReadOnlyAccess
を選択してみる。
特にタグはいらない。
適当な名前をつけて IAM Role を作成。
IAM Role の確認。
定義で比較しても同じっぽいので多分大丈夫そう。
自分のもの
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::000000000000:oidc-provider/vstoken.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"vstoken.actions.githubusercontent.com:aud": "https://github.com/mryhryki/****"
}
}
}
]
}
参考記事内のやつ
id_token
から(一時的な)AWSアクセスキーを取得する。
記事内では仕組みで自動的に取ってこれる感じっぽく見えたけど、せっかくなので自分でやってみる。
探してみたら AssumeRoleWithWebIdentity
という API があった!
CLI 的にはこれでヘルプが見れる。
$ aws sts assume-role-with-web-identity help
成功 🎉
aws sts assume-role-with-web-identity \
--role-arn 'arn:aws:iam::000000000000:role/GitHub_OIDC_test' \
--role-session-name `uuidgen` \
--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:BA0A48EA-8090-4506-8464-BD2A3FFDD5C7",
"Arn": "arn:aws:sts::000000000000:assumed-role/GitHub_OIDC_test/BA0A48EA-8090-4506-8464-BD2A3FFDD5C7"
},
"Provider": "arn:aws:iam::000000000000:oidc-provider/vstoken.actions.githubusercontent.com",
"Audience": "https://github.com/mryhryki/*****"
}
最終的にはこんなワークフローで試した。
name: "test_github_oidc"
on:
push:
branches:
- "test-github-oidc"
jobs:
test_github_oidc:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Show env
run: env | grep 'ACTIONS_ID_TOKEN' | sort
- name: Request and export AWS Access Key
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
目的としたいことは試せたので終わり。
余裕があれば記事にまとめようかな。
記事として投稿した。