fbpx

Generally, when using HashiCorp Terraform to deploy and manage Amazon AWS resources, the Terraform project will be working with AWS resources in only a single AWS Account. However, it’s common to structure cloud deployments across multiple Amazon AWS Accounts in certain use cases. This could be to separate DEV and PROD environments, or to separate cloud resource managements across multiple AWS Accounts for several other reasons. Regardless of the actual reason to use multiple AWS Accounts, it really is possible to use a single Terraform project to manage all the cloud resources across multiple AWS Accounts without the need to split things out into multiple Terraform projects.

Let’s take a look at configuring the AWS Terraform Provider to enable the deployment and management of AWS resources across multiple AWS Accounts from a single Terraform project!


Define Multiple AWS Providers

At these times, you will need to support multiple instances of the aws Terraform Provider, each targeting a different AWS Account, within a single Terraform project. This can be done by using the alias attribute on the provider declaration in Terraform. This enables the ability to have multiple aws providers configured for different AWS Account credentials.

This may become necessary when you have separate AWS Accounts, or even just separate AWS IAM credentials, that need to be used to deploy and manage specific Amazon AWS resources. Maybe the resources are managed across the different accounts, or maybe different security credentials are used for specific resource deployment needs. Either way, this technique will help you get the Terraform written the way you need it within a single Terraform project.

The following is an example of 2 different provider blocks for the aws Terraform provider with the alias attribute set to differentiate between them since they are configured for different AWS Accounts:

terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
      version = "~> 4.0"
    }
  }

  provider "aws" {
    alias = "dev"

    access_key = var.dev_aws_key
    secret_key = var.dev_aws_secret
    region = "us-east-1"
  }

  provider "aws" {
    alias = "prod"

    access_key = var.prod_aws_key
    secret_key = var.prod_aws_secret
    region = "us-west-2"
  }
}

Keep in mind the previous example uses Input Variables passed to the Terraform project to define the values that are used to configure the AWS Accounts for each aws Terraform provider instance.

Deploy to Multiple AWS Accounts within Terraform Project

Once you have multiple aws Terraform providers configured in the Terraform project with the alias attribute set on each, you can use the provider attribute on resource blocks to explicitly specific which provider to use for deploying each resource.

The following is an example of code from a single Terraform project that will deploy resources to multiple AWS Accounts using the aws providers from the previous example:

resource aws_s3_bucket "dev_bucket_1" {
  provider = "dev"
  bucket = "my-tf-dev-bucket-1"
}

resource aws_s3_bucket "prod_bucket_1" {
  provider = "prod"
  bucket = "my-tf-prod-bucket-1"
}

With the resource.provider attribute set, you’re telling the Terraform code which specific Terraform provider to use for deploying and managing that AWS resource. By defining multiple aws providers with the alias attribute, you are able to set up multiple instances of the aws provider to be used within a single Terraform provider. This is supported for the aws provider, as well as any other Terraform provider.

Passing Terraform Provider Alias to Modules

When writing Terraform Modules, for code reuse and organization within the Terraform project, the code within the module may be coded to just use the “default” aws provider; without any provider.alias expected. In these cases, you can explicitly set, or override, which aws Terraform provider from the Terraform project will be used as the “default” within the Terraform Module.

This is done by using the providers attribute on a module block to explicitly configure the Terraform Module for which Terraform providers to pass it.

The following is an example of using a Terraform Module within a project and passing different aws provider instances to it as the “default” provider. This will enable the same module, without code changes, to be used with multiple AWS Accounts within a single Terraform project.

module "sample-dev" {
  source = "./sample-module"
  providers = {
    aws = aws.dev
  }
}

module "sample-prod" {
  source = "./sample-module"
  providers = {
    aws = aws.prod
  }
}

When using the module.providers attribute to tell the Terraform Module which Terraform provider instance to use, you are defining it using an object syntax that allows for multiple providers. This enables you to explicitly specify all the different Terraform providers that module needs to use, in case it’s coded for multiple providers as well.

Deploy to Multiple AWS Accounts with a “Default” aws Provider

The previous examples all used named aws providers using the alias attribute on each provider. It is possible, and probably best practice, to use one aws Terraform provider instance as the “default”, and then use the alias attribute to configure multiple other providers to be used within the Terraform project as well.

The following it an alternative example that defines the dev AWS provider instance as the “default” for the Terraform project, while also defining the prod AWS provider instance as a named instance using the alias attribute.

terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
      version = "~> 4.0"
    }
  }

  # This is the "default" provider
  provider "aws" {
    access_key = var.dev_aws_key
    secret_key = var.dev_aws_secret
    region = "us-east-1"
  }

  # This provider uses the "prod" alias
  provider "aws" {
    alias = "prod"

    access_key = var.prod_aws_key
    secret_key = var.prod_aws_secret
    region = "us-west-2"
  }
}

# Use the "default" aws provider
resource aws_s3_bucket "dev_bucket_1" {
  bucket = "my-tf-dev-bucket-1"
}

module "sample-dev" {
  source = "./sample-module"
}

# Use the "prod" aliased aws provider
resource aws_s3_bucket "prod_bucket_1" {
  provider = "prod"
  bucket = "my-tf-prod-bucket-1"
}

module "sample-dev" {
  source = "./sample-module"
  providers = {
    aws = aws.prod
  }
}

Happy Terraform-ing!

Microsoft MVP

Chris Pietschmann is a Microsoft MVP, HashiCorp Ambassador, and Microsoft Certified Trainer (MCT) with 20+ years of experience designing and building Cloud & Enterprise systems. He has worked with companies of all sizes from startups to large enterprises. He has a passion for technology and sharing what he learns with others to help enable them to learn faster and be more productive.
HashiCorp Ambassador Microsoft Certified Trainer (MCT) Microsoft Certified: Azure Solutions Architect