Pre-requisite
- Two AWS accounts: AccountA and AccountB
 - IAM programmatic access user already setup and working for Terraform in AccountA, let’s call this user Terraform-User, and it already have role assigned in AccountA
 - Now that we are going to use the same Terraform-User access key and secret to work on resources in AccountB
 
Create a new role in AccountB
- Trusted entity -> AWS account -> since AccountB need to trust AccountA, enter AccountA’s account ID
 

- Assign required permission polices to this role, eg: AdministratorAccess
 - Assign a role name, eg: CrossAccountSignin
 - Example of the role JSON created
 
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::AccountA_Account_ID:root"
            },
            "Action": "sts:AssumeRole",
            "Condition": {}
        }
    ]
}
- Note down the ARN of this role, eg:
arn:aws:iam::AccountB_Account_ID:role/CrossAccountSignin 
Create and assign policy in AccountA
- Use following JSON definition
 - “Resource” point to the ARN of the CrossAccountSignin role created in AccountB
 
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "sts:AssumeRole"
            ],
            "Resource": "arn:aws:iam::AccountB_Account_ID:role/CrossAccountSignin"
        }
    ]
}
- Assign this policy to AccountA IAM user: Terraform-User
 
Assume role in Terraform
- providers.tf
Notice an alias gets created for account_b 
provider "aws" {
  region = "us-east-1"
}
provider "aws" {
  region = "us-east-1"
  alias  = "account_b"
  assume_role {
    role_arn = "arn:aws:iam::AccountB_Account_ID:role/CrossAccountSignin"
  }
}
- main.tf
 
resource "aws_vpc" "account_a_vpc" {
  cidr_block = "10.0.1.0/24"
  tags = {
    "Name" = "account_a_vpc"
  }
}
resource "aws_vpc" "account_b_vpc" {
  provider   = aws.account_b
  cidr_block = "10.0.2.0/24"
  tags = {
    "Name" = "account_b_vpc"
  }
}
- resource.aws_vpc.account_a_vpc will create VPC in AccountA implicitly
 - resource.aws_vpc.account_b_vpc will create VPC in AccountB by explicitly specifying provider = aws.account_b
 
Cross account access to data
Similarly to resource block, you can perform the same for data block, example:
- Same providers.tf
 
provider "aws" {
  region = "us-east-1"
}
provider "aws" {
  region = "us-east-1"
  alias  = "account_b"
  assume_role {
    role_arn = "arn:aws:iam::AccountB_Account_ID:role/CrossAccountSignin"
  }
}
- data.tf
 
data "aws_availability_zones" "az_zones" {
}
data "aws_availability_zones" "app_az_zones" {
  provider = aws.account_b
}
- data.aws_availability_zones.az_zones will retrieve availability zones as Terraform-User from AccountA
 - data.aws_availability_zones.app_az_zones” will retrieve availability zones assume role in AccountB
 
Cross account for module
Assume we have following folder structure:
|_ main.tf
|  providers.tf
|_ modules
    |_ app
         |_ main.tf
         |_ providers.tf
Root /providers.tf have following statement as before:
provider "aws" {
  region = "us-east-1"
}
provider "aws" {
  region = "us-east-1"
  alias  = "account_b"
  assume_role {
    role_arn = "arn:aws:iam::AccountB_Account_ID:role/CrossAccountSignin"
  }
}
Root /main.tf have following statement
module "app1" {
  source   = "./modules/app"
   .
   .
   .
}
If you run it, you may find resources gets created in the default account : AccountA, where Terraform-User is resided. How do we make the resource create in AccountB instead?
Think of module a mini block of terraform code that also require it’s own provider block. If you don’t specify anything in /modules/app/providers.tf, it will implicitly have this block, basically it’s looking for a provider called aws
provider "aws" {
}
So we will modify /main.tf like this:
module "app1" {
  source   = "./modules/app"
   providers = {
    aws = aws.account_b
  }
   .
   .
   .
}
This is telling within the module, provider.aws is equal to root provider.aws.account_b.
If you rerun terraform apply. you will notice:
- Resources created in AccountA remains
 - New resources get created in AccountB now
 - Warning message:
 
Warning: Provider aws is undefined
│
│   on main.tf line 8, in module "app1":
│    8:     aws = aws.account_b
│
│ Module module.app1 does not declare a provider named aws.
│ If you wish to specify a provider configuration for the module, add an entry for aws in the required_providers block within the module.
To make Terraform happy, add following lines in /modules/app/providers.tf
terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
    }
  }
}
					
			




















