IAMロール再作成の落とし穴:信頼関係ポリシーのプリンシパルIDが変わるとスイッチロールができなくなる問題

IAMロール再作成の落とし穴:信頼関係ポリシーのプリンシパルIDが変わるとスイッチロールができなくなる問題

Clock Icon2025.03.31

あしざわです。

IaCで管理しているIAMロールを削除した後、同じIaCテンプレートで再デプロイしたら元々できていたはずの他のAWSアカウントへのスイッチロールが急にできなくなってしまった。スイッチ先のIAMロールは変更していないのに。

そんな経験したことがある方はいませんか?

その原因はプリンシパルIDの違いにあるかもしれません。

本記事では、そんな事象を解説・検証します。

概要

同じ設定のIAMロールを作成し直しただけなのに、なぜ以前までできていたスイッチロールができなくなってしまったのでしょうか?

前述した図に表すとこのようになります。

image.png

原因は、IAMロールの信頼関係ポリシーの仕様にあります。

ここでいう信頼関係ポリシーは、スイッチ先のIAMロール(target-iam-role)の「信頼されたエンティティ」のことを指します。

このように特定のIAMリソースをPrincipalに設定し、sts:Assumeのアクションのみを許可するJSON定義です。見覚えがある方も多いと思います。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:role/sample-role"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

ここまでを図にしてみました。

image.png

信頼関係ポリシーの中の更に1つの要素、Principalの仕様に「特定の IAM ロール/ユーザーを指し示す ARN が含まれている場合、その ARN をポリシーに保存するときに、IAM がロール/ユーザーの一意のプリンシパル ID に変換」する、というものがあります。

つまり、見た目上はARNの形式でPrincipalを設定しているように見えますが、実際は一意のプリンシパルIDに変換・設定されている のです。

本件は、AWS公式ドキュメントの以下箇所にそれぞれ記載があります。
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements_principal.html#principal-roles
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements_principal.html#principal-users

AWS公式ドキュメントでは、プリンシパルIDについて個別にまとまったページは見つからなかったのですが、そのARNがどちらのIAMリソースなのかによってどんなプリンシパルIDに変換されるか異なるようです。

  • (IAMユーザーの場合)AIDAで始まる文字列
  • (IAMロールの場合)AROAで始まる文字列(?確認中)

参考:IAM ロールの「信頼されたエンティティ」に覚えのない IAM ユーザー ID が設定されている場合の対処法 | DevelopersIO

ここまでを図に表すと以下のようになります。

image.png

以上のような背景から、同じ名前・同じ設定でIAMロールを再作成しているように見えても、プリンシパルIDの差異によってスイッチロールが失敗してしまっているわけです。

ここまでで主題の件についてはよく理解できたかと思います。以降のセクションでは実際に手を動かして事象を確認してみます。

検証してみる

以下のロールを作成しました。

  • スイッチ元IAMロール(source-iam-role)
    • 信頼関係ポリシーで任意のIAMユーザーからのsts:AssumeRoleを許可
    • AWS管理ポリシーのReadOnlyAccessをアタッチ
    • インラインポリシーで、スイッチ先IAMロール(target-iam-role)のsts:AssumeRoleを許可
  • スイッチ先IAMロール(target-iam-role)
    • 信頼関係ポリシーで、スイッチ元IAMロール(source-iam-role)のsts:AssumeRoleを許可
    • AWS管理ポリシーのReadOnlyAccessをアタッチ

作成時に利用したCloudFormationテンプレートはこちらです。

スイッチ元IAMロール(source-iam-role)
AWSTemplateFormatVersion: '2010-09-09'
Description: 'CloudFormation template to create IAM role with parameterized trust and inline policies'

Parameters:
  SwitchAccountId:
    Type: String
    Description: 'AWS Account ID for the trust policy (account containing the user that can assume this role)'
    AllowedPattern: '^[0-9]{12}$'
    ConstraintDescription: 'Must be a valid 12-digit AWS account ID'

  TargetAccountId:
    Type: String
    Description: 'AWS Account ID for the inline policy (account containing the target role that can be assumed)'
    AllowedPattern: '^[0-9]{12}$'
    ConstraintDescription: 'Must be a valid 12-digit AWS account ID'

  UserName:
    Type: String
    Description: 'Name of the IAM user that can assume this role'
    Default: 'cm-ashizawa.hiroaki'

  TargetRoleName:
    Type: String
    Description: 'Name of the target role that can be assumed'
    Default: 'target-iam-role'

Resources:
  SourceIAMRole:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: 'source-iam-role'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: 'Allow'
            Principal:
              AWS: !Sub 'arn:aws:iam::${SwitchAccountId}:user/${UserName}'
            Action: 'sts:AssumeRole'
            Condition:
              Bool:
                'aws:MultiFactorAuthPresent': 'true'
      ManagedPolicyArns:
      - 'arn:aws:iam::aws:policy/ReadOnlyAccess'
      Policies:
        - PolicyName: 'AssumeTargetRolePolicy'
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: 'Allow'
                Action: 'sts:AssumeRole'
                Resource: !Sub 'arn:aws:iam::${TargetAccountId}:role/${TargetRoleName}'

Outputs:
  RoleARN:
    Description: 'ARN of the created IAM role'
    Value: !GetAtt SourceIAMRole.Arn
  RoleName:
    Description: 'Name of the created IAM role'
    Value: !Ref SourceIAMRole
スイッチ先IAMロール(target-iam-role)
AWSTemplateFormatVersion: '2010-09-09'
Description: 'CloudFormation template to create target IAM role'

Parameters:
  SourceAccountId:
    Type: String
    Description: 'AWS Account ID where the source-iam-role exists'
    AllowedPattern: '^[0-9]{12}$'
    ConstraintDescription: 'Must be a valid 12-digit AWS account ID'

  SourceRoleName:
    Type: String
    Description: 'Name of the source IAM role that can assume this role'
    Default: 'source-iam-role'

Resources:
  TargetIAMRole:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: 'target-iam-role'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: 'Allow'
            Principal:
              AWS: !Sub 'arn:aws:iam::${SourceAccountId}:role/${SourceRoleName}'
            Action: 'sts:AssumeRole'
      ManagedPolicyArns:
      - 'arn:aws:iam::aws:policy/ReadOnlyAccess'

Outputs:
  RoleARN:
    Description: 'ARN of the created target IAM role'
    Value: !GetAtt TargetIAMRole.Arn
  RoleName:
    Description: 'Name of the created target IAM role'
    Value: !Ref TargetIAMRole```

2つのIAMロールは同じAWSアカウント上に作成しても、異なるAWSアカウント上に作ってもどちらでもOKです。
今回は、同じAWSアカウントにしました。

作業前のtarget-iam-roleの信頼関係ポリシーの状態がこちらです。

image.png

(信頼関係ポリシーだけを抜粋)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:role/source-iam-role"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

以降で検証を行います。

事前に準備したsource-iam-roleにスイッチロールしておいてください。

まずはこの時点でsource-iam-roleからtarget-iam-roleへのAssumeRoleが実行できるか確認します。

以下コマンドでAssumeRoleの実行、AWSクレデンシャルの環境変数への設定までワンライナーで実行可能です。

eval $(aws sts assume-role --role-arn arn:aws:iam::123456789012:role/target-iam-role --role-session-name my-session | jq -r '.Credentials | "export AWS_ACCESS_KEY_ID=\(.AccessKeyId)\nexport AWS_SECRET_ACCESS_KEY=\(.SecretAccessKey)\nexport AWS_SESSION_TOKEN=\(.SessionToken)"')

正しくコマンドが実行できたら何も出力されません。

続いて、以下コマンドを実行して現在使用している AWS 認証情報を確認します。

aws sts get-caller-identity

以下のように、ARN欄にtarget-iam-roleが含まれているARNが表示されたら正しくスイッチロールできたことがわかります。

{
    "UserId": "AROAxxxxxxxxxxxx:my-session",
    "Account": "123456789012",
    "Arn": "arn:aws:sts::123456789012:assumed-role/target-iam-role/my-session"
}

それではsource-iam-roleを削除し、再作成しましょう。私の環境では、CloudFormationスタックの削除・再作成で実施しました。

一旦source-iam-roleにスイッチバックしてから、再度target-iam-roleへスイッチロールしてみましょう。先ほどと同じコマンドを使います。

eval $(aws sts assume-role --role-arn arn:aws:iam::123456789012:role/target-iam-role --role-session-name my-session | jq -r '.Credentials | "export AWS_ACCESS_KEY_ID=\(.AccessKeyId)\nexport AWS_SECRET_ACCESS_KEY=\(.SecretAccessKey)\nexport AWS_SESSION_TOKEN=\(.SessionToken)"')

コマンドの実行結果例がこちら。スイッチロールできなくなっていますね。

An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:sts::123456789012:assumed-role/source-iam-role is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::123456789012:role/target-iam-role

この時点でtarget-iam-roleの信頼関係ポリシーを確認すると、PrincipalがAROAで始まる文字列に置き換わっています。

image.png

この修正がCloudTrailなどの証跡として記録されていないのか気になりますよね。

Configのリソースタイムラインからtarget-iam-roleを確認してみたところ、修正されたようなイベントは見つかりませんでした。CloudTrail等に記録されないAWS InternalのAPIで修正していると思われます。

image.png

確認したtarget-iam-roleの信頼関係ポリシーを修正し、AROAの文字列をsource-iam-roleのARNに差し替えます。

私はマネジメントコンソールから修正しようとしたのですが、修正前の状態でIAMのバリデーションで警告が表示されていました。

Invalid Role Reference: Principal 要素には IAM ロール ID AROAxxxxxxxxxx が含まれています 。代わりにロール ARN を使用することをお勧めします。

image.png

ARNに差し替えたところ警告が消え、ポリシーの更新を行いました。

再度AssumeRoleのコマンドを実行すると、何も出力されないはずです。

eval $(aws sts assume-role --role-arn arn:aws:iam::123456789012:role/target-iam-role --role-session-name my-session | jq -r '.Credentials | "export AWS_ACCESS_KEY_ID=\(.AccessKeyId)\nexport AWS_SECRET_ACCESS_KEY=\(.SecretAccessKey)\nexport AWS_SESSION_TOKEN=\(.SessionToken)"')

AWS認証情報を確認するコマンドで、最初と同じ出力結果になれば、修正が完了です。

> aws sts get-caller-identity
{
    "UserId": "AROAxxxxxxxxxxxx:my-session",
    "Account": "123456789012",
    "Arn": "arn:aws:sts::123456789012:assumed-role/target-iam-role/my-session"
}

最後に

今回は「IAMロール再作成の落とし穴:信頼関係ポリシーのプリンシパルIDが変わるとスイッチロールができなくなる問題」について紹介しました。

このようなケースではIAMロールの削除によって暗黙的な信頼ポリシーの修正が行われることを覚えておくだけで、トラブルシューティングの際に役立ちそうです。

ちなみにIAMユーザーの再作成によってプリンシパルIDの置き換えが発生する件については、既にDevelopersIOブログでいくか執筆されています。

https://dev.classmethod.jp/articles/note-when-recreating-iam-user-with-the-same-name/
https://dev.classmethod.jp/articles/tsnote-iam-trusted-entity-iam-user-id-01/

IAMユーザーだけでなくIAMロールでも同じ事象が起きる、ということを改めて覚えておきましょう。

以上です。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.