[AWS] ユーザー管理をチームに委譲するIAM構成

# 目的
システムの規模が大きくなると関わるメンバーも増え、IAMユーザー管理の手間も大きくなってきます。
インフラ/アプリ/運用などでチームが分かれていて、それぞれ請け負う組織（部署や会社）が違ったりする場合、各チームにユーザー管理を委譲したいですよね。（したくないケースもあると思いますが）
そのような運用をするためのIAMグループ構成とポリシーを考えてみます。

# 設計/実装

## 前提/要件
  * 権限はIAMグループで管理する。
  * チームごとにリーダーを置き、リーダーにチーム内のユーザー管理権限を移譲する。
  * チーム内のサブグループも利用できる。担当業務でのグループ分けを想定。
  * 他チームのユーザーを操作できてはいけない。


## リーダーに移譲する権限
  * 自チームのIAMユーザー追加/更新/削除
  * 自チームのIAMユーザーへの権限付与（自グループへの追加/削除）

## リーダーに移譲しない権限
  * 他チームのIAMユーザー追加/更新/削除
  * 他チームグループへのIAMユーザー追加/削除
  * グループの作成/削除
  * グループの権限変更（グループポリシー変更）
  * 他チームのIAMユーザーへの権限付与（他グループへの追加/削除）  
    **→ 実現できませんでした。**


## グループ構成
| グループ | グループ名の例 | 役割 | 権限（ポリシー） |
|:----|:----|:----|:----|
| IAM管理者 | IAM-Manager | 全体のIAM管理。<br>グループ管理も。<br>任意で権限分割を。 | IAMFullAccess |
| チームA_リーダー | Team-A_Leader | チームAの<br>ユーザー管理 | [#ポリシー](#ポリシー)を参照 |
| 　└ チームA_メンバー | Team-A_Member | 各担当業務 | （任意） |
| チームB_リーダー | Team-B_Leader | チームBの<br>ユーザー管理 | [#ポリシー](#ポリシー) を参照 |
| 　├ チームB_メンバー① | Team-B_Developer | 各担当業務 | （任意） |
| 　└ チームB_メンバー② | Team-B_Operator | 各担当業務 | （任意） |

* AWSの機能で「サブグループ」というものがあるわけではないです。  
表内の階段状の表記は、あくまで権限範囲を表す論理的な構成を表現したものです。

## ルール
  * ユーザー名/グループ名には、チーム共通のPrefixを付与する。  
    リーダーが操作可能なIAMユーザー/グループを限定するため。
  * PrefixではなくSuffixでも良さそうです。  
    例えば「ユーザー名は会社メアドにする」というルールにすると、メアドの `@ドメイン名` をSuffixとして指定できます。  
    その場合は、後述の [#ポリシー](#ポリシー) の `Resource` 内のワイルドカード位置を調整で。  
    例) `"arn:aws:iam::<アカウントID>:user/*<ユーザー名Suffix>"`

## ポリシー
### チームリーダー用
下記のポリシーを各チームのリーダー用グループに付与する。
`<アカウントID>` `<ユーザー名Prefix>` `<グループ名Prefix>` は該当するものに置き換える。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iam:List*",
                "iam:Get*"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "iam:GenerateServiceLastAccessedDetails",
                "iam:CreateAccessKey",
                "iam:CreateUser",
                "iam:CreateLoginProfile",
                "iam:DeleteAccessKey",
                "iam:DeleteLoginProfile",
                "iam:DeleteSigningCertificate",
                "iam:DeleteUserPermissionsBoundary",
                "iam:DeleteUserPolicy",
                "iam:DeleteUser",
                "iam:DetachUserPolicy",
                "iam:UpdateAccessKey",
                "iam:UpdateUser",
                "iam:UpdateLoginProfile",
                "iam:EnableMFADevice",
                "iam:DeactivateMFADevice",
                "iam:ResyncMFADevice",
                "iam:DeleteVirtualMFADevice",
                "iam:CreateVirtualMFADevice"
            ],
            "Resource": [
                "arn:aws:iam::<アカウントID>:user/<ユーザー名Prefix>*",
                "arn:aws:iam::<アカウントID>:mfa/<ユーザー名Prefix>*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "iam:AddUserToGroup",
                "iam:RemoveUserFromGroup"
            ],
            "Resource": [
                "arn:aws:iam::<アカウントID>:group/<グループ名Prefix>*"
            ]
        }
    ]
}
```
* ステートメント1:  
  IAMのRead権限。  
  ここでは全IAMリソースにReadを可としていますが、見せたくない情報がある場合は範囲を限定してください。
* ステートメント2:  
  自チームのユーザー（指定Prefixが付与されたユーザー）の作成/更新/削除権限。  
  ユーザーポリシー付与権限は無し。
* ステートメント3:  
  自チームのグループ（指定Prefixが付与されたグループ）に対するIAMユーザーの追加/削除権限。


## 注意点
  * 『[#リーダーに移譲しない権限](#リーダーに移譲しない権限)』に記載したとおり、自チームに所属しないユーザーに対しても、自グループへの追加は出来てしまいます。  
    これを制限する方法が見つかりませんでした。もしあったら教えてください。
  * 上記の通り「自グループに追加できてしまう」ので、本来は管理対象外であるユーザーに対し、`Allow`で本来意図していない権限が付与されたり、`Deny`で本来意図していない権限が禁止されたりする可能性があります。  
    どちらも望ましくありませんが、前者(`Allow`)はまだマシ。後者(`Deny`)だとシステムの開発/運用に支障が出る可能性があります。  
    各チーム用グループは、なるべく`Deny`ポリシーを使わない権限設定にするほうが安全です。