AWS IAM Roles: A Guide to Cross-Account Access with Examples

Introduction

AWS IAM (Identity and Access Management) roles are the backbone of secure access control in cloud environments. However, managing cross-account IAM roles can quickly become challenging or confusing, especially if you’re missing critical permissions like sts:AssumeRole. Additionally, an incorrect or missing ExternalId can prevent roles, such as those used by third-party auditors or monitoring systems, from being assumed, as it is a key requirement for establishing cross-account trust.

This guide will walk you through common scenarios of cross-account communication, highlight potential pitfalls, and provide solutions with detailed flowcharts and examples.

Why Cross-Account IAM Roles Matter

In large organizations, production accounts are often separated by business function for security, billing, and compliance reasons. For example:

  • Analytics Account

  • Data Science Account

  • Centralized Logging Account

Cross-account IAM roles enable secure interactions across these environments, ensuring proper access control and permissions while preventing overly permissive configurations.

Real-Life Analogy: Checking into a Hotel

Think of cross-account access like checking into a hotel:

  1. Establish Trust:
    The receptionist verifies your reservation and identity.

    • In AWS, this is the trust policy ensuring the target account trusts the source account.
  2. Grant Permissions:
    You receive a key card programmed for your room.

    • In AWS, this is the sts:AssumeRole permission, allowing temporary access to the role.
  3. Access Resources:
    You use the key card to access your room and amenities.

    • In AWS, this corresponds to resource-specific permissions like accessing an S3 bucket or DynamoDB table.

This simple analogy illustrates how cross-account access works in AWS and why each step is critical.

What is a Principal?

In AWS, a Principal is an entity that can make requests to AWS services. A Principal must have permissions, either explicitly or implicitly granted, to access AWS resources.

Types of Principals in AWS

  1. IAM Users:

    • A user created within an AWS account, typically representing an individual or application.

    • Example: arn:aws:iam::123456789012:user/Alice.

  2. IAM Roles:

    • Temporary credentials associated with a specific role, allowing access to AWS resources. Roles can be assumed by users, applications, or other AWS services.

    • Example: arn:aws:iam::123456789012:role/EC2AccessRole

  3. AWS Services:

    • Services like Lambda, EC2, or ECS that need access to other AWS resources to function.

    • Example: arn:aws:iam::123456789012:role/service-role/LambdaExecutionRole.

  4. Federated Users or Applications:

    • External users authenticated by an identity provider (e.g., SAML, OpenID Connect) or by using AWS STS tokens.

    • Example: A user accessing AWS through a corporate identity provider.

Why is "Principal" Important in Cross-Account Access?

When setting up cross-account access, the first step is to identify the source Principal (the requester) and the target Principal (the resource owner). Knowing which entity assumes roles, accesses resources, and grants permissions helps clarify how AWS IAM policies and trust relationships function.

Understanding the Workflow

The core of cross-account IAM role configuration involves the following steps:

  1. Establish Trust: Make sure the target account trusts the role from the source account.

  2. Grant Permissions: Provide the necessary permissions for the source account to assume the role.

  3. Access Resources: Ensure the source account has the permissions needed to interact with resources in the target account.

Below is a flowchart illustrating the decision-making process to consider when setting up IAM roles.

Examples of Cross-Account Scenarios

Scenario 1: Analytics Account Accessing Data in Data Science Account

  • Accounts Involved:

    • Analytics Account: Runs business intelligence (BI) tools like Tableau or AWS QuickSight.

    • Data Science Account: Stores cleaned and processed data in S3 for model training.

  • Steps:

    • Add Analytics Account's IAM Role to the S3 bucket policy in Data Science Account.

        {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "AWS": "arn:aws:iam::ACCOUNT_ANALYTICS:role/BIReaderRole"
              },
              "Action": "s3:GetObject",
              "Resource": "arn:aws:s3:::data-science-bucket/*"
            }
          ]
        }
      

      The arn:aws:s3::: format for S3 ARNs is unique because S3 buckets are global resources, not account-specific. Unlike most AWS services, which include the account ID in their ARNs, S3 does not.

    • Ensure `sts:AssumeRole permission for the Analytics Account's IAM Role.

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

Scenario 2: Data Science Account Accessing Centralized Logging

  • Accounts Involved:

  • Data Science Account: Runs machine learning models that generate logs for debugging.

  • Centralized Logging Account: Collects and stores all logs in CloudWatch.

Steps:

  • Grant the Data Science Account IAM Role access to the CloudWatch Logs in Centralized Logging Account.
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::ACCOUNT_DATA_SCIENCE:role/LogWriterRole"
      },
      "Action": "logs:PutLogEvents",
      "Resource": "arn:aws:logs:region:ACCOUNT_LOGGING:log-group:/data-science-logs:*"
    }
  ]
}
  • Add sts:AssumeRole permission for the Data Science Account IAM Role.
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "sts:AssumeRole",
      "Resource": "arn:aws:iam::ACCOUNT_LOGGING:role/LogAccessRole"
    }
  ]
}

Common Pitfalls in Cross-Account Access

1. Missing sts:AssumeRole Permission:
Even with correct trust policies, access fails if this permission is not granted.

2. Misconfigured Resource Policies:
Ensure the target resource (e.g., S3 bucket or RDS) explicitly allows the requesting account.

3. Incorrect Role ARN:
Double-check ARNs in all trust and IAM policies to prevent mismatched configurations.

Conclusion

AWS IAM roles are powerful, but cross-account setups can be tricky without proper configurations. Ensuring trust policies, sts:AssumeRole permissions, and resource policies are aligned is critical for secure and seamless communication across production accounts. Additionally, always verify the use of ExternalId in scenarios where it is required, such as for third-party auditors or external monitoring tools, to prevent unexpected access issues.

By following the workflow and using the examples above, you can navigate complex use cases and avoid common pitfalls, ensuring a secure and well-configured cloud environment.

References