Getting Started with Multiple Providers in Terraform

Today, we'll look about how to interact with numerous Terraform providers. Providers serve as an intermediary between Terraform and infrastructure platforms such as AWS, Azure, GCP, Docker, and Kubernetes. As multi-cloud architectures gain appeal, understanding how to manage several providers becomes crucial for developing scalable and efficient infrastructure.

This session also covers how to use multiple copies of the same provider, which is important for delivering resources across several accounts or regions.

Providers in Terraform

Providers in Terraform are plugins that allow it to communicate with external APIs. Each provider identifies resources and data sources, making it easier to administer individual platforms. For example, Terraform may use the aws provider to build, edit, and remove AWS resources.

Required Providers

The required_providers block is used in Terraform to specify which providers your configuration depends on, including their source and version.

It provides stability and predictability by locking provider versions in your Terraform setup. This eliminates unexpected changes or incompatibilities when providers update, making your deployments more dependable across environments.

It also increases security by identifying a provider's legitimate source (for example, "hashicorp/aws") and ensuring that the right provider is installed during Terraform init. This is critical in production to prevent the unintended usage of unverified providers or mismatched versions, which might result in deployment problems or security issues.

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

  required_version = ">= 3.5.0"
}

Providers Aliases

Provider aliases allow you to set up several instances of the same provider in a single Terraform configuration. This is particularly handy for managing resources across several AWS regions or accounts or even clouds using the same provider. With aliases, you can ensure that resources are provisioned where they are needed, without needing separate provider configurations.

provider "aws" {
  alias = "east"
  region = "us-east-1"
}

# Alias for another provider instance in us-west-2
provider "aws" {
  alias  = "west"
  region = "us-west-2"
}

# Define an output for each region's name
output "region_east" {
  value = "Region: ${provider.aws.region}"
}

output "region_west" {
  value = "Region: ${provider.aws.west.region}"
}

Use the Aliases in Resources

When defining resources, specify which provider to use by referencing the alias with the provider argument.

resource "aws_instance" "east_instance" {
  provider = aws.east
  ami           = "ami-123456"
  instance_type = "t2.micro"
}

resource "aws_instance" "west_instance" {
  provider = aws.west
  ami           = "ami-654321"
  instance_type = "t2.micro"
}

Using Multiple Accounts

Using Assume Role

To manage infrastructure across multiple AWS accounts, IAM Assume Role is essential. This allows secure cross-account access without needing multiple user credentials. Here’s how to set it up:

Step 1: Create a New AWS Account

  1. Use AWS Organizations to create a child account.

  2. Leave the default IAM Role Name as OrganizationAccountAccessRole.

Step 2: Set Up IAM Role in the Child Account

AWS Organizations automatically creates the role OrganizationAccountAccessRole in the child account, allowing the parent account to assume this role. If needed, manually create an IAM role in the child account:

  1. Create a role with the trusted entity as the parent account:

     jsonCopy code{
       "Version": "2012-10-17",
       "Statement": [
         {
           "Effect": "Allow",
           "Principal": {
             "AWS": "arn:aws:iam::111111111111:root"
           },
           "Action": "sts:AssumeRole"
         }
       ]
     }
    
  2. Attach policies to define permissions (e.g., AdministratorAccess or custom policies).

Step 3: Configure Terraform Providers

In your Terraform configuration, define two providers—one for the parent account and one for the child account with an assume_role block.

provider "aws" {
  alias   = "parent"
  region  = "us-east-1"
}

provider "aws" {
  alias = "child"
  region = "us-east-1"

  assume_role {
    role_arn     = "arn:aws:iam::222222222222:role/OrganizationAccountAccessRole"
    session_name = "AssumeRoleSession"
  }
}
  • Replace 222222222222 with the child account ID.

Step 4: Deploy Resources

Use the provider aliases to target resources in the respective accounts:

resource "aws_s3_bucket" "parent_bucket" {
  provider = aws.parent
  bucket   = "parent-account-bucket"
}

resource "aws_s3_bucket" "child_bucket" {
  provider = aws.child
  bucket   = "child-account-bucket"
}

Step 5: Verify Configuration

Use the aws_caller_identity data source to verify access:

data "aws_caller_identity" "parent" {
  provider = aws.parent
}

data "aws_caller_identity" "child" {
  provider = aws.child
}

output "parent_account" {
  value = data.aws_caller_identity.parent.account_id
}

output "child_account" {
  value = data.aws_caller_identity.child.account_id
}

Conclusion

We looked at how to utilize provider aliases in Terraform to manage resources across various Amazon Web Services accounts. We can safely and efficiently isolate environments, enhance resource organization, and speed multi-account installations by defining aliases and relying on cross-account role assumptions. In complicated settings, this method guarantees improved compartmentalization, increased security, and simpler infrastructure administration.