AssumeRole エラー発生の背景と解決方法

## 概要

- 本記事では、AWS の AssumeRole 機能を利用する際に発生した AccessDenied エラーの原因と解決方法について解説します。ターゲットロール（AssumeRoleの対象ロール）の信頼ポリシーで特定の aws:userid を要求している一方、呼び出し元（使用しているロール）に sts:AssumeRole の実行権限が不足していたためにエラーが発生しました。記事では、エラーの背景、原因、そして解決策として2つ備忘のためにもここに書き残しておこうと思います。

## 前提

- 今回の事例では、ターゲットロールは、その信頼ポリシーで「AssumeRole を実行できるユーザー」を厳密に制限しています。
- 具体的には、ターゲットロールは、特定の IAM ロールに属するユーザーのみが AssumeRole できるように設定されています。
- 前提として、今回 AssumeRole を実行できるユーザーは自分が使用しているユーザーのみです。
- つまり、ターゲットロールを引き受けるためには、呼び出し元のユーザーがロール（またはそれに紐づく IAM Identity Center の許可セット）の一員であり、さらにそのユーザーに対して sts:AssumeRole の実行権限が付与されている必要があります。
- この前提に基づき、発生していたエラーは、呼び出し元であるロール側に、ターゲットロールを AssumeRole するための権限が不足していたことが原因でした。

まず、エラーになった際に設定されていた信頼ポリシーは下記の通りでした
```bash
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::xxxxxxxxxxx:root"  
                // ここで指定されたプリンシパルは、アカウントxxxxxxxxxxxの「root」エンティティを意味し、
                // そのアカウント内の全てのIAMエンティティが対象となります。
            },
            "Action": "sts:AssumeRole",
            "Condition": {
                "StringEquals": {
                    "aws:userid": "{UserId}"  
                    // 条件として、呼び出し元のaws:useridが{UserId}と完全一致する必要があることを示します。
                    // これにより、ターゲットロールをAssumeRoleできるユーザーを特定のIDに限定します。
                }
            }
        }
    ]
}
```

## エラー発生の背景

- AssumeRole の呼び出し時、以下のエラーが発生しました。
```bash
AccessDenied when calling the AssumeRole operation: User: arn:{role-arn}/{account-name} is not authorized to perform: sts:AssumeRole on resource: arn:{role-arn}
```

### エラーの原因

- ターゲットロールの信頼ポリシー設定
ターゲットロールでは Principal に arn:aws:iam::xxxxxxxxxxxx:root を指定し、条件として "aws:userid": [{UserId}] を要求しています。

:::note info
自分の UserId の取得方法は、CloudShellから `aws sts get-caller-identity` などを使用すると取得できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531653/afc82ab9-1512-4e58-96d4-d37d3c95b15f.png)
:::

- 呼び出し元の権限不足
結論からすると、AssumeRole を呼び出す側の IAM ロールに sts:AssumeRole の実行権限が付与されていないため、エラーが発生していました。


## 解決策

この場合、結論解決策は2つあります。

### 解決策1
- 呼び出し元ロールに sts:AssumeRole 権限を追加する
今回のように、`arn:aws:iam::xxxxxxxxxxx:root`みたいに Principal を設定してアカウント内の全てのエンティティが使用できる設定だと、利用元のロールが sts:AssumeRole の権限を持っている必要があります。
利用元の ロール側（または IAM Identity Center の許可セット側）に以下のポリシーステートメントを追加します。
    
    ```bash
    {
      "Sid": "AllowAssumeRole",
      "Effect": "Allow",
      "Action": "sts:AssumeRole",
      "Resource": "{AssumeRoleしたいロールのARN}"
    }
    ```

### 解決策2

- 信頼ポリシーの条件設定の見直し
AssumeRole する対象のロールの信頼ポリシーの Principal に利用元のゆの ARN を明示的に指定する。
この設定により、ターゲットロールは指定された利用元ロールからのみ AssumeRole されるように制限され、利用元側での追加の権限付与が不要になります。
    ```bash
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {
                    // ↓ここに明示的に利用元のロールを指定する
                    "AWS": "{利用元のロールのARNを指定する}"
                },
                "Action": "sts:AssumeRole",
                "Condition": {
                    "StringEquals": {
                        "aws:userid": "{UserId}"
                    }
                }
            }
        ]
    }
    ```

どちらの方法も有効ですが、どちらを採用するかは運用ポリシーやセキュリティ要件によルカと思います。
- 利用元ロール側に権限を追加する方法（解決策1）は、既存の信頼ポリシーを変更せずに対応できるため、変更箇所が限定されるメリットがあります。
- 信頼ポリシー側を利用元ロールに絞る方法（解決策2）は、ターゲットロールを AssumeRole できるユーザーをより厳密に管理できる点がメリットです。

どちらの方法を選択するかケースバイケースになると思います。

## まとめ
今回の事例は、特定の運用環境や条件下でのみ発生するエッジケースかもしれませんが、AssumeRole を利用したクロスアカウントや SSO を使ったアクセス管理の際には、ターゲットロールの信頼ポリシーと呼び出し元ロールの権限が密接に関係するため、注意が必要です。
このまとめが、同様の問題に直面する方の参考になれば幸いです。