特定のAWS SSOユーザーのみ除外するSCPポリシー例

IAMロールのARNじゃなくて、SSOユーザーのUserIdを使うよ
2021.07.14

ちゃだいん(@chazuke4649)です。

AWS Organizations環境で予防的ガードレールとしてSCPを利用する際に、特定のAWS SSOユーザーを制限から除外したいケースがあります。

例えば「基本的にAWS SSOでユーザー管理を行うので、IAMユーザーを作成できないようにSCPでIAMユーザー作成を禁止したい。ただし、一部の管理者だけ除外したい。」といったパターンなどが挙げられます。

うまくいかない方法

これを行う際に、最初に考えたのはAWS SSOによってユーザーアカウントに自動生成されるIAMロール(SSOユーザーの実体)のARNを使うことでした。ARNを条件キーで指定するのはよくあるパターンです。

しかしながら、このパターンだと、ユーザーアカウントが複数ある場合、IAMロールも各ユーザーアカウントごとに作成されるため、指定するIAMロールのARNがどんどん増えていきます。例えばSSOユーザーTesyama TestaroがOU配下の10ユーザーアカウントでSCPから除外したい場合、SCP自体は1つでOKかもしれませんが、条件キー部分にIAMロールのARNを10個記述することになります。管理が大変です。

さらに、よくよく考えてみると、このユーザーアカウントのIAMロールは正確には「アクセス権限セット」の実体です。IAMロールを指定してしまうとTesyama Testaroではない別のSSOユーザーが同じ「アクセス権限セット」を利用する場合、意図せずその別のSSOユーザーも除外されてしまうことになります。除外の対象はIAMロール(=アクセス権限セット)でなくSSOユーザーにすべきです。

この辺り、テキストだけではなんのこっちゃだと思うので、ぜひ以下ブログでAWS SSOの構成をつかんでください。

AWS SSOを図解してみた | DevelopersIO

解決方法

ではどうすればSSOユーザーを指定できるのでしょうか?

答えは、AWS SSOIAMポリシーの条件キーでAWS SSOユーザーの UserId を指定することです。

要は飛び先のIAMロールでなく、元々SSO IDストア側で持つユーザーを一意に識別するIDを、IAM条件キーに使用できます。

Using predefined attributes from the AWS SSO identity store for access control in AWS - AWS Single Sign-On

上記ドキュメントに記載のサンプルがこちらです。本サンプルは「のSSOユーザーのみ、GetObjectなどを許可するS3バケットポリシー」です。

{
  "Version":"2012-10-17",
  "Statement":[
    {
      
      "Effect":"Allow",
      "Principal": "*",
      "Action":["s3:GetObject","s3:GetObjectVersion"],
      "Resource":["arn:aws:s3:::mybucket/*"],
      "Condition": {
      "StringEquals": {
                    "identitystore:UserId": [
                        "<UserId>"
                    ]
                },
       "Null": {
                "identitystore:UserId": "false"
      }
    }
  ]
}

やってみる

前提条件

以下サービス・リソースは既に完了済みとなります。

  • AWS Organizationsを作成し、ユーザーアカウントを発行
  • AWS SSOを有効化
  • SSOユーザーを作成

1.UserIdの取得

事前作成したSSOユーザーを Tesyama Testaroとします。UserIdは各ユーザーの詳細画面で確認できるので、これをメモします。

2.SCPに設定

今回SCPとしては冒頭の事例のように「原則IAMユーザーの作成・削除などを禁止するが、特定のSSOユーザーのみ除外するSCP」を設定したいと思います。

先述の条件キーの記述と組み合わせると以下のようになります。

DenyCreateIAMUserExceptAdmin.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyCreateUser",
      "Effect": "Deny",
      "Action": [
        "iam:CreateUser",
        "iam:DeleteUser",
        "iam:CreateLoginProfile",
        "iam:CreateAccessKey"
      ],
      "Resource": [
        "*"
      ],
      "Condition": {
        "StringNotEquals": {
          "identitystore:UserId": [
            "95671e64ee-0654e2f1-85fe-xxxxxxxxxxxxxxxxxxxxxxx"
          ]
        },
        "Null": {
          "identitystore:UserId": "false"
        }
      }
    }
  ]
}

※UseId箇所はダミーです

こちらのSCPを対象のOUに設定します。

2021.9.2追記: 上記ポリシーだと一部不具合があったので、下記新しいポリシーの使用を推奨します。変更理由は後述します。

DenyCreateIAMUserExceptAdminPt2.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyCreateUser",
      "Effect": "Deny",
      "Action": [
        "iam:CreateUser",
        "iam:DeleteUser",
        "iam:CreateLoginProfile",
        "iam:CreateAccessKey"
      ],
      "Resource": [
        "*"
      ],
      "Condition": {
        "StringNotEqualsIfExists": {
          "identitystore:UserId": [
            "95671e64ee-0654e2f1-85fe-xxxxxxxxxxxxxxxxxxxxxxx"
          ]
        }
      }
    }
  ]
}

※UseId箇所はダミーです

変更理由

元のポリシーだと、Conditionで判定しているキーidentitystore:UserIdをエンティティが保有してない場合(例:IAMユーザーなど)、結果はFalseとなり、Deny文が効かなくなります。 そこで今回 StringNotEqualsIfExistsに変更し、Null文を削除しました。これによってキーがない場合はTrueになり、Deny文が効きます。

詳細は以下ブログをご参考ください。(該当箇所を以下引用してます)

キーが無いときに備えてどう対処するか? 条件キーの場合 指定したキーが無いときに 「trueとしたいか」、「falseとしたいか」 ポリシー設計段階で決めましょう。 「trueとしたい」 場合は IfExists を活用します。 (Nullを除く) 全ての条件演算子の末尾に付けることができます。 キーが存在しない場合に 条件要素は true として評価されます 。 「falseとしたい」 場合は Null 条件演算子 を使った条件を 明示的に追加 しましょう。

3.動作検証(UserIdを除外しない)

検証するために、先述のSCPと別に条件キーのない「有無を言わさずIAMユーザー作成を禁止するSCP」を作成しています。

DenyCreateIAMUser.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyCreateUser",
      "Effect": "Deny",
      "Action": [
        "iam:CreateUser",
        "iam:DeleteUser",
        "iam:CreateLoginProfile",
        "iam:CreateAccessKey"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}

これをOUにアタッチし、先述のAdministratorAcess権限のあるTesyama TestaroSSOユーザーで対象ユーザーアカウントにアクセスします。

適当なIAMユーザーtempuser2を作成しようとしたところ、以下の通りエラーが出ました。

4.動作検証(UserIdを除外する)

それでは次に、SCPDenyCreateIAMUser.jsonをデタッチして、SCPDenyCreateIAMUserExceptAdmin.jsonをアタッチします。

そして、再度同じようにIAMユーザーを作成しようと試みます。

すると以下のようにIAMユーザーを作成することができました。

終わりに

OrganizationsやAWS SSOを活用しLanding Zoneライクにマルチアカウント管理を行う場合、特定のSSOユーザーのみ除外したいSCPの記述方法についてご紹介しました。AWS SSO便利ですね。ガンガン使っていきましょう!

ちなみに、AWS SSO側にはSSOユーザー以外にSSOグループがあり、こちらには GroupId があります。ただしGroupIdを条件キーで指定することは、IAMポリシーとしては未サポートです。(試したけどダメでした)

それではこの辺で。ちゃだいん(@chazuke4649)でした。