aws-cloudformationamazon-iamrace-conditionsamaws-roles

Race Condition When Creating Self-Assuming IAM Role in CloudFormation


I'm facing a race condition when creating an IAM role in AWS CloudFormation that has a trust policy allowing it to assume itself (sts:AssumeRole). The issue arises because the role needs to reference its own ARN in the AssumeRolePolicyDocument, but CloudFormation tries to resolve this before the role has been fully created, leading to a circular dependency and a race condition.

Problem: In my CloudFormation template, I'm defining an IAM role with a trust policy that allows the role to assume itself:

MyNewRole:
  Type: AWS::IAM::Role
  Properties:
    RoleName: my-new-role
    AssumeRolePolicyDocument:
      Version: "2012-10-17"
      Statement:
        - Effect: Allow
          Principal:
            AWS: arn:aws:iam::<account-id>:role/my-new-role
          Action: sts:AssumeRole

However, I'm encountering the following error:

Invalid principal in policy: "AWS":"arn:aws:iam::<account-id>:role/my-new-role" (Service: Iam, Status Code: 400)

This error indicates that the role is being referenced in the trust policy before it actually exists, causing a race condition.

Question:

How can I handle this race condition in CloudFormation, where an IAM role needs to assume itself? Are there ways to delay or update the trust policy after the role is created, or are there better approaches to solve this issue?

What I've Tried:

  1. Using Fn::Sub to dynamically reference the role's ARN within the same template, but this still results in the race condition.
  2. Exploring the AWS blog update on IAM role trust policy behavior, but I'm unsure how to apply it in this context.
  3. Considering a Lambda-backed custom resource, but would prefer a pure CloudFormation solution if possible.

Any guidance on resolving this race condition would be appreciated!


Solution

  • This solution allows you to filter what can assume the role using a condition instead of specifying the "Principal" explicitly.

    Note: this may trigger Security warnings since it looks like it allows "*"

    MyNewRole:
      Type: AWS::IAM::Role
      Properties:
        RoleName: my-new-role
        AssumeRolePolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Principal:
                AWS: '*'
              Action: sts:AssumeRole
              Condition:
                StringLike:
                  aws:PrincipalArn: !Sub arn:aws:iam::${AWS::AccountId}:role/my-new-role