Permissions Boundaryによる利用者へのIAM権限移譲と権限昇格の防止

# なぜ必要?
社内のAWS環境の全体管理者が、AWS利用者(インフラエンジニアやDeveloper)に対してIAMの権限を移譲したいケースがあります。例えばマルチアカウントで運用していて、利用者のアカウント内ではサービスに必要なIAM Roleは管理者に申請せずに自分で作成して欲しいというような場合です。いちいち管理者に必要なIAM RoleとPolicyを申請していたら開発のスピードが落ちるし、管理者の運用負荷もバカにならないからです。
一方で、IAM Roleを作成可能にしてしまうと、利用者に与えられている権限や禁止したい操作を超えたIAM Roleを作成してスイッチすることができるようになります。これはガバナンスの観点でよろしくないという判断になる場合があります。指定したIAM PolicyしかIAM Roleにアタッチできないようにすることもできますが、事前に必要なポリシーをリストアップするのは難しいですし、管理も大変です。
そこでIAMに追加されたPermissions Boundary(アクセス権限の境界)という機能を使えば、上記の問題に対応することができます。
(IAM Userの作成権限を移譲する場合も同様です)

# Permissions Boundaryって何?
Permissions BoundaryはIAM Entity(IAM UserまたはRole。GroupはNG)に対して通常のIAM Policy(= Permissions Policy)に追加して付与するIAM Policyです。Permissions Boundaryが付与された場合、そのIAM Entityの権限はPermissions PolicyとPermissions Boundaryの積となります。実際には両方で許可されていれば許可となり、どちらかで拒否されていれば拒否となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/345960/026b4798-efcb-3e3f-a1d2-a92b7d03ca59.png)

付与はIAM UserやRoleのマネジメントコンソール画面やCLI/APIで簡単に実施できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/345960/502a595b-30e9-d4df-02c1-50deaf94345c.png)

これをうまく使うことで、権限昇格を防止した上で利用者にIAMの権限を移譲することができます。利用者がどれだけ強いIAM Policyを作成して付与しても、Permissions Boundaryの権限を越えることができなくなるためです。
詳細はこちら ： https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html

以下では具体例を使って説明してみます。

# どうやって使う? (具体例)
例えば、AWS利用者に対する要件が以下の場合を考えます。

* やってほしいこと
    * 自サービスで利用するIAM RoleとIAM Policyの作成
    * VPC関連と証跡関連(CloudTrailとConfig)以外は自由に操作してサービス開発してほしい
* やってほしくないこと
    * VPC関連の操作
    * CloudTrailとConfigの設定削除/変更
    * IAM Userの作成 (人間のログイン以外は原則Roleを使うこと)
    * <b>上記の権限を越えたIAM Roleの作成</b>

この場合、まず以下のIAM Policyを作成します。

* UserPermissionsPolicy (ポリシー名は例)
    * AWS利用者がログインに使用するIAM Entity(User or Role)に対して通常のIAM Policy(Permissions Policy)として付与するポリシー
    * Boundaryで最大範囲が決まるので、Full AccessでもOK、またはその利用者に必要な権限をセットする。

* UserPermissionsBoundary
    * AWS利用者がログインに使用するIAM Entity(User or Role)に対してPermissions Boundaryとして付与するポリシー
    * ポリシー概要(例)
        * 任意の操作許可
        * VPC関連操作を拒否
        * CloudTrailとConfigの停止/削除を拒否
        * IAMユーザの作成を拒否
        * IAM Roleの作成とPolicyのアタッチは指定したRole用Boundary(RolePermissionsBoundary)がアタッチされている場合のみ可能(されていないと拒否)
        * UserPermissionsBoundaryとRolePermissionsBoundaryの編集を拒否
        * アタッチされているPermissions Boundaryのデタッチを拒否

* RolePermissionsBoundary
    * AWS利用者が作成するIAM RoleにPermissions Boundaryとして付与する(付与を強制する)ポリシー
    * 利用者自身と同じ権限のIAM Role作成を許す場合はUserPermissionsBoundaryと同じ内容にし、作成させるIAM Roleではより権限を絞りたい場合は許可/拒否ポリシーを調整します。

次に、AWS利用者がログインに使用するIAM UserまたはRole(Switch RoleやFederationでログインする場合)のIAM PolicyとしてUserPermissionsPolicyを付与し、Permission BoundaryとしてUserPermissionsBoundaryを付与します。そうすることで利用者の権限が最大でもUserPermissionsBoundaryの範囲に制限され、かつ利用者によるIAM Role作成時には管理者が指定したPermissions Boundary(RolePermissionsBoundary)を付与する必要があるため意図した権限範囲を超えるRoleを作成できなくなります。

### ポリシードキュメント例
####UserPermissionsPolicy 
例では、Boundaryで最大範囲を決めるためここではFull Accessとしています。

```yaml
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AdministratorAccess",
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*"
        }
    ]
}
```

#### UserPermissionsBoundary

```yaml
{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Sid": "AdministratorAccess",
          "Effect": "Allow",
          "Action": "*",
          "Resource": "*"
      },
      {
          "Sid": "DenyUserCreationOrChange",
          "Effect": "Deny",
          "Action": [
              "iam:CreateUser",
              "iam:DeleteUser",
              "iam:PutUserPolicy",
              "iam:DeleteUserPolicy",
              "iam:AttachUserPolicy",
              "iam:DetachUserPolicy",
              "iam:PutUserPermissionsBoundary",
              "iam:AddUserToGroup",
              "iam:RemoveUserFromGroup",
              "iam:UpdateUser"
          ],
          "Resource": "*"
      },
      {
          "Sid": "DenyCreateOrChangeRoleWithoutBoundary",
          "Effect": "Deny",
          "Action": [
              "iam:CreateRole",
              "iam:PutRolePolicy",
              "iam:DeleteRolePolicy",
              "iam:AttachRolePolicy",
              "iam:DetachRolePolicy",
              "iam:PutRolePermissionsBoundary"
          ],
          "Resource": "*",
          "Condition": {
              "StringNotEquals": {
                  "iam:PermissionsBoundary": "arn:aws:iam::[AccoundID]:policy/RolePermissionsBoundary"
              }
          }
      }, 
      {
          "Sid": "DenyBoundaryPolicyEdit",
          "Effect": "Deny",
          "Action": [
              "iam:CreatePolicyVersion",
              "iam:DeletePolicy",
              "iam:DeletePolicyVersion",
              "iam:SetDefaultPolicyVersion"
          ],
          "Resource": [
              "arn:aws:iam::[AccoundID]:policy/UserPermissionsBoundary",
              "arn:aws:iam::[AccoundID]:policy/RolePermissionsBoundary"
          ]
      },
      {
          "Sid": "DenyBoundaryDelete",
          "Effect": "Deny",
          "Action": [
              "iam:DeleteUserPermissionsBoundary",
              "iam:DeleteRolePermissionsBoundary"
          ],
          "Resource": "*"
      },
      {
          "Sid": "DenyVPCChange",
          "Effect": "Deny",
          "Action": [
              "ec2:CreateVPC",
              "禁止するVPC操作2",
              "禁止するVPC操作3"
          ],
          "Resource": "*"
      },
      {
          "Sid": "DenyCloudTrailAndConfigChange",
          "Effect": "Deny",
          "Action": [
              "cloudtrail:DeleteTrail",
              "cloudtrail:PutEventSelectors",
              "cloudtrail:StopLogging",
              "cloudtrail:UpdateTrail",
              "config:DeleteConfigurationRecorder",
              "config:DeleteDeliveryChannel",
              "config:DeleteRetentionConfiguration",
              "config:PutConfigurationRecorder",
              "config:PutDeliveryChannel",
              "config:PutRetentionConfiguration",
              "config:StopConfigurationRecorder"
          ],
          "Resource": "*"
      }
  ]
}
```

#### RolePermissionBoundary
UserPermissionsBoundaryと同様か、作成するロールの最大の権限範囲に合わせて許可/拒否する操作を調整する。

#まとめ
ちょっと複雑ですが考え方を理解できれば権限移譲がしやすくなり、運用負荷軽減、開発スピード向上につながるため導入検討する価値歯あるかと思います。ただし、利用者がIAM Roleを作成するときに指定したPermission Boundaryを付与するという今までになかった操作が発生するため、Permissions Boundaryの考え方と操作方法を周知する必要があります。