[アップデート] IAMロールセッション名にユーザー名を強制できる条件 sts:RoleSessionName が使えるようになりました

2020.05.05

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

IAMロールの信頼ポリシーにて、新たに Conditon key として sts:RoleSessionName を設定できるようになりました。

IAM ロールを使用して実行されたアクションを担当する ID を簡単に特定

それによって、 例えばIAMロールを使用するクロスアカウント元のIAMユーザーに対し、ロールセッション名にIAMユーザー名の使用を強制することができます。

今まで「CloudTrailでアクションの実行者調べようと思ったら、クロスアカウントのユーザー名が任意のロールセッション名で誰か判別つかなくて困るよ〜」って経験がある人は大喜びだと思います。

何が嬉しいの?(詳しく)

まず、登場する2つのアカウントを以下とします。

  • アカウント1: [111111111111] クロスアカウントされる側のアカウント(IAMロールと対象リソースがある方)
  • アカウント2: [222222222222] クロスアカウントする側のアカウント(IAMユーザーがいる方)

今まで

外部アカウント[222222222222]用のIAMロールを用意する場合、ロールセッション名に対し何かルールを設けることはできませんでした。つまりそれを使用するユーザー側が、ロールセッション名を自由に付けてOKです。

ただし、これは管理者としては少し厄介でした。IAMロールを使用したアクションの実行者が誰なのか判別しづらいからです。具体的には、IAMロールの信頼されたエンティティがアカウント単位なのかユーザー単位なのかで若干下記のように異なります。

信頼されたエンティティがアカウント単位arn:aws:iam::222222222222:rootの場合、
このロールは、222222222222側で許可されている不特定多数のユーザーが使用できます。
このロールでロールセッション名が任意だった場合、111111111111側のCloudTrailで222222222222の誰が実行したのかわかりません。

信頼されたエンティティがユーザー単位arn:aws:iam::222222222222:user/user-nameの場合、
このロールは、222222222222側のuser-nameという特定のIAMユーザーしか使用できません。
このロールでロールセッション名が任意だった場合、111111111111側のCloudTrailで222222222222の誰が実行したかはわかるっちゃわかります。でもわかりづらいです。すでに特定のIAMユーザー単位に使用を制限しているので、ロールセッション名が何であれそのIAMユーザーだろうと判別がつくという意味です。ただCloudTrailで調査する際は、調べやすくはありません。

これから

例えばIAMロールを使用するクロスアカウント元のIAMユーザーに対し、ロールセッション名にIAMユーザー名の使用を強制することができます。
これによって、111111111111側の管理者は、上記どちらのロールでも222222222222側のどのユーザーがどのアクションを実行したか簡単にわかるようになります。

それでは早速試してみましょう!

概要

登場人物は以下の通りです。

  • アカウント1: [111111111111] クロスアカウントされる側のアカウント
  • アカウント1のRoleSessionName未反映IAMロール: TestEC2FullRoleForOtherAccount1
  • アカウント1のRoleSessionName反映済みIAMロール: TestEC2FullRoleForOtherAccount2
  • アカウント1のEC2インスタンス: i-042b5a25a68eb455b
  • アカウント2: [222222222222] クロスアカウントする側のアカウント
  • アカウント2のIAMユーザー: test-admin

アカウント2のユーザーtest-adminが、アカウント1のそれぞれのロールを使用し、アカウント1のEC2を操作します。

1. IAMロールを2つ作成する

RoleSessionName未反映のIAMロール

特別何かをすることなく、信頼されたエンティティをアカウント単位で設定しています。 信頼ポリシーは以下の通りです。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::222222222222:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {}
    }
  ]
}

コンソール画面は以下の通りです。

RoleSessionName設定済みのIAMロール

こちらは、下記ドキュメントを参考に、条件の部分にRoleSessionNameを使用します。

IAM and AWS STS Condition Context Keys - AWS Identity and Access Management

ドキュメントに従い、RoleSessionNameとIAMユーザー名がイコールでないと、AssumeRoleできない条件にします。 信頼ポリシーは以下の通りです。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::222222222222:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringLike": {
          "sts:RoleSessionName": "${aws:username}"
        }
      }
    }
  ]
}

コンソール画面では、右下にconditionsが設定されてることが表示されていますね。

2. RoleSessionName未設定のIAMロールの場合

未設定のロールを使用してEC2を操作します。
   IAMユーザーの名前はtest-adminですが、ロールセッション名を適当にunknown-user-nameと付けて、aws sts assume-roleを実行します。

問題なく実行できました。

ROLE_ARN='arn:aws:iam::111111111111:role/TestEC2FullRoleForOtherAccount1'
SOURCE_PROFILE='default'
USER_NAME='unknown-user-name'

aws sts assume-role \
--profile ${SOURCE_PROFILE} \
--role-arn ${ROLE_ARN} \
--role-session-name ${USER_NAME} \
--duration-second   3600 \
>
{
    "Credentials": {
        "AccessKeyId": "EXAMPLEEEEEEEEEEEEE",
        "SecretAccessKey": "EXAMPLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE",
        "SessionToken": "EXAMPLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE",
        "Expiration": "2020-05-05T08:21:55+00:00"
    },
    "AssumedRoleUser": {
        "AssumedRoleId": "AROA2UJCVL7Q4EXAMPLE:unknown-user-name",
        "Arn": "arn:aws:sts::111111111111:assumed-role/TestEC2FullRoleForOtherAccount1/unknown-user-name"
    }
}

これにより発行された一時的認証情報を環境変数に登録します。
登録後、改めて今使用している権限は何なのかaws sts get-caller-identiyで確認すると、一時的認証のユーザー名はunknown-user-nameになっていることがわかります。

% aws sts get-caller-identity
{
    "UserId": "AROA2UJCVL7Q4EXAMPLE:unknown-user-name",
    "Account": "111111111111",
    "Arn": "arn:aws:sts::111111111111:assumed-role/TestEC2FullRoleForOtherAccount1/unknown-user-name"
}

この権限で、事前に起動させていたEC2を停止します。

aws ec2 stop-instances --instance-ids i-042b5a25a68eb455b
{
    "StoppingInstances": [
        {
            "CurrentState": {
                "Code": 64,
                "Name": "stopping"
            },
            "InstanceId": "i-042b5a25a68eb455b",
            "PreviousState": {
                "Code": 16,
                "Name": "running"
            }
        }
    ]
}

少し時間を開けて、CloudTrailのイベント履歴をみてみると、今回のアクティビティがキャプチャされてました。 ご覧の通り、ユーザー名が、任意のロールセッション名であるため、管理者としてはこのアクションの実行者が誰なのか判別できません。

3. RoleSessionName設定済みのIAMロールの場合

今度はロールセッション名にIAMユーザー名の登録を条件づけたIAMロールを使用してみます。 先ほどと同じように、ロールセッション名をunknown-user-nameで実行したところ、ちゃんとエラーになりました。

ROLE_ARN='arn:aws:iam::111111111111:role/TestEC2FullRoleForOtherAccount2'
SOURCE_PROFILE='default'
USER_NAME='unknown-user-name'

aws sts assume-role \
--profile ${SOURCE_PROFILE} \
--role-arn ${ROLE_ARN} \
--role-session-name ${USER_NAME} \
--duration-second   3600 \
>
An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:iam::222222222222:user/test-admin is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::111111111111:role/TestEC2FullRoleForOtherAccount2

では、ロールセッション名にIAMユーザー名を入れてみると、今度は実行できました。

ROLE_ARN='arn:aws:iam::111111111111:role/TestEC2FullRoleForOtherAccount2'
SOURCE_PROFILE='default'
USER_NAME='test-admin'

aws sts assume-role \
--profile ${SOURCE_PROFILE} \
--role-arn ${ROLE_ARN} \
--role-session-name ${USER_NAME} \
--duration-second   3600
{
    "Credentials": {
        "AccessKeyId": "EXAMPLEEEEEEEEEEEEE",
        "SecretAccessKey": "EXAMPLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE",
        "SessionToken": "EXAMPLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE",
        "Expiration": "2020-05-05T07:25:12+00:00"
    },
    "AssumedRoleUser": {
        "AssumedRoleId": "AROA2UJCVL7QYEXAMPLE:test-admin",
        "Arn": "arn:aws:sts::111111111111:assumed-role/TestEC2FullRoleForOtherAccount2/test-admin"
    }
}

環境変数に登録後、同じように現在の一時認証情報のユーザー名を確認すると、IAMユーザー名と同じになっていました。

aws sts get-caller-identity
{
    "UserId": "AROA2UJCVL7QYEXAMPLE:test-admin",
    "Account": "111111111111",
    "Arn": "arn:aws:sts::111111111111:assumed-role/TestEC2FullRoleForOtherAccount2/test-admin"
}

さっき停止したEC2を起動してみます。

aws ec2 start-instances --instance-ids i-042b5a25a68eb455b
{
    "StartingInstances": [
        {
            "CurrentState": {
                "Code": 0,
                "Name": "pending"
            },
            "InstanceId": "i-042b5a25a68eb455b",
            "PreviousState": {
                "Code": 80,
                "Name": "stopped"
            }
        }
    ]
}

少し時間をおくと、CloudTrailイベント履歴にアクティビティがキャプチャされてました。 ユーザー名をtest-adminで絞ってみます。

StartInstancesのログが出てきました。ご覧の通り、ユーザー名にIAMユーザー名が使用されています。

これなら、このアクションが誰によるものなのか、管理者はすぐに判断できますね。

(おまけ)コンソールでスイッチロールした場合はどうなるの?

結論としては、どちらのロールでも問題なくスイッチでき、アクションを実行できました。 また、そのアクションをCloudTrailで調べると、どちらもユーザー名にIAMユーザー名が使用されていました。

つまり今回の条件の設定によるコンソールでのスイッチロールに影響はなく、かつちゃんとIAMユーザー名が使用されているので安心ということです。

よって、今回のアップデートは、CLIやSDKレベルのアクション時の匿名性回避に役立つものだと理解しました。

終わりに

今回のアップデートは、クロスアカウントが行われる環境下でのアクション実行者特定につながる管理者としては嬉しいアップデートだったのではないでしょうか。 CloudTrailによる追跡をより完璧なものにするために、ぜひ利用を検討してみてください。

1点注意事項としては、実施にあたりクロスアカウントするユーザー側に、ロールセッション名へIAMユーザー名を登録しないとAssumeRoleできなくなる旨を周知する必要があります。その点お忘れなく。

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