SSOログインする際のIAMとAWS Identity Centerの課題と解決

**IAM**ユーザーでログインしていたものを**AWS Identity Center**でログインするように移行する際に留意すべきと思われる点を取りまとめる。

<!-- ================================================= -->
# 前提1:IAMでの役割と権限のベストプラクティス
<!-- ================================================= -->
ユーザーが時に開発者だったりオペレータだったりと場合に応じて役割と権限を分ける方式を採用する場合、役割毎の**IAM**ユーザーを作成するのではなく、各役割に応じた権限を持つ**IAM**ロールを作成し、**IAM**ユーザーからスイッチロールすることで実現する。
どの**IAM**ユーザーがどの**IAM**ロールにスイッチロール可能かは、ユーザーグループにスイッチロールする権限を付与することで記述する。
**IAM**ユーザーがどのユーザーグループへ所属するかによって、スイッチロール先の**IAMロール**を制御できる。
この方式は**AWS Organizations**によって複数アカウントを管理する必要になった場合でも適用可能なため汎用性が高いが、ログインしたユーザーを識別する際には問題が発生する方式でもある。

<!-- ================================================= -->
# 前提2:ログインしたユーザーを識別する方法
<!-- ================================================= -->
1つの**IAM**ポリシーを用いて、ログインしたユーザー毎にアクセス可能なリソースの制限や権限の認可を制御する場合、**IAM**ポリシーの**Condition**句で制御する方式をとれば、ポリシー設計する量を削減でき、かつ今後のユーザー数の増加にも対応可能となる。
参考：[AWS グローバル条件コンテキストキー](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_condition-keys.html)

例えば、以下の例ではEC2のリソースタグとして部署を示す**Department**タグに記述された内容と、ユーザーのプリンシパルに付与されたタグの内容が一致した場合のみ電源の制御を可能にする。
```json:EC2に付与されたリソースタグとユーザーのプリンシパルタグの内容が一致したもののみ対象とするアイデンティティベースのポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ec2:StartInstances",
                "ec2:StopInstances",
                "ec2:RebootInstances"
            ],
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "ec2:ResourceTag/Department": "${aws:PrincipalTag/Department}"
                }
            }
        }
    ]
}
```

ただし、このプリンシパルタグは**IAM**ユーザーに付与されているため、複数の**IAM**ユーザーが同一の**IAM**ロールにスイッチロールする方式であった場合には使用できない。
各**IAM**ユーザー毎に異なる**IAM**ロールを用意する場合はポリシーを統一できたとしても今後**IAM**ユーザーを追加する際に**IAM**ロールも同様に追加していくことになるため、一長一短となる。

<!-- ================================================= -->
# IAMユーザーログインからの移行
<!-- ================================================= -->
**AWS Organizations**で複数のアカウントを管理する場合、ベストプラクティスとしては特定の1つのアカウント(便宜上、ログインアカウントと称する)上に**IAM**ユーザーを作成し、各アカウントへは**IAM**ロールでのスイッチロールで実現することになる。

ここで、**IAM**ユーザーで認証情報を管理していた状態から**Identity Center**で**SSO**ログインへ移行する場合、大きく以下の2パターンを検討する必要がある。

1. **スイッチロール方式**
 ログインアカウントに対してのみ**Identity Center**でのログインを許可(プロビジョニング)し、本来作業したいアカウントへは今まで通り**IAM**ロールへスイッチロールすることで実現する
1つの**IAM**ポリシーでユーザー識別を行わない場合はユーザーグループで許可していた**sts:AssumeRole**の権限と同じ内容のものを許可セットへ置換すれば良いが、ユーザー識別する場合はユーザー毎に許可セットを作成していくことになる。
1. **直接ログイン方式**
 今までと異なり、作業したいアカウントへ直接ログインできるようにプロビジョニングを行うようにし、必要な権限ポリシーは各アカウント毎に用意するようにする。
各アカウント上に作成済の**IAM**ロールに付与されたカスタマー管理ポリシーを許可セットに割り当てることとなる。

よって、スイッチロールか直接ログインのどちらを選択すべきかは

* 前提2にあるような、ポリシー内のConditionでユーザーを識別するポリシーを記述していない場合はスイッチロール方式にメリットがある。
* 逆に、ユーザーを識別する必要がある場合は直接ログイン方式が必要となる。
* また、スイッチロール方式と直接ログイン方式は完全に排他というわけではなく、通常はスイッチロール方式を取り、特定のAWSサービスを利用する場合のみ直接ログインする方式を取る、と言った運用も取ることが可能である。

となる。

<!-- ================================================= -->
# 許可セットのプロビジョニング先を特定のアカウントに限定する方法
<!-- ================================================= -->
上記でスイッチロール方式のみを採用する場合、**AWS Identity Center**上でユーザーを許可セットに割り当てた後、ログインアカウントにプロビジョニングする必要があるが、ログインアカウント以外にプロビジョニングできるようになっていると思わぬ事故となるため、以下に**IAM**ポリシーにてプロビジョニング先のアカウントを限定する内容を記載する。

```json:許可セットを特定アカウントにのみプロビジョニング可能なように制限するポリシー
---(略)---
        {
            "Effect":"Allow",
            "Action":[
                "sso:DescribeAccountAssignment*",
                "sso:DescribeInstanceAccessControlAttributeConfiguration",
                "sso:CreateInstanceAccessControlAttributeConfiguration",
                "sso:UpdateInstanceAccessControlAttributeConfiguration",
                "sso:DescribePermissionSet*",
                "sso:DeletePermissionSet",
                "sso:UpdatePermissionSet",
                "sso:GetInlinePolicyForPermissionSet",
                "sso:GetPermissionsBoundaryForPermissionSet"
           ],
           "Resource": [
                "arn:aws:sso:::instance/*",
                "arn:aws:sso:::permissionSet/*/*"
           ]
        },
        {
            "Effect":"Allow",
            "Action":[
                "sso:CreateAccountAssignment",
                "sso:DeleteAccountAssignment",
                "sso:ProvisionPermissionSet"
           ],
           "Resource": [
                "arn:aws:sso:::account/[ログインアカウントID]",
                "arn:aws:sso:::instance/*",
                "arn:aws:sso:::permissionSet/*/*"
           ]
        },
---(略)---
```
"arn:aws:sso:::account/[ログインアカウントID]"を複数行記載することで、複数のプロビジョニング先を指定することができる。