principal に IAM ロールを指定するとき～検証：ロールの連鎖（Role chaining）

principal に IAM ロールを指定したことはありますか？ 
あまりないような気もしますが、ドキュメントに気になる内容を発見したので書いてみます。

## principal に IAM ロールを指定するとは
IAM ポリシーは以下のように、
**Principal が Resource に対して Action することを Condition の条件のもと Effect する**
という構成になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/0b5eddef-8b42-e4c0-5d2e-cb82f7a31935.png)

例1）
**Lambda （Principal）が S3（Resource）に対して s3:GetObject（Action）することを Allow（Effect）する**
という IAM ポリシーを書くことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/b165709c-ef9d-d9ff-fc3d-96b80f5dffc1.png)

例2）
**IAM ユーザー（Principal）が IAM ロール（Resource）に対して sts:AssumeRole（Action）することを Allow（Effect）する**
という IAM ポリシーを書くことができます。
IAM ロールに設定する信頼ポリシーでよくあるパターンです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/a6fd596e-9f64-ebee-8a54-fe0b1689f29c.png)

つまり、principal に IAM ロールを指定するとは、
**IAM ロール（Principal）が Resource に対して Action することを Effect する**
という内容のポリシーを設定することと言えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/7c487f2c-c5f9-0714-8e56-a4f99ab2a30f.png)

## で今回発見したこと
以下ドキュメントの「重要」という赤の網掛け部分です。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements_principal.html#principal-roles

>ロール信頼ポリシーの Principal 要素に、特定の IAM ロールを指し示す ARN が含まれている場合、その ARN はポリシーを保存するときにロールの一意のプリンシパル ID に変換されます。これにより、ロールを削除して再作成することにより、誰かがそのユーザーの特権をエスカレートするリスクを緩和できます。
通常、この ID はコンソールには表示されません。これは、信頼ポリシーが表示されるときに、IAM が ロール ARN への逆変換を行うためです。
ただし、ロールを削除すると、関係が壊れます。
ロールを再作成した場合でも、ポリシーは適用されません。これは、新しいロールは信頼ポリシーに保存されている ID と一致しない新しいプリンシパル ID を持っているためです。
この場合、プリンシパル ID はリソースベースポリシーに表示されます。これは AWS が有効な ARN に戻って ID をマッピングできなくなるためです。その結果、信頼ポリシーの Principal 要素で参照されているロールを削除して再作成する場合は、ロールを編集して正しくなくなったプリンシパル ID を正しい ARN に置き換える必要があります。ポリシーを保存するときに、ARN は再びロールの新しいプリンシパル ID に変換されます。

なんだか難しい感じがしますが、
「principal に IAM ロールを指定して、その IAM ロールを削除してから同じロール名で別の IAM ロールを作成しても、同じようにアクセスすることはできません」
ということのようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/eb3ab665-d7bd-faab-506c-c99fbd1d2263.png)

# 動作確認してみたい
## 検証
[ロールの連鎖（Role chaining）](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#iam-term-role-chaining) で検証してみます。
IAM ユーザー「principal-test-user」から、IAM ロール「principal-test-role」にスイッチロールし、さらに IAM ロール「s3-access-role」にスイッチロールして S3 バケット「20221220-emiki-s3bucket」にアクセスできるか確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/240a6bf7-c33a-5c41-3225-c584c7ee7974.png)

ここでキモになるのが、IAM ロール「s3-access-role」の信頼ポリシーの Principal に IAM ロール「principal-test-role」を指定するところです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/61252e83-ab59-ad5f-2bd6-073af3ef0f90.png)

IAM ロール「principal-test-role」を削除し、全く同じポリシーで全く同じロール名のロールを再作成した場合、S3 バケット「20221220-emiki-s3bucket」にアクセスできるのか試します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/e6176e74-399b-9a87-2a79-aed2020da449.png)


### 1. IAM ユーザー「principal-test-user」を作成する
IAM ユーザー「principal-test-user」を作成します。
IAM コンソールからサクッと作成します。

- パスワード - AWS マネジメントコンソールへのアクセス

アクセス許可の設定はしません。
AWS マネジメントコンソールへのアクセスをするために、パスワードだけ設定します。


### 2. IAM ロール「principal-test-role」を作成する
IAM ロール「principal-test-role」を作成します。
IAM コンソールからサクッと作成します。

- ステップ 1 信頼されたエンティティを選択
   - 信頼されたエンティティタイプ：AWS アカウント
   - AWS アカウント：このアカウント

- ステップ 2 許可を追加
   - AWSCloudShellFullAccess

- ステップ 3 名前、確認、および作成
   - ロール名：principal-test-role
   - 説明：principal-test-role before
   - タグを追加
      - key：Environment
      - Value：before

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/776e02de-daf3-1383-8a85-1fadecd5fd09.png)

作成した IAM ロール「principal-test-role」の信頼ポリシーを少し編集します。
AWS アカウントに所属する IAM ユーザーすべてが principal になっているので、先ほど作成した IAM ユーザー「principal-test-user」を principal に設定します。

```json:principal-test-role 信頼ポリシー編集前
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:root"
            },
            "Action": "sts:AssumeRole",
            "Condition": {}
        }
    ]
}
```
↓
```json:principal-test-role 信頼ポリシー編集後
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:user/principal-test-user"
            },
            "Action": "sts:AssumeRole",
            "Condition": {}
        }
    ]
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/08fc77f7-4bb4-3052-742e-8333688178b7.png)

### 3. IAM ロール「s3-access-role」を作成する
S3 へのアクセス権限を持つ IAM ロール「s3-access-role」を作成します。
IAM コンソールからサクッと作成します。

- ステップ 1 信頼されたエンティティを選択
   - 信頼されたエンティティタイプ：AWS アカウント
   - AWS アカウント：このアカウント

- ステップ 2 許可を追加
   - AmazonS3FullAccess

- ステップ 3 名前、確認、および作成
   - ロール名：s3-access-role
   - 説明：s3-access-role

作成した IAM ロール「s3-access-role」の信頼ポリシーを少し編集します。
AWS アカウントに所属する IAM ユーザーすべてが principal になっているので、先ほど作成した IAM ロール「principal-test-role」を principal に設定します。

```json:s3-access-role 信頼ポリシー編集前
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:root"
            },
            "Action": "sts:AssumeRole",
            "Condition": {}
        }
    ]
}
```
↓
```json:s3-access-role 信頼ポリシー編集後
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:role/principal-test-role"
            },
            "Action": "sts:AssumeRole",
            "Condition": {}
        }
    ]
}
```

### 4. S3 バケットにアクセスする
「principal-test-user」で「principal-test-role」にスイッチロールし、CloudShell で「s3-access-role」にスイッチします。
二重にスイッチ後、S3 バケットにアクセスできるか確認します。

#### 4-1. スイッチロール 1 回目
「principal-test-user」で AWS マネジメントコンソールにログインします。
続いて「principal-test-role」にスイッチロールします。
スイッチロール後の「principal-test-role」で CloudShell を開きます。
この段階で `aws sts get-caller-identity` すると、現在の権限が「principal-test-role」であることが分かります。

```
[cloudshell-user@ip-10-6-47-215 ~]$ aws sts get-caller-identity
{
    "UserId": "AROA4LMX2UGT7Q4RLBOOI:principal-test-user",
    "Account": "123456789012",
    "Arn": "arn:aws:sts::123456789012:assumed-role/principal-test-role/principal-test-user"
}
[cloudshell-user@ip-10-6-47-215 ~]$
```
#### 4-2. スイッチロール 2 回目
この後スイッチロールする「s3-access-role」のプロファイルを設定します。
まず CloudShell で「~/.aws」ディレクトリを作成します。
（デフォルトでは存在しないようです）

```
[cloudshell-user@ip-10-6-47-215 ~]$ mkdir ~/.aws
[cloudshell-user@ip-10-6-47-215 ~]$ ls -la
total 37
drwxr-xr-x 5 cloudshell-user cloudshell-user 4096 Jan  9 06:53 .
drwxr-xr-x 3 root            root            1024 Jan  9 06:24 ..
drwxrwxr-x 2 cloudshell-user cloudshell-user 4096 Jan  9 06:53 .aws
-rw------- 1 cloudshell-user cloudshell-user  118 Dec 22 13:56 .bash_history
-rw-r--r-- 1 cloudshell-user cloudshell-user   18 Dec 22 13:28 .bash_logout
-rw-r--r-- 1 cloudshell-user cloudshell-user  193 Dec 22 13:28 .bash_profile
-rw-r--r-- 1 cloudshell-user cloudshell-user  314 Dec 22 13:28 .bashrc
drwxr-xr-x 3 cloudshell-user cloudshell-user 4096 Dec 22 13:28 .config
drwxr-xr-x 3 cloudshell-user cloudshell-user 4096 Jan  9 06:25 .local
-rw-r--r-- 1 cloudshell-user cloudshell-user  777 Dec 22 13:28 .zshrc
[cloudshell-user@ip-10-6-47-215 ~]$
```
「credentials」ファイルを作成します。
vim で「credentials」ファイルを開きます。
```
[cloudshell-user@ip-10-6-47-215 ~]$ vim ~/.aws/credentials
```

「i」を押下して編集モードに移行し、以下のように設定します。
```
[s3-access-role]
role_arn = arn:aws:iam::123456789012:role/s3-access-role
credential_source = EcsContainer
```
「esc」を押下して編集モードから抜け、「:wq」で保存します。

この段階で `aws sts get-caller-identity --profile s3-access-role` すると、現在の権限が「s3-access-role」であることが分かります。
```
[cloudshell-user@ip-10-6-47-215 ~]$ aws sts get-caller-identity --profile s3-access-role
{
    "UserId": "AROA4LMX2UGTS5YWJ3QKR:botocore-session-1673247507",
    "Account": "123456789012",
    "Arn": "arn:aws:sts::123456789012:assumed-role/s3-access-role/botocore-session-1673247507"
}
[cloudshell-user@ip-10-6-47-215 ~]$
```

#### 4-3. S3 バケット内のオブジェクト表示
[バケットとオブジェクトの一覧表示](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-listing-buckets) を参考に、S3 バケット内のオブジェクトを表示します。

```
[cloudshell-user@ip-10-6-47-215 ~]$ aws s3 ls s3://20221220-emiki-s3bucket --profile s3-access-role
2022-12-20 14:02:16          0 test - コピー (2).txt
2022-12-20 14:02:16          0 test - コピー (3).txt
2022-12-20 14:02:16          0 test - コピー (4).txt
2022-12-20 14:02:16          0 test - コピー.txt
2022-12-20 14:02:16          0 test.txt
[cloudshell-user@ip-10-6-47-215 ~]$ 
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/e2876904-fc05-7d84-69d3-b5e451aefefd.png)

表示できました。
ここで、CloudShell を閉じ、「principal-test-user」にスイッチバックします。

### 5. 「principal-test-role」を削除する
「principal-test-role」を削除します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/e3f96590-02e4-96cc-6625-1f80c3d4c912.png)

### 6. 再度同じ名前と権限で「principal-test-role」を作成する
再度同じ名前と権限で「principal-test-role」を作成します。
IAM コンソールからサクッと作成します。

- ステップ 1 信頼されたエンティティを選択
   - 信頼されたエンティティタイプ：AWS アカウント
   - AWS アカウント：このアカウント

- ステップ 2 許可を追加
   - AWSCloudShellFullAccess

- ステップ 3 名前、確認、および作成
   - ロール名：principal-test-role
   - 説明：principal-test-role after
   - タグを追加
      - key：Environment
      - Value：after

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/1c79d31e-21ca-9e57-669a-e9580f79b9b2.png)

作成した IAM ロール「principal-test-role」の信頼ポリシーを編集します。
AWS アカウントに所属する IAM ユーザーすべてが principal になっているので、既存の IAM ユーザー「principal-test-user」を principal に設定します。

```json:principal-test-role 信頼ポリシー編集前
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:root"
            },
            "Action": "sts:AssumeRole",
            "Condition": {}
        }
    ]
}
```
↓
```json:principal-test-role 信頼ポリシー編集後
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:user/principal-test-user"
            },
            "Action": "sts:AssumeRole",
            "Condition": {}
        }
    ]
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/a5daa811-853f-b63a-3538-d743e1773c35.png)

### 7. S3 バケットにアクセスする
「principal-test-user」で「principal-test-role」にスイッチロールし、CloudShell で「s3-access-role」にスイッチします。
二重にスイッチ後、S3 バケットにアクセスできるか確認します。

#### 7-1. スイッチロール 1 回目
「principal-test-user」で AWS マネジメントコンソールにログインします。
続いて「principal-test-role」にスイッチロールします。
スイッチロール後の「principal-test-role」で CloudShell を開きます。
この段階で aws sts get-caller-identity すると、現在の権限が「principal-test-role」であることが分かります。
```
[cloudshell-user@ip-10-6-20-151 ~]$ aws sts get-caller-identity
{
    "UserId": "AROA4LMX2UGTZFOGO2J5M:principal-test-user",
    "Account": "123456789012",
    "Arn": "arn:aws:sts::123456789012:assumed-role/principal-test-role/principal-test-user"
}
[cloudshell-user@ip-10-6-20-151 ~]$
```

#### 7-2. スイッチロール 2 回目
この後スイッチロールする「s3-access-role」のプロファイルを設定します。
まず CloudShell で「~/.aws」ディレクトリを作成します。

```
[cloudshell-user@ip-10-6-20-151 ~]$ mkdir ~/.aws
[cloudshell-user@ip-10-6-20-151 ~]$ ls -la
total 32
drwxr-xr-x 4 cloudshell-user cloudshell-user 4096 Jan  9 07:16 .
drwxr-xr-x 4 root            root            4096 Jan  9 07:06 ..
drwxrwxr-x 2 cloudshell-user cloudshell-user 4096 Jan  9 07:16 .aws
-rw-r--r-- 1 cloudshell-user cloudshell-user   18 Jan  9 07:06 .bash_logout
-rw-r--r-- 1 cloudshell-user cloudshell-user  193 Jan  9 07:06 .bash_profile
-rw-r--r-- 1 cloudshell-user cloudshell-user  314 Jan  9 07:06 .bashrc
drwxr-xr-x 3 cloudshell-user cloudshell-user 4096 Jan  9 07:06 .config
-rw-r--r-- 1 cloudshell-user cloudshell-user  777 Jan  9 07:06 .zshrc
[cloudshell-user@ip-10-6-20-151 ~]$ 
```
「credentials」ファイルを作成します。
vim で「credentials」ファイルを開きます。
```
[cloudshell-user@ip-10-6-20-151 ~]$ vim ~/.aws/credentials
```
「i」を押下して編集モードに移行し、以下のように設定します。
```
[s3-access-role]
role_arn = arn:aws:iam::123456789012:role/s3-access-role
credential_source = EcsContainer
```
「esc」を押下して編集モードから抜け、「:wq」で保存します。

この段階で `aws sts get-caller-identity --profile s3-access-role` すると、アクセスが拒否されます。

```
[cloudshell-user@ip-10-6-20-151 ~]$ aws sts get-caller-identity --profile s3-access-role

An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:sts::123456789012:assumed-role/principal-test-role/principal-test-user is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::123456789012:role/s3-access-role
[cloudshell-user@ip-10-6-20-151 ~]$
```

#### 7-3. S3 バケット内のオブジェクト表示
S3 バケット内のオブジェクト一覧も表示できません。
```
[cloudshell-user@ip-10-6-20-151 ~]$ aws s3 ls s3://20221220-emiki-s3bucket --profile s3-access-role

An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:sts::123456789012:assumed-role/principal-test-role/principal-test-user is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::12345689012:role/s3-access-role
[cloudshell-user@ip-10-6-20-151 ~]$ 
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/f0dcb639-efe9-cde5-25db-a1bf7bd5ba8e.png)

## 参考
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements_principal.html#principal-roles

https://dev.classmethod.jp/articles/role-chaining/

https://dev.classmethod.jp/articles/aws-cloudshell-cross-account-switch-role/

https://qiita.com/willco21/items/7a65233c2bb8246840a7