AWS IAM再入門

# 概要
いまさらだけども理解しているつもりできちんと理解していなかったIAMについて、改めて勉強したので忘れないようにまとめる。

参考にした資料：
[【AWS Black Belt Online Seminar】AWS Identity and Access Management (AWS IAM) Part1](https://youtu.be/K7F5yTThynw)
[【AWS Black Belt Online Seminar】AWS Identity and Access Management (AWS IAM) Part2](https://youtu.be/qrZKKF6V6Dc)
※この記事で利用しているSSは上記資料内のものです。詳しく知りたい方は直接元の動画を見てください。

# IAMに登場する主な要素
- IAMユーザ
- IAMグループ
- IAMロール
- ポリシー

# IAMユーザ
- マネジメントコンソールやCLIで利用する**ユーザ**、あるいはSDKでAWSリソースへアクセスする**アプリケーション**の単位(EC2等で実行するアプリケーションの場合ユーザではなくロールを利用)で作成する。
- **ID+パスワード(+MFA)**もしくは**アクセスキー(認証用に生成された文字列)**で認証される。
- 複数の人やアプリケーションで使いまわしてはいけない。
![スクリーンショット 2021-01-31 18.35.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/854dcaad-723d-8fb5-16e7-3bd598ab0d71.png)

# IAMグループ
- 複数のユーザに**同一のポリシーのセット**を付与するのに使える。
- グループとユーザは0...10対N(1ユーザの所属できるグループは10まで、グループに所属させないことも可)  
例）開発チームリーダーAさんはDevグループとLeaderグループに所属させる、開発チームメンバーBさんにはDevグループにだけ所属させる

![スクリーンショット 2021-01-31 18.29.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/87263852-933e-9b8c-933b-89d97695a19d.png)

# IAMロール
- AWSサービスやEC2インスタンス内のアプリケーション、別のAWSアカウントのIAMユーザ/ロール、OIDCなど外部認証で認証されたユーザに権限を付与するための仕組み。
- IAMユーザやグループには紐付かない。

## IAMロールの主なユースケース

1. EC2上のアプリケーションへの権限付与
2. クロスアカウントアクセス
3. 一時的な権限昇格(Switch Role)
4. 外部IdPによる認証

:one: **EC2上のアプリケーションへの権限付与**
EC2上で動作するアプリケーションは通常のローカルPCやオンプレサーバ同様、EC2インスタンス内に保存されたアクセスキーによるAWSの操作を行うこともできるが、アクセスキーの漏洩などの危険性があるため、必ずIAMロールを利用する。
EC2インスタンスの作成時にIAMロールを指定する箇所があるのでそこで事前に作成したIAMロールを指定するだけ。
![スクリーンショット 2021-01-31 20.49.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/efffd8ca-8d98-7242-e772-bbd26cef6113.png)

:two: **クロスアカウントアクセス**
ロールは異なるAWSアカウントへの権限を移譲にも利用できる。
AWSでは環境やシステムごとにアカウントを分離することを推奨しており、エンタープライズでは一人のユーザが複数アカウントを利用することは珍しくない。このため、ユーザと権限の管理コストを下げるためにも、IAMロールを利用する。
アカウント間でアクセスキーなどのセキュリティ情報の共有をしてはいけない、権限の分離のためにアカウントを分けている意味がなくなってしまう。

![スクリーンショット 2021-01-31 20.54.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/5c375ff4-389a-8fb5-2860-42ef31d05a8b.png)

:three: **一時的な権限昇格(Switch Role)**

クロスアカウントだけでなく、同じアカウント内でもIAMロールの切り替えによる権限の切り替えが可能。
マネジメントコンソールから簡単に切り替えができるので、クロスアカウントでもこの仕組を使うと操作が楽になる。
![スクリーンショット 2021-01-31 20.55.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/1c2f4bc2-c26b-a427-637a-9903da61fa1c.png)

:four: **外部IdPによる認証(SSO)**

IAMロールを用いて外部のIdPによるSSOも可能。
社内システムなどの場合、社内のActiveDirectoryで管理された社員情報で認証を行わせることでユーザの二重管理を防げる。

![スクリーンショット 2021-01-31 21.09.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/95b90084-e55e-a6a1-cfe0-ecf312dde3f5.png)

ここで利用できるIdPにはGoogle,Facebook,Amazon,twitterなどのOIDC準拠のものも含まれる。
これを利用し、モバイルアプリに対しこれらのOIDCで認証を行い、AWSの操作権限を与えることもできる。
バックエンドにアプリケーションサーバを置かずとも、認証されたユーザのみにクライアントから直接DB操作をさせることができる、すごい。

![スクリーンショット 2021-01-31 20.58.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/d8cbd7c1-8753-e6fa-2f91-d8bda6b707ee.png)

# ポリシー
IAMユーザ、IAMグループ、IAMロール、あるいはAWSリソースそのものに付与する権限の内容を定義するもの。JSONで記述する。
IAMユーザ、IAMグループ、IAMロールに付与するポリシーを「アイデンティティベースポリシー」、AWSリソースに付与するポリシーを「リソースベースポリシー」という。

![スクリーンショット 2021-01-31 18.35.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/4ab6f734-5137-138d-9d38-accf9892a235.png)

## ポリシーに記述する主な要素

- Version
- Statement
- Effect
- Principal
- Action
- Resource
- Condition
![スクリーンショット 2021-01-31 18.36.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/8dc8e95a-8de6-f4fa-1e16-5ad75b0127b4.png)

他にもいくつか存在するが、基本はこれを覚えておくけばいい。
参考(公式ホワイトペーパー)：https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements.html

## Version
このポリシーのバージョンではなく、ポリシー言語のバージョン。
現在(2020/02時点)でのバージョンは

- 2008-10-17
- 2012-10-17

の2つしか存在しない。
指定しないと旧バージョンのドキュメントとして読み込まれ、ポリシー変数が有効にならなかったりするので必ず最新を指定する。
参考：https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements_version.html

```json:example_policy
{
  "Version": "2012-10-17",　←これ
  "Statement": [
    ︙
  ]
}
```

## Statement
Effect、Principal、Action、Resource、Conditionなどの子属性をまとめる親属性、配列。
この中身の1要素のことをステートメントブロックという。

```json:記述例
{
  "Version": "2012-10-17",
  "Statement": [ 　←これ
    {　　　　　　　　　　　　　　　　　　　　　　　←ここから
      "Sid": "FirstStatement",
      "Effect": "Allow",
      "Action": ["iam:ChangePassword"],
      "Resource": "*"
    },　　　　　　　　　　　　　　　　　　　　　　　←ここまでが1ステートメントブロック
    {
      "Sid": "ThirdStatement",
      "Effect": "Allow",
      "Action": [
        "s3:List*",
        "s3:Get*"
      ],
      "Resource": [
        "arn:aws:s3:::confidential-data",
        "arn:aws:s3:::confidential-data/*"
      ],
      "Condition": {"Bool": {"aws:MultiFactorAuthPresent": "true"}}
    }
  ]
}
```

## Effect
そのステートメントは許可なのか拒否なのか。
"Allow"or"Deny"

```json:記述例
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "FirstStatement",
      "Effect": "Allow",　　←これ
      "Action": ["iam:ChangePassword"],
      "Resource": "*"
    }
  ]
}
```

## Principal
そのステートメントはどのIAMエンティティ(IAMユーザやIAMロールなど)に対する定義なのか。
リソースベースポリシーにのみ必要、アイデンティティベースポリシーの場合暗黙で付与先のIAMエンティティ(IAMユーザやIAMロールなど)が対象となる。
指定したもの"以外"を対象とする`NotPrincipal`もある。

```json:記述例
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "FirstStatement",
      "Effect": "Allow",
      "Principal": {　　←これ
        "AWS": [　　←複数のIAMエンティティを配列で指定可能
          "arn:aws:iam::AWS-account-ID:user/user-name-1", 
          "arn:aws:iam::AWS-account-ID:user/UserName2"
        ]
      }
      "Action": ["iam:ChangePassword"],
      "Resource": "*"
    }
  ]
}
```

## Action
そのステートメントはどのアクション(AWSリソースへの操作)を許可もしくは拒否するのか。
`サービス名:アクション名`で事前定義されているものから選択し指定する。
指定したもの"以外"を対象とする`NotAction`もある。

```json:記述例
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "FirstStatement",
      "Effect": "Allow",
      "Action": [　　←これ
        "ec2:StartInstances",　　←複数指定可能
        "sqs:*Message",   ←ワイルドカードも利用可能
        "iam:ChangePassword",
        "s3:GetObject" ]
      "Resource": "*"
    }
  ]
}
```

## Resource
そのステートメントはどのリソースに対する定義なのか。
`Describe~`などのリスト系の場合、`"*"`しか使えない。
書き込み系等のレベルの高い権限はできるだけ`Resource`を具体的に指定し、最小権限になるようにする。

```json:記述例
{
  "Version": "2012-10-17",
  "Statement": {
    "Effect": "Allow",
    "Action": "dynamodb:*",　　↓これ
    "Resource": "arn:aws:dynamodb:us-east-2:AWS-account-ID:table/${aws:username}"
  }　　　　　　　　　　　　　　　　　　　　　　　　　　　　　ポリシー変数(後述)が利用可能↑
}
```

## Condition
このポリシーを適用する条件。
特定のIPからのアクセスのみ許可、やS3バケット内の特定文字列から始まるオブジェクトへのアクセスのみ許可、EC2の特定のインスタンスタイプのみ起動を許可、など。
ANDとORをまとめて1つの`Condition`に定義可能。

![スクリーンショット 2021-01-31 18.08.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/15f29cf5-5345-d2b5-db91-7dd01d782fab.png)


```json:記述例
{
  "Version": "2012-10-17",
  "Statement": {
    "Effect": "Allow",
    "Action": "iam:*AccessKey*",
    "Resource": "arn:aws:iam::AWS-account-ID:user/*",
    "Condition": {　　←これ
      "IpAddress": {
        "aws:SourceIp": [
          "203.0.113.0/24",
          "2001:DB8:1234:5678::/64"
        ]
      }
    }
  }
}
```

## その他ポリシーに関する予備知識
### ポリシー変数
リソースとコンディションには`${aws:username}`や`${aws:SourceIp}`などの変数を利用することができる。
アクセス時に実際にログインしているIAMユーザやアクセス元のIPなどが動的にはめ込まれる。
**例1：各ユーザに自分のユーザ名のついたS3バケットやDynamoDBのテーブルのみ操作可能にする
例2：VPNを経由しているとき(特定IPからのアクセス時)のみ対象の操作を許可する**
参考：https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_variables.html#policy-vars-infotouse

### カスタマー管理ポリシーとインラインポリシーの使い分け
カスタマー管理ポリシーのほうがあとからできたらしい、AWSはできるだけインラインポリシーではなくカスタマー管理ポリシーを使用することを推奨している。
![スクリーンショット 2021-01-31 17.36.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/ae2afec9-4118-9128-72e8-e6e56be1ad3f.png)

### IAMユーザ/ロール再作成時などの注意
プリンシパルに指定されたIAMユーザやIAMロールを再作成したときはロールの再編集が必要。
ロール保存時に内部ではユーザ名/ロール名ではなくIDで紐付けされているため。

![スクリーンショット 2021-01-31 18.03.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/92976ec3-8a61-3fb2-efd2-91dd64f64b26.png)

### アクセス許可の境界(Permission Boundary)
IAMポリシーはホワイトリストなので、後から許可を付与することで権限の範囲を広げることができる。
この追加に対して「これ以上は追加されたくない」という"境界"を事前に定義するのに利用する。
「ここまでは許可」と「これは拒否」を指定できる。
![スクリーンショット 2021-01-31 18.20.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/7a4a7702-61f3-8f47-03a7-9b71d0f76f83.png)

詳しくは↓が解りやすい。
https://dev.classmethod.jp/articles/iam-permissions-boundary/
AWS OrganizationのSCPもほぼ同じ、違いはアカウントをまたぐことができるかどうか

# 権限決定のロジック
IAMではアイデンティティベースポリシーやリソースベースポリシーなど複数の許可・拒否定義要素があるため、これらがどういった流れで適用されるのかを知らないと、正しい設定を行うことができない。

## DenyとAllowの優先順位
明示的に定義した場合、Denyが勝つ
![スクリーンショット 2021-01-31 18.09.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/7b8039d8-c50e-2298-be46-dcb630f5d8e4.png)

## 全体の決定ロジック
SCPでもアクセス許可の境界でも拒否されていない、かつアイデンティティベースまたはリソースベースポリシーで許可されていれば許可。
![スクリーンショット 2021-01-31 18.11.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/72040a76-2b68-8d71-66ce-28f3d8b094f0.png)

ただし、クロスアカウントの場合、アイデンティティベースとリソースベースポリシー両方で許可されていないといけない。
(アイデンティティベースは自アカウント側、リソースベースは相手アカウント側なので当然といえば当然)
![スクリーンショット 2021-01-31 22.43.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/c18dc632-4f5b-8664-7fab-803e2c513449.png)

## リソースベースポリシーとアイデンティティベースポリシー
リソースベースポリシーとアイデンティティベースポリシーはOR条件、どちらかに定義されていれば有効。
![スクリーンショット 2021-01-31 18.21.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/60d60f5d-d74c-aaf3-2ff0-183eb77230dd.png)

## 管理ポリシーとインラインポリシー
管理ポリシーとインラインポリシーもOR条件、どちらかに定義されていれば有効。
![スクリーンショット 2021-01-31 18.19.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/56c7c1a8-4180-915a-2762-5661cd883c2b.png)

# その他予備知識

## STS
権限の移譲を行うサービス、IAMと深く関わってくる。
`Switch Role`や`Assume Role`に利用。

## アクセスアドバイザー
IAMエンティティへのアクセス状況を確認できる機能、不審なアクセスや不要なユーザ・ロールが存在しないか確認するのに利用する。
![スクリーンショット 2021-01-31 21.23.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140013/e3debc15-c383-bded-f9a4-7f1b9d601eb2.png)

## ポリシージェネレータ

GUIでIAMポリシーを生成できる。
https://awspolicygen.s3.amazonaws.com/policygen.html