Closed34

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 に設定されているのかな。

これはドキュメントにも書かれていなさそう。

https://docs.github.com/en/actions/reference/environment-variables

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

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 を作成。

定義で比較しても同じっぽいので多分大丈夫そう。

自分のもの

{
  "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/****"
        }
      }
    }
  ]
}

参考記事内のやつ

https://awsteele.com/blog/2021/09/15/aws-federation-comes-to-github-actions.html

id_token から(一時的な)AWSアクセスキーを取得する。

記事内では仕組みで自動的に取ってこれる感じっぽく見えたけど、せっかくなので自分でやってみる。

成功 🎉

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

目的としたいことは試せたので終わり。
余裕があれば記事にまとめようかな。

このスクラップは2021/09/25にクローズされました
ログインするとコメントできます