assume role まわりめも

assume role とは: AWS リソースとか IAM ユーザの「プリンシパル」に IAM role を一時的につけること

プリンシパルの一覧はここ ↓ https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_principal.html

assume role をするためには、IAM ロールに「この人たちがこのロールを使っていいですよ」というポリシーを付ける必要がある

たとえば、下のポリシーは「AWS アカウント 1234... が、このロールに対して assume role というアクションをすることを許可しますよ」というポリシー。assume role のプリンシパルAWS アカウント以外ももちろん指定できる。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "AWS": [ "123456789012" ] // ← AWSアカウントを信頼
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

下記より引用

今回は cognito に登録したユーザが IAM role を assume-role できるようにしたかったので、↓を参考にしながら進めた

下準備として、

  • Cognito で User Pool をつくって、その中にユーザを登録する
  • Cognito で Identity Pool をつくって、「認証されたロール」のところで IAM Role を作る OR 指定する

の2つが必要。IAM Role は「この Identity Pool の人は全員このロール」もできるし、条件に応じてロールを指定することもできる。カスタム属性値を使って指定もできるので結構柔軟にできそう。

各ルールは、トークンクレーム (Amazon Cognito ユーザープールからの ID トークンのユーザー属性など)、一致タイプ、値、および IAM ロールを指定します。一致タイプは、EqualsNotEqualStartsWith、または Contains となります。クレームに一致する値をユーザーが持っている場合、そのユーザーは、認証情報を取得するときにそのロールを引き受けることができます。例えば、custom:dept カスタム属性値が Sales のユーザーに特定の IAM ロールを割り当てるルールを作成できます。

https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/role-based-access-control.html#token-claims-for-role-based-access-control

あとは記事に書いてあるとおりの手順でいけるけど、自分は最初の admin-initiate-auth の部分を initiate-auth に変えた。

REGION=xxx
USER_POOL_ID=xxx
CLIENT_ID=xxx
USER_EMAIL=xxx
PASSWORD=xxx
IDENTITY_POOL_ID=xxx

COGNITO_USER_POOL=cognito-idp.${REGION}.amazonaws.com/${USER_POOL_ID}

echo "initiate auth: get ID token"
ID_TOKEN=$(aws cognito-idp initiate-auth \
  --client-id ${CLIENT_ID} \
  --auth-flow USER_PASSWORD_AUTH \
  --auth-parameters "USERNAME=${USER_EMAIL},PASSWORD=${PASSWORD}" \
  --query "AuthenticationResult.IdToken" \
  --output text) && echo ${ID_TOKEN}

echo ""
echo "get id: get identity id"
IDENTITY_ID=$(aws cognito-identity get-id \
  --identity-pool-id ${IDENTITY_POOL_ID} \
  --logins "${COGNITO_USER_POOL}=${ID_TOKEN}" \
  --query "IdentityId" \
  --output text) && echo ${IDENTITY_ID}

echo ""
echo "get credentails for identity"
OUTPUT=$(aws cognito-identity get-credentials-for-identity \
  --identity-id ${IDENTITY_ID} \
  --logins "${COGNITO_USER_POOL}=${ID_TOKEN}") \
  && echo ${OUTPUT}

# store the credentials in environment variables
export AWS_ACCESS_KEY_ID=$(echo ${OUTPUT} | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo ${OUTPUT} | jq -r '.Credentials.SecretKey')
export AWS_SESSION_TOKEN=$(echo ${OUTPUT} | jq -r '.Credentials.SessionToken')
echo "updated AWS_xx variables"

このスクリプトを実行後に

aws sts get-caller-identity

を実行すると、

{
    "UserId": "xxx:CognitoIdentityCredentials",
    "Account": "xxx",
    "Arn": "arn:aws:sts::xxx:assumed-role/<ROLE_NAME>/CognitoIdentityCredentials"
}

のような出力が得られる。

補足として、 aws sts get-caller-identity をターミナルで実行する場合、ターミナルの AWS_PROFILE などの環境変数を読んで実行される (いちおう --profile オプションもあるけど詳しく試してない)。なので、自分のスクリプトではてっとりばやく AWS_ACCESS_KEY_ID とかを設定してる。

感想

「一時クレデンシャル」がなにかよくわかってなかったけど、つまり AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY の期限付きのペアなのね、というのがわかった

refs