duyne

    Allowing a Role to Assume Another Role

    • aws
    • iam
    • assume-role
    • security

    Overview

    When working with AWS IAM, you may need to configure one IAM Role to assume another IAM Role. This is a common pattern for implementing the principle of least privilege and enabling cross-account access.

    What You'll Learn

    • Same Account: Role to Role AssumeRole
    • Cross-Account: Role to Role AssumeRole

    Important: The configuration method differs depending on whether the two IAM Roles are in the same AWS account or in different AWS accounts.

    flowchart TB
        subgraph Overview[IAM Role to Role AssumeRole Overview]
            direction TB
            subgraph SameAccount[Same Account Scenario]
                direction LR
                RoleA1[Role A<br/>Source Role] -->|1. Trust Relationship<br/>on Role B| RoleB1[Role B<br/>Target Role]
                RoleA1 -.->|2. Auto Permission<br/>No Policy Needed| RoleB1
            end
            
            subgraph CrossAccount[Cross-Account Scenario]
                direction LR
                Account1[Account 111111111111<br/>Source Account]
                Account2[Account 222222222222<br/>Target Account]
                
                RoleA2[Role A<br/>Source Role] -->|1. Trust Relationship<br/>on Role B| RoleB2[Role B<br/>Target Role]
                RoleA2 -->|2. sts:AssumeRole Policy<br/>Required on Role A| RoleB2
                
                Account1 --> RoleA2
                Account2 --> RoleB2
            end
        end
        
        style Overview fill:#fff,stroke:#000,stroke-width:2px
        style SameAccount fill:#fff,stroke:#000,stroke-width:1px
        style CrossAccount fill:#fff,stroke:#000,stroke-width:1px
        style RoleA1 fill:#fff,stroke:#000,stroke-width:1px
        style RoleB1 fill:#fff,stroke:#000,stroke-width:1px
        style RoleA2 fill:#fff,stroke:#000,stroke-width:1px
        style RoleB2 fill:#fff,stroke:#000,stroke-width:1px
        style Account1 fill:#fff,stroke:#000,stroke-width:1px
        style Account2 fill:#fff,stroke:#000,stroke-width:1px

    Same Account: Role to Role AssumeRole

    When both IAM Roles exist in the same AWS account, the configuration is straightforward.

    Scenario

    Let's assume we have two IAM Roles:

    • Role A: The role that will perform the AssumeRole action
    • Role B: The role that will be assumed

    Both roles are in the same AWS account (e.g., account 111111111111).

    flowchart LR
        subgraph SameAccountArch[Same Account Architecture]
            direction LR
            subgraph Account[Account 111111111111]
                direction TB
                RoleA[Role A<br/>Source Role<br/>Performs AssumeRole]
                RoleB[Role B<br/>Target Role<br/>Gets Assumed]
                
                RoleA -->|sts:AssumeRole| RoleB
            end
            
            TrustPolicy[Trust Relationship<br/>on Role B<br/>Principal: Role A]
            RoleB -.->|Configure| TrustPolicy
        end
        
        style SameAccountArch fill:#fff,stroke:#000,stroke-width:2px
        style Account fill:#fff,stroke:#000,stroke-width:1px
        style RoleA fill:#fff,stroke:#000,stroke-width:1px
        style RoleB fill:#fff,stroke:#000,stroke-width:1px
        style TrustPolicy fill:#fff,stroke:#000,stroke-width:1px

    Configuration

    To allow Role A to assume Role B, you only need to modify the Trust Relationship (Trust Policy) of Role B.

    Step 1: Update Role B's Trust Relationship

    Edit Role B's Trust Relationship policy to include Role A as a trusted principal:

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

    Key Points:

    • The Principal element specifies which IAM Role is allowed to assume this role
    • Use the full ARN of Role A: arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME
    • The Action must be sts:AssumeRole

    Step 2: Verify Role A Has AssumeRole Permission

    In the same account scenario, Role A automatically has permission to call sts:AssumeRole on Role B once the Trust Relationship is configured. No additional policy is required on Role A.

    Understanding the Principal Element

    The Principal element in a Trust Relationship policy is used to specify which entities (IAM Users, IAM Roles, AWS Services, or other AWS resources) are allowed to assume the role.

    For more detailed information about the Principal element, refer to the AWS IAM documentation.

    Cross-Account: Role to Role AssumeRole

    When the two IAM Roles are in different AWS accounts, the configuration requires an additional step.

    Scenario

    Let's assume:

    • Role A: Exists in AWS account 111111111111 (source account)
    • Role B: Exists in AWS account 222222222222 (target account)

    Role A needs to assume Role B across accounts.

    flowchart TB
        subgraph CrossAccountArch[Cross-Account Architecture]
            direction TB
            subgraph SourceAccount[Account 111111111111<br/>Source Account]
                direction TB
                RoleA[Role A<br/>Source Role]
                PolicyA[Permissions Policy<br/>sts:AssumeRole<br/>Resource: Role B ARN]
                RoleA -.->|Requires| PolicyA
            end
            
            subgraph TargetAccount[Account 222222222222<br/>Target Account]
                direction TB
                RoleB[Role B<br/>Target Role]
                TrustPolicy[Trust Relationship<br/>Principal: Role A ARN<br/>Action: sts:AssumeRole]
                RoleB -.->|Requires| TrustPolicy
            end
            
            RoleA -->|1. Check Policy| PolicyA
            PolicyA -->|2. AssumeRole Request| RoleB
            RoleB -->|3. Check Trust Relationship| TrustPolicy
            TrustPolicy -->|4. Grant Access| RoleB
        end
        
        style CrossAccountArch fill:#fff,stroke:#000,stroke-width:2px
        style SourceAccount fill:#fff,stroke:#000,stroke-width:1px
        style TargetAccount fill:#fff,stroke:#000,stroke-width:1px
        style RoleA fill:#fff,stroke:#000,stroke-width:1px
        style RoleB fill:#fff,stroke:#000,stroke-width:1px
        style PolicyA fill:#fff,stroke:#000,stroke-width:1px
        style TrustPolicy fill:#fff,stroke:#000,stroke-width:1px

    Configuration

    For cross-account AssumeRole, you need to configure both roles:

    Step 1: Update Role B's Trust Relationship (Target Account)

    Edit Role B's Trust Relationship policy in account 222222222222:

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

    Note: The Trust Relationship configuration is identical to the same-account scenario. The difference is that the ARN points to a role in a different account.

    Step 2: Add AssumeRole Policy to Role A (Source Account)

    This is the critical difference! Role A must have an IAM policy that explicitly allows it to assume Role B.

    Add the following policy to Role A in account 111111111111:

    {
      "Version": "2012-10-17",
      "Statement": {
        "Effect": "Allow",
        "Action": "sts:AssumeRole",
        "Resource": "arn:aws:iam::222222222222:role/Role_B"
      }
    }

    Key Points:

    • The Action is sts:AssumeRole
    • The Resource must be the full ARN of Role B in the target account
    • This policy grants Role A permission to perform the AssumeRole operation

    Why the Additional Policy is Required

    In cross-account scenarios, AWS requires explicit permission on the source role (Role A) to assume roles in other accounts. This is a security measure to prevent unauthorized cross-account access.

    Complete Example: Cross-Account Setup

    Here's a complete example showing both configurations:

    flowchart TB
        subgraph CompleteExample[Complete Cross-Account Example]
            direction TB
            subgraph SourceAcc[Account 111111111111 - Source]
                direction TB
                EC2Service[EC2 Service<br/>Can Assume Role A]
                RoleA[Role A]
                RoleATrust[Role A Trust Relationship<br/>Principal: ec2.amazonaws.com]
                RoleAPolicy[Role A Permissions Policy<br/>Action: sts:AssumeRole<br/>Resource: Role B ARN]
                
                EC2Service -->|Assumes| RoleA
                RoleA -.->|Has| RoleATrust
                RoleA -.->|Has| RoleAPolicy
            end
            
            subgraph TargetAcc[Account 222222222222 - Target]
                direction TB
                RoleB[Role B]
                RoleBTrust[Role B Trust Relationship<br/>Principal: Role A ARN<br/>Action: sts:AssumeRole]
                RoleBPolicy[Role B Permissions Policy<br/>Action: s3:GetObject<br/>Resource: s3://example-bucket/*]
                
                RoleB -.->|Has| RoleBTrust
                RoleB -.->|Has| RoleBPolicy
            end
            
            RoleA -->|1. AssumeRole Request| RoleB
            RoleB -->|2. Access S3 Resources| S3Bucket[S3 Bucket<br/>example-bucket]
        end
        
        style CompleteExample fill:#fff,stroke:#000,stroke-width:2px
        style SourceAcc fill:#fff,stroke:#000,stroke-width:1px
        style TargetAcc fill:#fff,stroke:#000,stroke-width:1px
        style EC2Service fill:#fff,stroke:#000,stroke-width:1px
        style RoleA fill:#fff,stroke:#000,stroke-width:1px
        style RoleB fill:#fff,stroke:#000,stroke-width:1px
        style RoleATrust fill:#fff,stroke:#000,stroke-width:1px
        style RoleAPolicy fill:#fff,stroke:#000,stroke-width:1px
        style RoleBTrust fill:#fff,stroke:#000,stroke-width:1px
        style RoleBPolicy fill:#fff,stroke:#000,stroke-width:1px
        style S3Bucket fill:#fff,stroke:#000,stroke-width:1px

    Account 111111111111 (Source Account)

    Role A - Trust Relationship:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Service": "ec2.amazonaws.com"
          },
          "Action": "sts:AssumeRole"
        }
      ]
    }

    Role A - Permissions Policy:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": "sts:AssumeRole",
          "Resource": "arn:aws:iam::222222222222:role/Role_B"
        }
      ]
    }

    Account 222222222222 (Target Account)

    Role B - Trust Relationship:

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

    Role B - Permissions Policy:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": "s3:GetObject",
          "Resource": "arn:aws:s3:::example-bucket/*"
        }
      ]
    }

    Best Practices

    1. Use External IDs for Cross-Account: Add an ExternalId condition to the Trust Relationship for additional security:

      {
        "Condition": {
          "StringEquals": {
            "sts:ExternalId": "unique-external-id-here"
          }
        }
      }
    2. Principle of Least Privilege: Grant only the minimum permissions required in the assumed role's policy

    3. Use Session Duration: Set appropriate session duration limits:

      {
        "Action": "sts:AssumeRole",
        "Condition": {
          "NumericLessThan": {
            "aws:RequestedRegion": "3600"
          }
        }
      }
    4. Monitor AssumeRole Calls: Enable CloudTrail to audit all AssumeRole operations

    5. Use IAM Paths: Organize roles using IAM paths for better management:

      arn:aws:iam::111111111111:role/production/app/Role_A

    Conclusion

    Configuring IAM Role to Role AssumeRole is a powerful feature for implementing secure, cross-account access patterns. The key difference between same-account and cross-account scenarios is:

    • Same Account: Only requires Trust Relationship configuration on the target role
    • Cross-Account: Requires both Trust Relationship on target role AND sts:AssumeRole policy on source role

    Understanding this distinction is crucial for troubleshooting access issues and implementing secure IAM architectures.

    References