Multi-Provider Setup
Managing infrastructure across multiple cloud providers requires careful planning of provider configurations, authentication strategies, and resource organization. Each cloud provider has different authentication mechanisms, regional structures, and service offerings that need to be coordinated in a unified Terraform configuration.
This part covers the foundational patterns for multi-cloud Terraform configurations, from basic provider setup to advanced authentication and resource management strategies.
Multi-Provider Configuration
A typical multi-cloud setup involves configuring multiple providers with appropriate aliases and authentication:
terraform {
required_version = ">= 1.6"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.20"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.70"
}
google = {
source = "hashicorp/google"
version = "~> 4.80"
}
}
}
# AWS Provider Configuration
provider "aws" {
region = var.aws_region
alias = "primary"
default_tags {
tags = local.common_tags
}
}
provider "aws" {
region = var.aws_secondary_region
alias = "secondary"
default_tags {
tags = local.common_tags
}
}
# Azure Provider Configuration
provider "azurerm" {
features {}
subscription_id = var.azure_subscription_id
tenant_id = var.azure_tenant_id
# Use managed identity when running in Azure
use_msi = var.use_azure_msi
}
# Google Cloud Provider Configuration
provider "google" {
project = var.gcp_project_id
region = var.gcp_region
# Use service account key or application default credentials
credentials = var.gcp_credentials_file
}
provider "google" {
project = var.gcp_project_id
region = var.gcp_secondary_region
alias = "secondary"
credentials = var.gcp_credentials_file
}
Authentication Strategies
Different providers require different authentication approaches:
AWS Authentication:
# Method 1: IAM Roles (recommended for production)
provider "aws" {
region = "us-west-2"
assume_role {
role_arn = "arn:aws:iam::123456789012:role/TerraformRole"
}
}
# Method 2: Environment variables
# AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN
# Method 3: AWS CLI profiles
# AWS_PROFILE=production terraform apply
Azure Authentication:
# Method 1: Service Principal
provider "azurerm" {
features {}
subscription_id = var.azure_subscription_id
client_id = var.azure_client_id
client_secret = var.azure_client_secret
tenant_id = var.azure_tenant_id
}
# Method 2: Managed Identity (when running in Azure)
provider "azurerm" {
features {}
use_msi = true
}
# Method 3: Azure CLI authentication
# az login && terraform apply
Google Cloud Authentication:
# Method 1: Service Account Key
provider "google" {
project = var.gcp_project_id
region = var.gcp_region
credentials = file("path/to/service-account-key.json")
}
# Method 2: Application Default Credentials
provider "google" {
project = var.gcp_project_id
region = var.gcp_region
# Uses gcloud application-default login
}
# Method 3: Workload Identity (when running in GKE)
provider "google" {
project = var.gcp_project_id
region = var.gcp_region
# Automatically uses workload identity
}
Environment-Specific Provider Configuration
Different environments often require different provider configurations:
# variables.tf
variable "environment" {
description = "Environment name"
type = string
}
variable "cloud_providers" {
description = "Cloud providers to use by environment"
type = map(object({
aws_enabled = bool
azure_enabled = bool
gcp_enabled = bool
aws_region = string
azure_region = string
gcp_region = string
}))
default = {
dev = {
aws_enabled = true
azure_enabled = false
gcp_enabled = false
aws_region = "us-west-2"
azure_region = "West US 2"
gcp_region = "us-west1"
}
staging = {
aws_enabled = true
azure_enabled = true
gcp_enabled = false
aws_region = "us-west-2"
azure_region = "West US 2"
gcp_region = "us-west1"
}
production = {
aws_enabled = true
azure_enabled = true
gcp_enabled = true
aws_region = "us-west-2"
azure_region = "West US 2"
gcp_region = "us-west1"
}
}
}
# main.tf
locals {
config = var.cloud_providers[var.environment]
common_tags = {
Environment = var.environment
ManagedBy = "terraform"
Project = var.project_name
}
}
# Conditional provider configuration
provider "aws" {
count = local.config.aws_enabled ? 1 : 0
region = local.config.aws_region
default_tags {
tags = local.common_tags
}
}
provider "azurerm" {
count = local.config.azure_enabled ? 1 : 0
features {}
}
provider "google" {
count = local.config.gcp_enabled ? 1 : 0
project = var.gcp_project_id
region = local.config.gcp_region
}
Resource Organization Patterns
Organize multi-cloud resources for maintainability:
# AWS Resources
resource "aws_vpc" "main" {
count = local.config.aws_enabled ? 1 : 0
provider = aws
cidr_block = "10.0.0.0/16"
tags = merge(local.common_tags, {
Name = "${var.project_name}-aws-vpc"
Provider = "aws"
})
}
# Azure Resources
resource "azurerm_resource_group" "main" {
count = local.config.azure_enabled ? 1 : 0
provider = azurerm
name = "${var.project_name}-rg"
location = local.config.azure_region
tags = merge(local.common_tags, {
Provider = "azure"
})
}
resource "azurerm_virtual_network" "main" {
count = local.config.azure_enabled ? 1 : 0
provider = azurerm
name = "${var.project_name}-vnet"
address_space = ["10.1.0.0/16"]
location = azurerm_resource_group.main[0].location
resource_group_name = azurerm_resource_group.main[0].name
tags = merge(local.common_tags, {
Provider = "azure"
})
}
# Google Cloud Resources
resource "google_compute_network" "main" {
count = local.config.gcp_enabled ? 1 : 0
provider = google
name = "${var.project_name}-vpc"
auto_create_subnetworks = false
labels = {
environment = var.environment
managed_by = "terraform"
project = var.project_name
provider = "gcp"
}
}
Cross-Provider Data Sharing
Share data between providers using outputs and data sources:
# outputs.tf
output "network_info" {
description = "Network information across all providers"
value = {
aws = local.config.aws_enabled ? {
vpc_id = aws_vpc.main[0].id
vpc_cidr_block = aws_vpc.main[0].cidr_block
region = local.config.aws_region
} : null
azure = local.config.azure_enabled ? {
vnet_id = azurerm_virtual_network.main[0].id
vnet_address_space = azurerm_virtual_network.main[0].address_space
resource_group = azurerm_resource_group.main[0].name
region = local.config.azure_region
} : null
gcp = local.config.gcp_enabled ? {
network_id = google_compute_network.main[0].id
network_name = google_compute_network.main[0].name
region = local.config.gcp_region
} : null
}
}
# Use in other configurations
data "terraform_remote_state" "network" {
backend = "s3"
config = {
bucket = "company-terraform-state"
key = "network/terraform.tfstate"
region = "us-west-2"
}
}
locals {
aws_vpc_id = data.terraform_remote_state.network.outputs.network_info.aws.vpc_id
azure_vnet_id = data.terraform_remote_state.network.outputs.network_info.azure.vnet_id
gcp_network_id = data.terraform_remote_state.network.outputs.network_info.gcp.network_id
}
Provider Version Management
Pin provider versions for consistency across clouds:
terraform {
required_version = ">= 1.6"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.20"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.70"
}
google = {
source = "hashicorp/google"
version = "~> 4.80"
}
random = {
source = "hashicorp/random"
version = "~> 3.4"
}
tls = {
source = "hashicorp/tls"
version = "~> 4.0"
}
}
}
# Lock file ensures consistent provider versions
# terraform.lock.hcl is automatically generated
Multi-Cloud Module Structure
Organize modules for multi-cloud scenarios:
modules/
├── multi-cloud-network/
│ ├── main.tf
│ ├── variables.tf
│ ├── outputs.tf
│ ├── aws.tf
│ ├── azure.tf
│ └── gcp.tf
├── cloud-agnostic-database/
│ ├── main.tf
│ ├── variables.tf
│ ├── outputs.tf
│ ├── aws-rds.tf
│ ├── azure-sql.tf
│ └── gcp-sql.tf
└── monitoring/
├── main.tf
├── variables.tf
├── outputs.tf
├── aws-cloudwatch.tf
├── azure-monitor.tf
└── gcp-monitoring.tf
Multi-cloud network module example:
# modules/multi-cloud-network/main.tf
variable "providers_config" {
description = "Configuration for each cloud provider"
type = object({
aws_enabled = bool
azure_enabled = bool
gcp_enabled = bool
})
}
variable "network_cidrs" {
description = "CIDR blocks for each provider"
type = object({
aws = string
azure = string
gcp = string
})
default = {
aws = "10.0.0.0/16"
azure = "10.1.0.0/16"
gcp = "10.2.0.0/16"
}
}
# AWS networking resources
resource "aws_vpc" "main" {
count = var.providers_config.aws_enabled ? 1 : 0
cidr_block = var.network_cidrs.aws
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.name_prefix}-aws-vpc"
Provider = "aws"
}
}
# Azure networking resources
resource "azurerm_virtual_network" "main" {
count = var.providers_config.azure_enabled ? 1 : 0
name = "${var.name_prefix}-vnet"
address_space = [var.network_cidrs.azure]
location = var.azure_location
resource_group_name = var.azure_resource_group_name
tags = {
Provider = "azure"
}
}
# GCP networking resources
resource "google_compute_network" "main" {
count = var.providers_config.gcp_enabled ? 1 : 0
name = "${var.name_prefix}-vpc"
auto_create_subnetworks = false
labels = {
provider = "gcp"
}
}
Error Handling and Debugging
Multi-cloud configurations can be complex to debug:
# Enable detailed logging
export TF_LOG=DEBUG
export TF_LOG_PATH=terraform.log
# Test provider authentication
terraform providers
# Validate configuration
terraform validate
# Plan with specific providers
terraform plan -target="aws_vpc.main"
terraform plan -target="azurerm_virtual_network.main"
terraform plan -target="google_compute_network.main"
# Check provider plugin cache
ls -la .terraform/providers/
Provider-specific debugging:
# AWS debugging
aws sts get-caller-identity
aws configure list
# Azure debugging
az account show
az account list
# GCP debugging
gcloud auth list
gcloud config list
gcloud projects list
What’s Next
Multi-provider setup provides the foundation for multi-cloud infrastructure, but the real challenges emerge when you need to connect networks across different cloud providers. Cross-cloud networking requires understanding each provider’s networking model and implementing secure, performant connections.
In the next part, we’ll explore cross-cloud networking patterns, including VPN connections, private peering, and hybrid connectivity solutions that enable seamless communication across AWS, Azure, and Google Cloud.