インスタンスプロファイルを理解するついでにポリシーとロールを整理する。

# はじめに
EC2インスタンスにCLIからインスタンスプロファイルを割り当てる作業を行った際、ちゃんと理解できてないなぁと感じたので、覚えがてら**インスタンスプロファイル**と**IAMポリシー**、**IAMロール**の関係について整理します。

# IAMポリシーとは
**AWSのリソースにアクセスする際の制御を行う機能**です。

IAMポリシーにはAWSが事前に用意している**AWS管理ポリシー**とユーザがカスタマイズして使う**カスタマー管理ポリシー**があります。

**AWS管理ポリシー**は`AmazonS3ReadOnlyAccess`や`AmazonEC2FullAccess`などの名前が付けられているため、利用するサービスへのアクセスに必要なポリシーを選んで各ユーザ、グループなどに割り当てることで各リソースへのアクセスを制限できます。

但し、**AWS管理ポリシー**を使う場合、ポリシーの編集はできないため、もし複数サービスへのアクセス許可を定義したポリシーを作成したかったり、サービスへのアクセス制御以外にIPアドレスでもアクセス制限したかったりする場合は**カスタマー管理ポリシー**を作成して、使いたい**AWS管理ポリシー**を選ぶことでユーザ独自のポリシーを作成することができます。

![policy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/bee3479a-1fb0-445b-a3fe-0c79220c25c3.png)

# IAMロールとは
EC2インスタンスやLambdaなどからAWSの各種サービスを利用したい場合に、**AWSサービスの操作権限を与える機能**です。

ユーザがAWS CLIやAWSコンソールからAWSのサービス、リソースを操作する場合、**アクセスキー**、**シークレットアクセスキー**を使ってアクセスを行いますが、**IAMポリシー**を**IAMロール**にアタッチして、さらにアタッチした**IAMロール**をEC2インスタンス等に紐付けることで**アクセスキー**、**シークレットアクセスキー**を設定しなくても、**IAMポリシー**で許可されているサービス、リソースを操作できます。

EC2インスタンスであれば、ユーザのアクセスキーを`aws configure`コマンドで登録してあげれば、ユーザに紐付けられているポリシーで`AWS CLIでアクセスすることもできますが、アクセスキーを登録する必要が無い分セキュリティ的に安全で、**アクセスキーの登録ができないLambdaやECSのコンテナ上からも利用できる**のがメリットです。

![role.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/fae440a8-f881-63da-ccca-b4de78d7c7d9.png)

# インスタンスプロファイルとは
**EC2インスタンス**と**IAMロール**を結びつけるための箱です。

AWSコンソールから操作した場合にはインスタンスプロファイルなんて用語が出てきませんが、AWSコンソールからEC2インスタンスにIAMロールをアタッチするときにプルダウンで選択する名前が`InstanceProfile`です。

![capture_19122020_173411.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/e9356c34-4ace-0371-97e6-b47ecc3d4d5d.jpeg)

内部的には、**IAMロール**はEC2インスタンスに直接結びつけることができず、`InstanceProfile`経由で**IAMロール**を結びつけることでEC2インスタンスでIAMロールを使用できるようにしています。

![InstanceProfile.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/33699386-8f3f-952e-1007-4fd54457c8c2.png)

ただ、AWSコンソールから操作した場合はIAMロールを選択することで、内部的に勝手に**IAMロールと同じ名前でインスタンスプロファイルが作られて、IAMロールと結び付けられる**ので、インスタンスプロファイルという用語が出てこないわけです。

そのおかげでインスタンスプロファイルの概念を理解するのに記事一本書けてしまいました。

# AWS CLIからのポリシー、ロール、インスタンスプロファイルの作成
IAMポリシー、IAMロール、インスタンスプロファイルの関係を理解するために、先ほどの図を少し修正した以下図を参考にAWS CLIから作っていこうと思います。

1. IAMポリシーの作成
2. IAMロールの作成
3. IAMロールとIAMポリシーの紐付け
4. インスタンスプロファイルの作成
5. インスタンスプロファイルとIAMロールの紐付け
6. インスタンスプロファイルとEC2インスタンスの紐付け

![InstanceProfile2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/622351b8-2e50-2f55-018f-4b50696aec75.png)


## 前準備
今回はEC2インスタンスからS3の`instance-profile-test1`というバケットに対しての書き込み権限を与えるインスタンスプロファイルを作成しようと思います。

今回出てくる名前やファイルは以下として進めます。

|構成|設定|
|:--|:--|
|IAMポリシー名|S3WritePolicy|
|IAMロール名|S3WriteRole|
|インスタンスプロファイル名|S3WriteProfile|
|IAMポリシーファイルパス|/home/ec2-user/iampolicy.json|
|Assumeロールファイルパス|/home/ec2-user/assume.json|
|テスト用S3バケット（許可あり）|instance-profile-test1|
|テスト用S3バケット（許可なし）|instance-profile-test2|
|書き込みテスト用ファイル|/home/ec2-user/writetest|

## IAMポリシーの作成
IAMポリシー作成には以下のような`JSON`形式の設定ファイルが必要となります。

既に手元に雛形があれば手元のファイルから作成すれば良いですが、初めはIAMポリシー作成時に表示されるビジュアルエディタから作成したほうが良いかもしれません。

以下で`instance-profile-test1`というバケットに対する書き込み許可とリスト表示の許可設定を行っています。

```json:IAMポリシーファイル
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::instance-profile-test1/*",
                "arn:aws:s3:::instance-profile-test1"
            ]
        }
    ]
}
```

上記で作成したIAMポリシーファイルを使ってIAMポリシーを作成します。
また、後ほど使用するため、`create-policy`実行後に表示される`Arn`は控えて下さい。

```shell:IAMポリシーの作成
aws iam create-policy --policy-name S3WritePolicy --policy-document file:///home/ec2-user/policy.json
```

```json:create-policy実行例
{
    "Policy": {
        "PolicyName": "S3WritePolicy",
        "PermissionsBoundaryUsageCount": 0,
        "CreateDate": "YYYY-MM-DDThh:mm:ssZ",
        "AttachmentCount": 0,
        "IsAttachable": true,
        "PolicyId": "xxxxxxxxxxxxxxxxxxxxx",
        "DefaultVersionId": "v1",
        "Path": "/",
        "Arn": "arn:aws:iam::xxxxxxxxxxxx:policy/S3WritePolicy",
        "UpdateDate": "YYYY-MM-DDThh:mm:ssZ"
    }
}
```

## IAMロールの作成
IAMロール作成には以下のような`JSON`形式の**Assumeロール**というファイルが必要となります。

**Assumeロール**とは、AWSコンソールでロールを作成する場合の**信頼関係**タブにあたる設定となり、うまく設定すると、他のアカウントからのアクセスなどを信頼することもできるそうです。

「[IAMロール徹底理解 〜 AssumeRoleの正体](https://dev.classmethod.jp/articles/iam-role-and-assumerole/)」

今回はIAMロール作成時のデフォルトで作成します。

```json:IAMロールファイル
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "sts:AssumeRole",
            "Effect": "Allow",
            "Principal": {
                "Service": "ec2.amazonaws.com"
            }
        }
    ]
}
```

上記で作成したIAMポリシーファイルを使ってIAMポリシーを作成します。

```shell:IAMロールの作成
aws iam create-role --role-name S3WriteRole --assume-role-policy-document file:///home/ec2-user/assume.json
```

## IAMロールとIAMポリシーの紐付け
先ほど個々に作成したIAMロールとIAMポリシーを紐付けします。
`--policy-arn`で指定する`ARN`は、先ほどIAMポリシーを作成した際に表示されたARN名を指定してください。

```shell:IAMロールとIAMポリシーの紐付け
aws iam attach-role-policy --role-name S3WriteRole --policy-arn arn:aws:iam::xxxxxxxxxxxx:policy/S3WritePolicy
```

もしARM名を控え忘れた場合は以下から確認しましょう。

```shell:カスタマー管理ポリシーの確認
aws iam list-policies --scope Local
```

## インスタンスプロファイルの作成
EC2インスタンスとIAMロールを紐付けるコネクタ部分となるインスタンスプロファイルの箱を作成します。

```shell:インスタンスプロファイルの作成
aws iam create-instance-profile --instance-profile-name S3WriteProfile
```

## インスタンスプロファイルとIAMロールの紐付け
先ほど作成したインスタンスプロファイルとIAMロールを紐付けします。

```shell:インスタンスプロファイルとIAMロールの紐付け
aws iam add-role-to-instance-profile --instance-profile-name S3WriteProfile --role-name S3WriteRole
```

## インスタンスプロファイルとEC2インスタンスの紐付け
今まで作成してきたIAMポリシー、IAMロール、インスタンスプロファイルのまとまりをEC2インスタンスに紐付けます。

EC2インスタンスの**インスタンスID**が必要となるので、以下コマンドで目的のEC2インスタンスを見つけ、インスタンスIDを控えましょう。

```shell:EC2インスタンスIDの確認
aws ec2 describe-instances
```

```shell:インスタンスプロファイルとEC2インスタンスの紐付け
aws ec2 associate-iam-instance-profile --instance-id [インスタンスID] --iam-instance-profile Name=S3WriteProfile
```

ちなみにAWSコンソールのEC2インスタンスのセキュリティタブからIAMロール欄を見るとIAMロール名が表示されますが・・・

![capture_23122020_081239.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/da129447-532a-8e5e-62d0-71a51324a9c7.jpeg)

「アクション」→「セキュリティ」→「IAMロールを変更」から見ると作成した**インスタンスプロファイル**が結びついていることが確認できます。

![capture_23122020_081317.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/4fc70ba3-704e-f07e-7970-02a4ae5f60c1.jpeg)

# S3バケット書き込みテスト
先ほどIAMポリシーファイルで許可したS3バケットと許可していないS3バケットに対してファイルコピーを実施し、IAMポリシーが有効になっているかを確認します。

テスト用S3バケットとテスト用ファイルは先に作成しておいてください。

```shell:書き込み許可されているS3バケットへのファイルコピー
aws s3 cp /home/ec2-user/writetest s3://instance-profile-test1
```

IAMポリシーで想定通りに許可されていれば、以下のように表示されます。

```shell:コピー成功時の表示例
upload: ./writetest to s3://instance-profile-test1/writetest
```

書き込み許可されていないS3バケットに対して同様にファイルコピーを実施すると以下のように表示されます。

```shell:書き込み許可されていないS3バケットへのファイルコピー
aws s3 cp /home/ec2-user/writetest s3://instance-profile-test2
```

```shell:コピー失敗時の表示例
upload failed: ./writetest to s3://instance-profile-test2/writetest An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
```

また、リスト表示の許可も与えているため、以下コマンドを実行すればリストも表示されます。

```shell:リスト表示許可されているS3バケットのリスト表示
aws s3 ls s3://instance-profile-test1
```

```shell:リスト表示許可されているS3バケットのリスト表示結果
YYYY-MM-DD hh:mm:ss          0 writetest
```

これでEC2インスタンスにアカウント情報を与えずにIAMロールで許可した操作を行えることが確認できました。

# （おまけ）AWS CLIからのポリシー、ロール、インスタンスプロファイルの削除
おまけとして削除方法も書いておきます。
作成するときの逆をやるだけです。

1. インスタンスプロファイルとEC2インスタンスの紐付け解除
2. インスタンスプロファイルとIAMロールの紐付け解除
3. インスタンスプロファイルの削除
4. IAMロールとIAMポリシーの紐付け解除
5. IAMロールの削除
6. IAMポリシーの削除

ちなみに、IAMロールとインスタンスプロファイルを今回のように別名で作成した場合、AWSコンソールでIAMポリシーを結びつけるときに表示されるインスタンスプロファイルは**AWS CLIからしか消せない**ので、**IAMロールを消したのにプルダウンで表示されている場合**は、後述のコマンドから削除しましょう。

先に次作業で使用する`Association-id`を以下で確認して控えます。

```shell:Association-idの確認
aws ec2 describe-iam-instance-profile-associations
```

確認した`Association-id`を使い、それぞれ削除していきます。

```shell:インスタンスプロファイルとEC2インスタンスの紐付け解除
aws ec2 disassociate-iam-instance-profile --association-id iip-assoc-xxxxxxxxxxxxxxxxx
```

```shell:インスタンスプロファイルとIAMロールの紐付け解除
aws iam remove-role-from-instance-profile --instance-profile-name S3WriteProfile --role-name S3WriteRole
```

```shell:インスタンスプロファイルの削除
aws iam delete-instance-profile --instance-profile-name S3WriteProfile
```

```shell:IAMロールとIAMポリシーの紐付け解除
aws iam detach-role-policy --role-name S3WriteRole --policy-arn arn:aws:iam::xxxxxxxxxxxx:policy/S3WritePolicy
```

```shell:IAMロールの削除
aws iam delete-role --role-name S3WriteRole
```

```shell:IAMポリシーの削除
aws iam delete-policy --policy-arn arn:aws:iam::xxxxxxxxxxxx:policy/S3WritePolicy
```

# おわりに
私と同じようにインスタンスプロファイルに振り回されている人の助けになれば幸いです。

# 参考記事
- 「[インスタンスプロファイルの使用](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html)」
- 「[AWS CLI を使用して IAM ロールを引き受ける方法を教えてください。](https://aws.amazon.com/jp/premiumsupport/knowledge-center/iam-assume-role-cli/)」
- 「[ロールまたはインスタンスプロファイルの削除](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_manage_delete.html)」