PowerUserAccessだと全てのIAMロールにスイッチ出来てしまう問題の対処方法

AWS Organizationsの登場などにより、AWSを使ったシステムでは複数のAWS アカウントをつかったマルチアカウント運用が増えています。

マルチアカウント運用ではIAMロールによるユーザの集中管理などが重要となってきます。
この記事ではこの集中管理の時の思わぬ注意点をご紹介します。

#AWSにおけるマルチアカウントのベストプラクティス
AWSのマルチアカウント運用を行う場合複数のパターンが考えられます。

1. 各アカウントにIAMユーザを作成して個別にログインする。
1. IAM管理用の踏み台アカウントを作成し、各アカウントにはIAMロールを作成しスイッチロールを利用する。
1. AWS SSO を利用し、SSOログインを行う。
1. OneLoginのようなサードパーティーの認証プロバイダを利用する。

各アカウントを利用する方式は、メンバー変更があった際に、全てのAWSアカウントでユーザの追加、削除を行う必要があり対象アカウントが増えてくると管理コストが増大します。

AWS SSOを利用する場合はMicrosoft Active Directoryが必要となります。
企業が自社利用する場合には問題ありませんが、開発会社など外部委託する場合には適用が難しくなります。

サードパーティープロバイダの利用は別途契約が必要となります。

##AWS ドキュメント
少し古い資料ですが、AWSのマルチアカウントベストプラクティスではIAM管理用の踏み台アカウントを用意し、そこから開発アカウントや本番アカウントのIAMロールにスイッチする運用をベストプラクティスとしています。
<img width="720" alt="2019-08-17_11h47_49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102020/a5f35b7a-5a29-b5b1-3ac1-de822f1752b1.png">
https://d0.awsstatic.com/events/jp/2017/summit/slide/D4T2-2.pdf#page=28

JUMPアカウント方式とすることで、開発メンバーの増減などに少ない労力で柔軟に対応することができるようになります。

##実環境での構成

AWSベストプラクティスでは、JUMPアカウントにはIAMユーザーのみが存在しそれ以外のリソースは存在しません。

Organizationsのように、アカウントが統一されており、CloudTrailの設定等が一括して行われている環境であれば、実際にJUMPアカウントをこのような構成にすることも可能ですが、特に全体管理がなされていない複数のアカウントの一つJUMPアカウントにする場合にはJUMPサーバ内にCloudTrailの設定や、踏み台アカウントの構築などある程度の操作権限を持ったIAMユーザが必要になる場合があります。

#ターゲットアカウントにおけるIAMロール

スイッチロールのターゲットとなるアカウントでは、特に複雑な操作は不要です。
通常のIAMユーザーやIAMグループを作成するときと同様に、適切な権限を設定した
**IAMロール** を作成します。

このときにIAM管理者ロール、リソース管理者、開発者、テスターなどのロールを作成しておくことにより権限管理が可能となります。

##信頼関係の設定

IAMロールを作成するときには、**別のAWSアカウント** を選択してJUMPアカウントのアカウントIDを入力します。
<img width="733" alt="2019-08-17_20h35_59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102020/a58bea92-30c4-2935-12ac-c48ae5d91378.png">

IAMロールの信頼関係タブから変更することもできます。

```json:信頼関係
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<JUMPアカウントのID>:root"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

#IAMグループとIAMロール

AWSのベストプラクティスでは、IAMユーザーに直接ポリシーを設定するのはなく、IAMグループに権限を設定し、IAMユーザーはグループに所属することで、権限を管理する方法が推奨されています。

IAMグループ毎にでスイッチ出来るIAMロールを制限することによって
IAM管理者、リソース管理者、開発者、テスターなどの役割を分ける事が可能です。

ターゲットアカウントで作成したIAMロールと、JUMPアカウントのIAMグループを対として設計することが重要です。

##特定ロールへのスイッチ制御

実際に特定のIAMロールにスイッチさせるには、次のようなIAMポリシーをIAMグループに対して設定します。
実際にはユーザー管理ポリシーとして作成し、この管理ポリシーをIAMグループにアタッチする方法がオススメです。

```JSON:スイッチ先IAMロールを限定するIAMポリシー

{
  "Version": "2012-10-17",
  "Statement": {
    "Effect": "Allow",
    "Action": "sts:AssumeRole",
    "Resource": "arn:aws:iam::<ターゲットアカウントIDもしくは*>:role/<作成したIAMロール名>"
  }
}

```

なお、この手順は公式ドキュメントにも記載があります。
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html


#JUMPアカウントにおけるPowerUserAccess
公式ドキュメントでも言及されていますが、JUMPアカウントのIAMグループにAWS管理ポリシーのPowerUserAccessポリシーをアタッチした場合、上記のスイッチ先**IAMロールを限定するIAMポリシー** は適切に動作しません。

PowerUserAccessポリシーがアタッチされている場合、全てのIAMロールに対してアクセスが出来てしまいます。
AWSの公式ドキュメントでは、この場合以下のようなスイッチロールの拒否権限を提案しています。

```Json:特定のIAMロールへのスイッチを拒否するポリシ－

{
  "Version": "2012-10-17",
  "Statement": {
    "Effect": "Deny",
    "Action": "sts:AssumeRole",
    "Resource": "arn:aws:iam::<ターゲットアカウントIDもしくは*>:role/目的以外のIAMロール名"
  }
}

```

この場合、IAMロールの数が少なければ無理ではありませんが、複数のIAMロールがある場合に制御が複雑になってしまいます。

また、拒否権限を含める場合、1つのユーザーが複数のIAMグループに所属した場合に狙い通りに動作しない場合があります。
例えば、リソース管理者とIAM管理者を兼務する人と、どちらか片方の役割しか持たない人などがいた場合、に2つのIAMグループに所属しても、2つの権限の合成のようには動作しません。

##スイッチ制御とPowerUserAccess
そもそも、なぜPowerUserAccessではスイッチロールが適切に機能しないのでしょうか。

その原因を考えるために、PowerUserAccessの権限を見てみます。

```Json:PowerUserAccessポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "NotAction": [
                "iam:*",
                "organizations:*",
                "account:*"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "iam:CreateServiceLinkedRole",
                "iam:DeleteServiceLinkedRole",
                "iam:ListRoles",
                "organizations:DescribeOrganization",
                "account:ListRegions"
            ],
            "Resource": "*"
        }
    ]
}
```


PowerUserAccessではNotAction要素によって、**IAM**、**Organizations**、**AWSアカウント自体**に対して以外の全ての操作を許可しているポリシーとなっています。

スイッチロールに関する制御は、利用している要素がIAMロールなので、IAM要素のように考えてしまいますが、実際には**STS**となります。

PowerUserAccessはSTSの全てが許可されている状態になるため、**スイッチ先IAMロールを限定するIAMポリシー**に関わらず全てのIAMロールにスイッチ出来てしまいます。

##スイッチ制御対応版PowerUserAccess権限の提案
**スイッチ先IAMロールを限定するIAMポリシー**を意図通りに動作させるためには、
**特定のIAMロールへのスイッチを拒否するポリシ－**を使うようりも、そのほかのユーザーと同じように
スイッチ先IAMロールを限定するIAMポリシーが意図通りに動作するカスタムのPowerUserAccessポリシーを作成し、利用されることをオススメします。

具体的には以下のようなポリシーになります。

```Json:IAMロールスイッチ制限に対応するPowerUserAccessポリシ－
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "NotAction": [
                "iam:*",
                "organizations:*",
                "account:*",
                "sts:*",
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "iam:CreateServiceLinkedRole",
                "iam:DeleteServiceLinkedRole",
                "iam:ListRoles",
                "organizations:DescribeOrganization",
                "account:ListRegions"
            ],
            "Resource": "*"
        }
    ]
}
```

NotAction要素の中にsts:*を追加します。

これで、意図通りに、**スイッチ先IAMロールを限定するIAMポリシー**で指定されたIAMロールにのみスイッチすることが可能となります。

JUMPアカウントでPowerUserAccessの権限を持ちながら、マルチアカウントでのアカウント制御を行いたい場合にぜひご検討ください。