Cross-account access in AWS is a common operational requirement for platform teams that need to provision resources in multiple accounts from a single control plane. Terraform’s AWS provider supports this pattern through the assume_role block, which instructs the provider to obtain temporary security credentials via AWS Security Token Service and operate in a target account without storing permanent credentials for that account.
Introduction
The AssumeRole workflow lets an IAM user or service in a primary account request temporary credentials for a role defined in a secondary account. This eliminates the need to manage separate long-lived credentials for each AWS account and centralizes authentication through the primary identity. The AWS provider for Terraform can be configured to authenticate to Account A, request temporary credentials for Account B, and then assume a role to manage resources within Account B.
Core Concepts of AssumeRole with Terraform
AssumeRole allows temporary assumption of another IAM role’s permissions. It is ideal for secure cross-account access in Terraform.
The mechanism works by having the provider use existing AWS credentials to call sts:AssumeRole. The call returns temporary credentials that are scoped to the trust policy and permissions policy of the target role. Terraform then uses those temporary credentials for all subsequent API calls until the session expires.
Key properties of the pattern include:
- Temporary assumption of another IAM role’s permissions
- Ideal for secure cross-account access in Terraform
- No need to manage separate credentials for each AWS account
Prerequisites for Cross-Account AssumeRole
Before configuring the provider, two AWS accounts are required: a primary account, Account A, and a target account, Account B.
- Two AWS accounts, a primary account Account A and a target account Account B
- An IAM user in Account A with permissions to call
sts:AssumeRole - Terraform installed and configured locally, or access to an HCP Terraform or Terraform Enterprise environment
For the target account, an IAM role must exist with the necessary permissions for Terraform to operate, for example create EC2 instances, S3 buckets, etc.
- IAM Role in the Target Account: Create an IAM role in the AWS account where you want to deploy resources. This role should have the necessary permissions for Terraform to operate
- Trust Policy: Configure the role’s trust policy to allow your IAM user or the service running Terraform to assume this role
Define permissions based on the principle of least privilege.
Creating the IAM Role in the Target Account
In the AWS account you want to manage, Account B, create a new IAM role that trusts the primary account, Account A.
- Navigate to IAM > Roles > Create role in the AWS console for Account B
- Select Another AWS account as the trusted entity type
- Enter the Account ID of Account A
- Optional Select the box for Require external ID to add another layer of security. This ensures that requests from Account A are only successful if they include a specific external ID that you define
The trust policy establishes which principal can assume the role and under what conditions. The permissions policy attached to the role determines what Terraform can do once the role is assumed.
Terraform Provider Configuration
Provider configuration is the point where Terraform is instructed to assume the role.
A basic provider block with assume_role looks like:
provider "aws" {
region = "your-target-region"
assume_role {
role_arn = "arn:aws:iam::TARGET_ACCOUNT_ID:role/YOUR_ROLE_NAME"
session_name = "TerraformSession"
}
}
Replace TARGETACCOUNTID and YOURROLENAME with the actual values.
When multiple accounts are involved, aliases and separate provider blocks are used.
provider "aws" {
alias = "staging"
region = "us-east-1"
assume_role {
role_arn = "arn:aws:iam::222222222222:role/TerraformDeployRole"
session_name = "terraform-staging"
external_id = "terraform-deploy-2026"
}
}
Production account example:
provider "aws" {
alias = "production"
region = "us-east-1"
assume_role {
role_arn = "arn:aws:iam::333333333333:role/TerraformDeployRole"
session_name = "terraform-production"
external_id = "terraform-deploy-2026"
}
}
Resources can be pinned to a specific provider:
resource "aws_s3_bucket" "staging_data" {
provider = aws.staging
bucket = "staging-data-bucket"
}
Do not hardcode role ARNs. Using variables for the role ARN keeps configurations portable across environments.
Authentication Flow During Execution
Authentication relies on the local AWS credentials that Terraform will use to initiate the assume role call.
- AWS CLI Credentials: Ensure your local AWS CLI is configured with credentials that have permission to assume the role you defined in your Terraform code. This is usually your regular IAM user
- Ensure your local AWS CLI is configured with credentials for your IAM user in Account A, the user allowed to assume the role
When you run Terraform commands, for example terraform apply, the AWS provider will automatically use your local AWS credentials to assume the specified role. This grants Terraform the permissions it needs in the target account.
The assume_role block in the aws provider tells Terraform to assume the specified role in Account B. When you run terraform apply, Terraform uses your local AWS credentials to get temporary credentials for the role in Account B. With these temporary credentials, Terraform can then create resources in the target account.
A typical workflow:
- Run
terraform initto initialize the project - Run
terraform applyto create the S3 bucket in Account B
During apply, Terraform prompts for confirmation:
```
Terraform will perform the following actions:
awsiamrole.assume_role will be created
...
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Enter a value: yes
```
After creation, the role_arn output is noted for reuse:
Outputs:
role_arn = "arn:aws:iam::<ACCOUNT_ID>:role/assume_role"
Note the role_arn output value. You will reference this value in your configuration to assume the new IAM role in the destination account.
A provider block that references the output role ARN:
provider "aws" {
region = "us-east-2"
profile = "source"
assume_role {
role_arn = "<ROLE_ARN>"
}
}
Notice that this configuration does not reference the destination profile from your AWS credentials file.
Important Considerations
Security is central to the design. Carefully manage the permissions granted to the IAM role being assumed.
Additional considerations:
- Security: Carefully manage the permissions granted to the IAM role being assumed
- Session Duration: Handle potential timeouts for long-running operations
- Terraform Cloud/Enterprise: Securely configure environment variables for credentials
Prioritize security and plan for session management.
Common pitfalls include long running operations exceeding the assumed role session duration, leading to credential expiry mid-apply. Session timeouts can be mitigated by keeping applies short, using targeted resources, or configuring an appropriate session duration on the role.
Credential management differs between local execution and remote execution. In Terraform Cloud or Enterprise, environment variables for credentials must be securely configured rather than relying on local AWS CLI profiles.
Comparison of Provider Configuration Options
| Parameter | Purpose | Example Value |
| rolearn | ARN of the role to assume in target account | arn:aws:iam::TARGETACCOUNTID:role/YOURROLENAME |
| sessionname | Identifier for the assumed session | TerraformSession |
| external_id | Additional security check for cross-account role assumption | terraform-deploy-2026 |
| region | AWS region for provider operations | us-east-1 |
Using Variables for Role ARNs
Hardcoding role ARNs reduces portability. Using variables for the role ARN and account IDs allows the same Terraform code to target staging and production with different provider aliases.
The pattern with aliases enables a single state file or separate state files to manage resources across accounts while keeping authentication isolated per provider.
Conclusion
Managing infrastructure across multiple AWS accounts is made significantly easier and more secure with Terraform’s AssumeRole functionality. By configuring an IAM role in the target account and utilizing the assume_role block within Terraform code, resources can be provisioned without needing to directly manage credentials for the target account.
The approach combines the principle of least privilege with proper credential management. Security is maintained by limiting the permissions of the assumed role, requiring an external ID where appropriate, and using temporary credentials that expire automatically.
As infrastructure grows, mastering Terraform’s AssumeRole capabilities proves invaluable for managing complex deployments and ensuring secure cross-account access within an AWS ecosystem. The pattern supports streamlined workflows for teams that need centralized control while preserving account boundaries and auditability.