めも: assume role with web identity

このへんの記事を読みながらつくっていたら色々迷ったのでめも

やらかし1: Identity Provider を作っていなかった

IAM 管理画面で、ウェブアイデンティティ用の IAM Role を作っていたけど、プロバイダを特定の Cognito User Pool x App Client ではなく "Amazon Cognito" にしてた

これでやるとふつうに assume role したときに 403 になった

正しくはこう (ハンズオン資料から)

やらかし2: id token の形式が違う

c.f. https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/sts/command/AssumeRoleWithWebIdentityCommand/

AssumeRoleWithWebIdentityCommand はこういう風にコマンドを叩いているんだけど、ポイントとなるのは

  • WebIdentityToken は JWT 形式 (i.e. type string)
  • RoleSessionName は JWT から取り出した username

を入れる必要があること。

ソース: ハンズオンのここにあった Lambda の Zip を落としてそのコードを読んだ

import { STSClient, AssumeRoleWithWebIdentityCommand } from '@aws-sdk/client-sts'

const REGION = 'ap-northeast-1'
const stsClient = new STSClient({ region: REGION })

const username = jwtDecode(event['queryStringParameters']?.openIdToken)['cognito:username']
const command = new AssumeRoleWithWebIdentityCommand({
    RoleArn: "YOUR_ROLE_ARN",
    RoleSessionName: username,
    WebIdentityToken: event['queryStringParameters']?.openIdToken,
})
await stsClient.send(command)

やらかしパターン

(1) /oauth2/token のレスポンスをそのまま WebIdentityToken につっこむ

id_token 以外のものも入ってるしそもそも JWT じゃないので NG

このエンドポイントからのレスポンスは https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html にあるように、id_token, access_token, refresh_token がそれぞれ JWT で返ってくる。一方 command に送るのは id_token だけなので、そのまま送ると NG になる

{ 
    "access_token":"eyJra1example", 
    "id_token":"eyJra2example",
    "refresh_token":"eyJj3example",
    "token_type":"Bearer", 
    "expires_in":3600
}

なので、 oauth2/token からのレスポンスのうち id_token プロパティだけを取り出すという作業が必要

const res = await fetch(...) // request to /oauth2/token
const data = await res.json()
const idToken = data.id_token

(2) id token をデコードして送る

これも「JWT 形式じゃないよ」と怒られるので、デコードせずに WebIdentityToken パラメータにつっこむ。