IAM tutorial: Delegate access across AWS accounts using IAM roles - AWS Identity and Access Management

IAM tutorial: Delegate access across AWS accounts using IAM roles

Important

IAM best practices recommend that you require human users to use federation with an identity provider to access AWS using temporary credentials instead of using IAM users with long-term credentials. We recommend that you only use IAM users for specific use cases not supported by federated users.

This tutorial teaches you how to use a role to delegate access to resources in different AWS accounts called Destination and Originating. You share resources in one account with users in a different account. By setting up cross-account access in this way, you don't have to create individual IAM users in each account. In addition, users don't have to sign out of one account and sign in to another account to access resources in different AWS accounts. After configuring the role, you see how to use the role from the AWS Management Console, the AWS CLI, and the API.

In this tutorial, the Destination account manages application data accessed by different applications and teams. In each account, you store application information in Amazon S3 buckets. You manage IAM users in the Originating account, where you have two IAM user roles: Developers and Analysts. Developers and Analysts use the Originating account to generate data shared by multiple microservices. Both roles have permissions to work in the Originating account and access resources there. From time to time, a developer must update the shared data in the Destination account. The developers store this data in an Amazon S3 bucket called amzn-s3-demo-bucket-shared-container.

At the end of this tutorial, you have the following:

  • Users in the Originating account (the trusted account) allowed to assume a specific role in the Destination account.

  • A role in the Destination account (the trusting account) allowed to access a specific Amazon S3 bucket.

  • The amzn-s3-demo-bucket-shared-container bucket in the Destination account.

Developers can use the role in the AWS Management Console to access the amzn-s3-demo-bucket-shared-container bucket in the Destination account. They can also access the bucket by using API calls authenticated by temporary credentials provided by the role. Similar attempts by an Analyst to use the role fail.

This workflow has three basic steps:

Create a role in the Destination Account

First, you use the AWS Management Console to establish trust between the Destination account (ID number 999999999999) and the Originating account (ID number 111111111111). You start by creating an IAM role named UpdateData. When you create the role, you define the Originating account as a trusted entity and specify a permissions policy that allows trusted users to update the amzn-s3-demo-bucket-shared-container bucket.

Grant access to the role

In this section, you modify the role policy to deny Analysts access to the UpdateData role. Because Analysts have PowerUser access in this scenario, and you must explicitly deny the ability to use the role.

Test access by switching roles

Finally, as a Developer, you use the UpdateData role to update the amzn-s3-demo-bucket-shared-container bucket in the Destination account. You see how to access the role through the AWS console, the AWS CLI, and the API.

Considerations

Before you use IAM roles to delegate resource access across AWS accounts, it's important to consider the following:

  • You cannot switch to a role when you sign in as the AWS account root user.

  • IAM roles and resource-based policies delegate access across accounts only within a single partition. For example, assume that you have an account in US West (N. California) in the standard aws partition. You also have an account in China (Beijing) in the aws-cn partition. You can't use an Amazon S3 resource-based policy in your account in China (Beijing) to allow access for users in your standard aws account.

  • You can use AWS IAM Identity Center to facilitate single sign-on (SSO) for external AWS accounts (accounts outside your AWS Organizations) using Security Assertion Markup Language (SAML). For details, see Integrate external AWS accounts into AWS IAM Identity Center for central access management with independent billing using SAML 2.0

  • You can associate roles to AWS resources like Amazon EC2 instances or AWS Lambda functions. For details, see Create a role to delegate permissions to an AWS service.

  • If you want to have an application assume a role in another AWS account, you can use the AWS SDK for cross account role assumption. For more information, see Authentication and access in the AWS SDKs and Tools Reference Guide.

  • Switching roles using the AWS Management Console only works with accounts that do not require an ExternalId. For example, assume that you grant access to your account to a third party and require an ExternalId in a Condition element in your permissions policy. In that case, the third party can access your account only by using the AWS API or a command line tool. The third party cannot use the console because it must supply a value for ExternalId. For more information about this scenario, see Access to AWS accounts owned by third parties, and How to enable cross account access to the AWS Management Console in the AWS Security Blog.

Prerequisites

This tutorial assumes that you have the following already in place:

  • Two separate AWS accounts that you can use, one to represent the Originating account, and one to represent the Destination account.

  • Users and roles in the Originating account created and configured as follows:

    Job title User Permissions
    Developer David Both users can sign in and use the AWS Management Console in the Originating account.
    Analyst Jane
  • You do not need to create any users in the Destination account.

  • An Amazon S3 bucket created in the Destination account. You can call it amzn-s3-demo-bucket-shared-container in this tutorial, but because S3 bucket names must be globally unique, you must use a bucket with a different name.

Create a role in the Destination Account

You can allow users from one AWS account to access resources in another AWS account. In this tutorial, we'll do this by creating a role that defines who can access it and what permissions it grants to users that switch to it.

In this step of the tutorial, you create the role in the Destination account and specify the Originating account as a trusted entity. You also limit the role permissions to only read and write access to the amzn-s3-demo-bucket-shared-container bucket. Anyone granted permission to use the role can read and write to the shared-container bucket.

Before you can create a role, you need the account ID of the Originating AWS account. Each AWS account has a unique account ID identifier assigned to it.

To obtain the Originating AWS account ID
  1. Sign in to the AWS Management Console as an administrator of the Originating account, and open the IAM console at https://console.aws.amazon.com/iam/.

  2. In the IAM console, choose your user name on the navigation bar in the upper right. It typically looks like this: username@account_ID_number_or_alias.

    For this scenario, you can use the account ID 111111111111 for the Originating account. However, you should use a valid account ID if you use this scenario in your test environment.

To create a role in the Destination account that can be used by the Originating account
  1. Sign in to the AWS Management Console as an administrator of the Destination account, and open the IAM console.

  2. Before creating the role, prepare the managed policy that defines the permissions for the role requirements. You attach this policy to the role in a later step.

    You want to set read and write access to the amzn-s3-demo-bucket-shared-container bucket. Although AWS provides some Amazon S3 managed policies, there isn't one that provides read and write access to a single Amazon S3 bucket. You can create your own policy instead.

    In the navigation pane, choose Policies and then choose Create policy.

  3. Choose the JSON tab and copy the text from the following JSON policy document. Paste this text into the JSON text box, replacing the resource ARN (arn:aws:s3:::shared-container) with the real one for your Amazon S3 bucket.

    { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:ListAllMyBuckets", "Resource": "*" }, { "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:GetBucketLocation" ], "Resource": "arn:aws:s3:::amzn-s3-demo-bucket-shared-container" }, { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:PutObject", "s3:DeleteObject" ], "Resource": "arn:aws:s3:::amzn-s3-demo-bucket-shared-container/*" } ] }

    The ListAllMyBuckets action grants permission to list all buckets owned by the authenticated sender of the request. The ListBucket permission allows users to view objects in the amzn-s3-demo-bucket-shared-container bucket. The GetObject, PutObject, DeleteObject permissions allows users to view, update, and delete contents in the amzn-s3-demo-bucket-shared-container bucket.

    Note

    You can switch between the Visual and JSON editor options anytime. However, if you make changes or choose Next in the Visual editor, IAM might restructure your policy to optimize it for the visual editor. For more information, see Policy restructuring.

  4. On the Review and create page, type read-write-app-bucket for the policy name. Review the permissions granted by your policy, and then choose Create policy to save your work.

    The new policy appears in the list of managed policies.

  5. In the navigation pane, choose Roles and then choose Create role.

  6. Choose the An AWS account role type.

  7. For Account ID, type the Originating account ID.

    This tutorial uses the example account ID 111111111111 for the Originating account. You should use a valid account ID. If you use an invalid account ID, such as 111111111111, IAM does not let you create the new role.

    For now you do not need to require an external ID, or require users to have multi-factor authentication (MFA) in order to assume the role. Leave these options unselected. For more information, see AWS Multi-factor authentication in IAM.

  8. Choose Next: Permissions to set the permissions associated with the role.

  9. Select the checkbox next to the policy that you created previously.

    Tip

    For Filter, choose Customer managed to filter the list to include only the policies that you created. This hides the AWS created policies and makes it much easier to find the one you need.

    Then, choose Next.

  10. (Optional) Add metadata to the role by attaching tags as key-value pairs. For more information about using tags in IAM, see Tags for AWS Identity and Access Management resources.

  11. (Optional) For Description, enter a description for the new role.

  12. After reviewing the role, choose Create role.

    The UpdateData role appears in the list of roles.

Now you must obtain the Amazon Resource Name (ARN) of the role, a unique identifier for the role. When you modify the Developer's role in the Originating account, you specify the role ARN from the Destination account to grant or deny permissions.

To obtain the ARN for UpdateData
  1. In the navigation pane of the IAM console, choose Roles.

  2. In the list of roles, choose the UpdateData role.

  3. In the Summary section of the details pane, copy the Role ARN value.

    The Destination account has an account ID of 999999999999, so the role ARN is arn:aws:iam::999999999999:role/UpdateData. Ensure that you provide the real AWS account ID for the Destination account.

At this point, you have established trust between the Destination and Originating accounts. You did this by creating a role in the Destination account that identifies the Originating account as a trusted principal. You also defined what the users who switch to the UpdateData role can do.

Next, modify the permissions for the Developer role.

Grant access to the role

At this point, both Analysts and Developers have permissions that allow them to manage data in the Originating account. Use the following required steps for adding permissions to allow switching to the role.

To modify the Developers role to allow them to switch to the UpdateData role
  1. Sign in as an administrator in the Originating account, and open the IAM console.

  2. Choose Roles, and then choose Developers.

  3. Choose the Permissions tab, choose Add permissions, and then choose Create inline policy.

  4. Choose the JSON tab.

  5. Add the following policy statement to allow the AssumeRole action on the UpdateData role in the Destination account. Be sure that you change DESTINATION-ACCOUNT-ID in the Resource element to the actual AWS account ID of the Destination account.

    { "Version": "2012-10-17", "Statement": { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::DESTINATION-ACCOUNT-ID:role/UpdateData" } }

    The Allow effect explicitly allows the Developers group access to the UpdateData role in the Destination account. Any developer who tries to access the role succeeds.

  6. Choose Review policy.

  7. Type a Name such as allow-assume-S3-role-in-destination.

  8. Choose Create policy.

In most environments, you may not need the following procedure. If, however, you use PowerUserAccess permissions, then some groups might already be able to switch roles. The following procedure shows how to add a "Deny" permission to the Analysts group to ensure that they cannot assume the role. If you do not need this procedure in your environment, then we recommend that you do not add it. "Deny" permissions make the overall permissions picture more complicated to manage and understand. Use "Deny" permissions only when you do not have a better option.

To modify the Analysts role to deny permission to assume the UpdateData role
  1. Choose Roles, and then choose Analysts.

  2. Choose the Permissions tab, choose Add permissions, and then choose Create inline policy.

  3. Choose the JSON tab.

  4. Add the following policy statement to deny the AssumeRole action on the UpdateData role. Be sure that you change DESTINATION-ACCOUNT-ID in the Resource element to the actual AWS account ID of the Destination account.

    { "Version": "2012-10-17", "Statement": { "Effect": "Deny", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::DESTINATION-ACCOUNT-ID:role/UpdateData" } }

    The Deny effect explicitly denies the Analysts group access to the UpdateData role in the Destination account. Any analyst who tries to access the role receives an access denied message.

  5. Choose Review policy.

  6. Type a Name like deny-assume-S3-role-in-destination.

  7. Choose Create policy.

The Developers role now has permissions to use the UpdateData role in the Destination account. The Analysts role is prevented from using the UpdateData role.

Next, you can see how David, a developer, can access the amzn-s3-demo-bucket-shared-container bucket in the Destination account. David can access the bucket from the AWS Management Console, the AWS CLI, or the AWS API.

Test access by switching roles

After completing the first two steps of this tutorial, you have a role that grants access to a resource in the Destination account. You also have one role in the Originating account with users allowed to use that role. This step discusses how to test switching to that role from the AWS Management Console, the AWS CLI, and the AWS API.

To get help with common issues that you might encounter when working with IAM roles, see Troubleshoot IAM roles.

Switch roles (console)

If David needs to update data in the Destination account in the AWS Management Console, he can do so by using Switch Role. He specifies the account ID or alias and the role name, and his permissions immediately switch to those permitted by the role. He can then use the console to work with the amzn-s3-demo-bucket-shared-container bucket, but cannot work with any other resources in Destination. While David uses the role, he also cannot make use of his power-user privileges in the Originating account. That's because only one set of permissions can be in effect at a time.

IAM provides two ways that David can use to enter the Switch Role page:

  • David receives a link from their administrator that points to a predefined Switch Role configuration. The link is provided to the administrator on the final page of the Create role wizard or on the Role Summary page for a cross-account role. Choosing this link takes David to the Switch Role page with the Account ID and Role name fields already filled in. All David needs to do is choose Switch Roles.

  • The administrator does not send the link in email, but instead sends the Account ID number and Role Name values. To switch roles, David must manually enter the values. This is illustrated in the following procedure.

To assume a role
  1. David signs into the AWS Management Console using his normal user in the Originating account.

  2. They choose the link that the administrator emailed to them. This takes David to the Switch Role page with the account ID or alias and the role name information already filled in.

    —or—

    David chooses their name (the Identity menu) on the navigation bar, and then chooses Switch Roles.

    If this is the first time that David tries to access the Switch Role page this way, he first lands on a first-run Switch Role page. This page provides additional information on how switching roles can permit users to manage resources across AWS accounts. David must choose Switch Role on this page to complete the rest of this procedure.

  3. Next, in order to access the role, David must manually type the Destination account ID number (999999999999) and the role name (UpdateData).

    Also, David wants to monitor which roles and associated permissions currently active in IAM. To keep track of this information, he types Destination in the Display Name text box, chooses the red color option, and then chooses Switch Role.

  4. David can now use the Amazon S3 console to work with the Amazon S3 bucket, or any other resource to which the UpdateData role has permissions.

  5. When done, David can return to their original permissions. To do that, they choose the Destination role display name on the navigation bar and then choose Back to David @ 111111111111.

  6. The next time that David wants to switch roles and chooses the Identity menu in the navigation bar, he sees the Destination entry still there from last time. He can simply choose that entry to switch roles immediately without reentering the account ID and role name.

Switch roles (AWS CLI)

If David needs to work in the Destination environment at the command line, he can do so by using the AWS CLI. He runs the aws sts assume-role command and passes the role ARN to get temporary security credentials for that role. He then configures those credentials in environment variables so subsequent AWS CLI commands work using the role's permissions. While David uses the role, he cannot use his power-user privileges in the Originating account, because only one set of permissions can be in effect at a time.

Note that all access keys and tokens are examples only and cannot be used as shown. Replace with the appropriate values from your live environment.

To assume a role
  1. David opens a command prompt window, and confirms that the AWS CLI client is working by running the command:

    aws help
    Note

    David's default environment uses the David user credentials from his default profile that he created with the aws configure command. For more information, see Configuring the AWS Command Line Interface in the AWS Command Line Interface User Guide.

  2. He begins the switch role process by running the following command to switch to the UpdateData role in the Destination account. He received the role ARN from the administrator that created the role. The command requires that you provide a session name as well, you can choose any text you like for that.

    aws sts assume-role --role-arn "arn:aws:iam::999999999999:role/UpdateData" --role-session-name "David-ProdUpdate"

    David then sees the following in the output:

    { "Credentials": { "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", "SessionToken": "AQoDYXdzEGcaEXAMPLE2gsYULo+Im5ZEXAMPLEeYjs1M2FUIgIJx9tQqNMBEXAMPLE CvSRyh0FW7jEXAMPLEW+vE/7s1HRpXviG7b+qYf4nD00EXAMPLEmj4wxS04L/uZEXAMPLECihzFB5lTYLto9dyBgSDy EXAMPLE9/g7QRUhZp4bqbEXAMPLENwGPyOj59pFA4lNKCIkVgkREXAMPLEjlzxQ7y52gekeVEXAMPLEDiB9ST3Uuysg sKdEXAMPLE1TVastU1A0SKFEXAMPLEiywCC/Cs8EXAMPLEpZgOs+6hz4AP4KEXAMPLERbASP+4eZScEXAMPLEsnf87e NhyDHq6ikBQ==", "Expiration": "2014-12-11T23:08:07Z", "AccessKeyId": "AKIAIOSFODNN7EXAMPLE" } }
  3. David sees the three pieces that they need in the Credentials section of the output.

    • AccessKeyId

    • SecretAccessKey

    • SessionToken

    David needs to configure the AWS CLI environment to use these parameters in subsequent calls. For information about the various ways to configure your credentials, see Configuring the AWS Command Line Interface. You cannot use the aws configure command because it does not support capturing the session token. However, you can manually enter the information into a configuration file. Because these are temporary credentials with a relatively short expiration time, it is easiest to add them to the environment of your current command line session.

  4. To add the three values to the environment, David cuts and pastes the output of the previous step into the following commands. You might want to cut and paste into a simple text editor to address line wrap issues in the output of the session token. It must be added as a single long string, even though it is shown line wrapped here for clarity.

    The following example shows commands given in the Windows environment, where "set" is the command to create an environment variable. On a Linux or macOS computer, you would use the command "export" instead. All other parts of the example are valid in all three environments.

    For details on using Tools for Windows Powershell, see Switch to an IAM role (Tools for Windows PowerShell)

    set AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE set AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY set AWS_SESSION_TOKEN=AQoDYXdzEGcaEXAMPLE2gsYULo+Im5ZEXAMPLEeYjs1M2FUIgIJx9tQqNMBEXAMPLECvS Ryh0FW7jEXAMPLEW+vE/7s1HRpXviG7b+qYf4nD00EXAMPLEmj4wxS04L/uZEXAMPLECihzFB5lTYLto9dyBgSDyEXA MPLEKEY9/g7QRUhZp4bqbEXAMPLENwGPyOj59pFA4lNKCIkVgkREXAMPLEjlzxQ7y52gekeVEXAMPLEDiB9ST3UusKd EXAMPLE1TVastU1A0SKFEXAMPLEiywCC/Cs8EXAMPLEpZgOs+6hz4AP4KEXAMPLERbASP+4eZScEXAMPLENhykxiHen DHq6ikBQ==

    At this point, any following commands run under the permissions of the role identified by those credentials. In David's case, the UpdateData role.

    Important

    You can save your frequently used configuration settings and credentials in files that are maintained by the AWS CLI. For more information, see Using existing configuration and credentials files in the AWS Command Line Interface User Guide.

  5. Run the command to access the resources in the Destination account. In this example, David lists the contents of their S3 bucket with the following command.

    aws s3 ls s3://shared-container

    Because Amazon S3 bucket names are universally unique, there is no need to specify the account ID that owns the bucket. To access resources for other AWS services, refer to the AWS CLI documentation for that service for the commands and syntax required to reference its resources.

Using AssumeRole (AWS API)

When David needs to make an update to the Destination account from code, he makes an AssumeRole call to assume the UpdateData role. The call returns temporary credentials that he can use to access the amzn-s3-demo-bucket-shared-container bucket in the Destination account. With those credentials, David can make API calls to update the amzn-s3-demo-bucket-shared-container bucket. However, he cannot make API calls to access any other resources in the Destination account, even though he has power-user permissions in the Originating account.

To assume a role
  1. David calls AssumeRole as part of an application. They must specify the UpdateData ARN: arn:aws:iam::999999999999:role/UpdateData.

    The response from the AssumeRole call includes the temporary credentials with an AccessKeyId and a SecretAccessKey. It also includes an Expiration time that indicates when the credentials expire and you must request new ones. When you set up role chaining with the AWS SDK, many credential providers automatically refresh credentials before they expire.

  2. With the temporary credentials, David makes an s3:PutObject call to update the amzn-s3-demo-bucket-shared-container bucket. They would pass the credentials to the API call as the AuthParams parameter. Because the temporary role credentials have only read and write access to the amzn-s3-demo-bucket-shared-container bucket, any other actions in the Destination account are denied.

For a code example (using Python), see Switch to an IAM role (AWS API).

The following resources can help you learn more about topics in this tutorial:

  • For more information about IAM users, see IAM Identities .

  • For more information about Amazon S3 buckets, see Create a Bucket in the Amazon Simple Storage Service User Guide.

  • To learn whether principals in accounts outside of your zone of trust (trusted organization or account) have access to assume your roles, see What is IAM Access Analyzer?.

Summary

You have completed the cross-account API access tutorial. You created a role to establish trust with another account and defined what actions trusted entities can take. Then, you modified a role policy to control which IAM users can access the role. As a result, developers from the Originating account can make updates to the amzn-s3-demo-bucket-shared-container bucket in the Destination account by using temporary credentials.