IAMポリシーの概念まとめ

AWSのIAMポリシーは概念がたくさん出てくるので、勉強した範囲でまとめ（間違っているかもしれない）

## ポリシーの分類

```mermaid
classDiagram

アイデンティティベースポリシー --|> ポリシー
リソースベースポリシー --|> ポリシー
ポリシー <|-- AWS管理ポリシー
ポリシー <|-- カスタマ管理ポリシー
ポリシー <|-- インラインポリシー
```
### アタッチ対象による分類

- アイデンティティベースポリシー 
    - ユーザー、グループ、ロールにアタッチするポリシー。
    - アタッチ対象がPrincipalになるので、Principalの指定は不要
- リソースベースポリシー
    - S3バケットや、SQSキューなどのリソースにアタッチするポリシー
    - インラインポリシーでのみ記述で記述できる
    - IAMロールの信頼ポリシーもリソースベースポリシーの一種

### 管理方式による分類

- AWS管理ポリシー
    - AWS側でメンテナンスされるポリシー
    - 特定のAWSサービスのSourceIPリストなどを含むポリシーなどは、AWS側で更新してくれる
- カスタマ管理ポリシー
    - AWS利用者側でポリシーエディタなどで作成したポリシーに名前をつけたもの
    - IAMのポリシー一覧に表示される
- インラインポリシー
    - カスタマが作成する点はカスタマ管理ポリシーと同様だが、こちらはAWSの各リソースの設定画面で設定する
    - IAMのポリシー一覧には表示されない

## ポリシーの構造

```mermaid
classDiagram

Policy o--> "*" Statement
Statement --> "*" Principal
Statement --> "*" Action 
Statement --> "*" Resource 
Statement --> "*" Condition
 
Principal <|-- AWS
Principal <|-- Service
Principal <|-- Federated


class Policy {
  +Version
}
class Statement {
 +Sid
 +Effect
}
class Effect {
  <<enum>>
  Allow
  Deny
}
```

- Policy: 実質的にStatementの配列
- Statement: 実際の許可、拒否情報
    - Sid: Statementの識別子。自由につけて良い
    - Effect: Allow または Deny
- Principal: 許可or拒否を受ける主体
    - AWS: AWSアカウント、AWSユーザー、AWSロールなど
    - Service: AWSの各種サービス（例えばEC2サービスなど）
    - Federated：外部認証ユーザー
- Action: "s3:ListAllMyBuckets"などの文字列 または その配列。"*"ですべてのアクションを表す
- Resouce: ARN文字列 または その配列。 "*"ですべてのリソースを表す。ARN内に*をワイルドカードとして使用可能
- Condition: 特定の条件のとき許可or拒否するときにつける

Statement配下の4つの頭文字を取ってPARCモデルという

サンプルは下記を参照
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/access_policies.html

## IAMユーザー

```mermaid
classDiagram

IAMユーザー --> "*" 許可ポリシー
IAMユーザー --> "0...1" 許可境界

```

- 許可ポリシー（Permission Policy）: このユーザーが何をできるか or できないか。複数指定可
- 許可境界（Permission Boundary）：このユーザーができることの上限。詳しくは後述

## IAMロール


```mermaid
classDiagram

IAMロール --> "*" 許可ポリシー
IAMロール --> "0...1" 許可境界
IAMロール --> "0...1" 信頼ポリシー
```
- 許可ポリシー、許可境界：IAMユーザーと同様
- 信頼ポリシー：このロールを誰が使ってよいか。詳しくは後述


## 許可境界（Permission Boundary）

- IAMユーザーがあるアクションを行えるかは、許可ポリシーと許可境界の両方に含まれるかで判定される
- これだけだと許可境界がなくても、許可ポリシーの方から、許可境界に含まれないものを削るだけでもよくなってしまう
- 許可境界の本来のユースケースは、IAMユーザーにIAMロールの作成を許しつつ、IAMユーザーが自身の持っている権限を超えたIAMロールを作って、それをEC2やLambdaなどにアタッチすることで権限昇格してしまうことを防ぐこと

概略レベルでは、下記のような手順で使う

- AWSアカウントの管理者は、IAMロールの上限となるポリシーを定義する
    - 名前を仮に MyProjectRoleBoundaries とする
- AWSアカウント管理者は、開発用IAMユーザーを作るときに下記のような許可ポリシーを設定する
```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                ...
                "iam:CreateRole",
                "iam:UpdateRole*",
                ...
            ],
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "iam:PermissionsBoundary": 
                       "arn:aws:iam::123456789012:policy/MyProjectRoleBoundaries"
                }
            }
        },
```
- 開発用のIAMユーザーは、IAMロールを作成するときに、その境界として MyProjectRoleBoundaries を設定する
- これでIAMユーザーが、作成したIAMロールのどれだけ強力な権限をつけようとも、MyProjectRoleBoundaries が上限となる
- IAMユーザーが、IAMロール作成時に MyProjectRoleBoundariesを境界に設定しない場合は、上記のConditionによりCreateRoleに失敗してしまう。
- 実際にはこれだけでは穴がたくさんあるので、実践ではより精査が必要となる
- 参考
    - https://www.yamamanx.com/iam-permission-boundary-role/
    - https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/access_policies_boundaries.html

## IAMロールの信頼ポリシー

- 概略的な表現をすれば「誰がこのロールを使えるか」になる
- S3へのFull AccessできるロールをEC2にアタッチするケースでは、ロールの信頼ポリシーでは以下のような記述になる
```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "ec2.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
```
- 文字通りの解釈では「EC2サービスに、AssumeRoleを許可する」となる
- EC2インスタンスが、あるロールとして振る舞う場合、以下のような動きをする
    - EC2サービス（EC2インスタンスではないことに注意）が、STS（Secure Token Service）からそのロールのアクセスキーIDとシークレットアクセスキーを取得する
        - これがAssumeRoleにより許可される
    - EC2サービスは取得したアクセスキーIDとシークレットアクセスキーをEC2インスタンスのメタデータにセットする
    - EC2インスタンスからAWSのAPIを呼び出す際には、AWS SDKはIMDS(Instance MetaData Service)から自身に設定されたアクセスキーIDとシークレットアクセスキーを取得し、使用する
- PrincipalをIAMユーザーに変えれば、IAMユーザーがIAMロールのアクセスキーIDとシークレットアクセスキーを取得できるようになる

## インスタンスメタデータの取得

インスタンスメタデータは、EC2インスタンス内からは、下記のエンドポイントからcurlなどで簡単に取得することができる
```
$ curl http://169.254.169.254/latest/meta-data/
```
この169.254.169.254はリンクローカルアドレスで、EC2インスタンス内からのみ利用できる。
このシンプルなhttp呼び出しを使うやり方はIMDSv1という方式で、今後廃止が予定されているので、
以下のようにIMDSv2方式を使うことが推奨されている

IMDSv2方式ではメタデータの取得の前にトークンを手に入れる
```
$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
```
トークンを取得したら以下のように、自身に割り当てられたロールを確認する

```
$ curl -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/meta-data/iam/security-credentials/
```
ロール名が分かったら、AccessKeyIdとSecretAccessKeyを取得する

```
$ curl -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/meta-data/iam/security-credentials/ロール名
```
- 参考
    - インスタンスメタデータの取得
        - https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html
    - インスタンスメタデータのカテゴリ
        - https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/instancedata-data-categories.html



## PassRole

許可境界（Permission Boundary）では、IAMユーザーが自身の権限を超えるRoleを作成することを制限ができました。では、すでに強力な権限を持っているRoleが作成済みであった場合、その利用を制限するにはどうすればよいでしょうか。

例えば、以下があったとしましょう。
- EC2Fullアクセス権限を持っているIAMユーザー
- S3Fullアクセス権限を持ったIAMロール（EC2サービスに、AssumeRoleを許可している）

このIAMユーザーが、自身の作成したEC2インスタンスに、S3Fullアクセスのロールを割り当てることはできるでしょうか？答えはEC2Fullアクセスだけでは無理ですが、IAMユーザーに以下の権限を加えれば可能です。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "iam:ListInstanceProfiles",
            "Resource": "*"
        }
    ]
}
```


重要なのはiam:PassRoleの部分です。PassRoleはIAMロールをAWSリソースに割り当てる権限です。

「どのRoleを、どのリソースに割り当てるか」といった細かい指定は下記を参照してください。

参考： https://dev.classmethod.jp/articles/restrict-pass-ima-role-with-passrole/