Terraform_multicloud
Terraform Multi-Cloud Patterns
Section titled “Terraform Multi-Cloud Patterns”Overview
Section titled “Overview”Multi-cloud infrastructure management involves deploying and managing resources across multiple cloud providers. Terraform’s provider ecosystem makes it well-suited for multi-cloud deployments.
Why Multi-Cloud?
Section titled “Why Multi-Cloud?”- Vendor independence: Avoid lock-in
- Best-of-breed: Use best services from each provider
- Disaster recovery: Cross-cloud redundancy
- Compliance: Meet data residency requirements
- Cost optimization: Leverage pricing differences
Multi-Cloud Architecture
Section titled “Multi-Cloud Architecture”┌─────────────────────────────────────────────────────────────────┐│ Multi-Cloud Architecture ││ ││ ┌──────────────┐ ││ │ Terraform │ ││ │ Config │ ││ └──────┬───────┘ ││ │ ││ ┌──────────────────────┼──────────────────────┐ ││ │ │ │ ││ ▼ ▼ ▼ ││ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ││ │ AWS │ │ Azure │ │ GCP │ ││ │ (us-east) │ │ (eastus) │ │ (us-east) │ ││ └─────────────┘ └─────────────┘ └─────────────┘ ││ ││ ┌───────────────────────────────────────────────────────────┐ ││ │ Networking │ ││ │ Transit Gateway / ExpressRoute / Cloud Interconnect │ ││ └───────────────────────────────────────────────────────────┘ │└─────────────────────────────────────────────────────────────────┘Multi-Provider Configuration
Section titled “Multi-Provider Configuration”Multiple Providers
Section titled “Multiple Providers”# AWS Providerprovider "aws" { alias = "aws_primary" region = "us-east-1"}
provider "aws" { alias = "aws_secondary" region = "us-west-2"}
# Azure Providerprovider "azurerm" { alias = "primary" subscription_id = var.azure_subscription_id tenant_id = var.azure_tenant_id features {}}
# GCP Providerprovider "google" { alias = "primary" project = var.gcp_project region = "us-central1"}Using Providers in Resources
Section titled “Using Providers in Resources”# AWS resourcesresource "aws_instance" "primary" { provider = aws.aws_primary ami = var.aws_ami # ...}
resource "aws_instance" "secondary" { provider = aws.aws_secondary ami = var.aws_ami # ...}
# Azure resourcesresource "azurerm_virtual_machine" "primary" { provider = azurerm.primary # ...}
# GCP resourcesresource "google_compute_instance" "primary" { provider = google.primary # ...}Abstraction with Modules
Section titled “Abstraction with Modules”Multi-Cloud Module Structure
Section titled “Multi-Cloud Module Structure”modules/├── compute/│ ├── main.tf # Abstract compute logic│ ├── variables.tf # Provider-agnostic variables│ ├── outputs.tf│ └── versions.tf# Use conditional logic for provider-agnostic resources
resource "aws_instance" "compute" { count = var.provider == "aws" ? var.instance_count : 0 ami = var.aws_ami instance_type = var.instance_type # AWS-specific config}
resource "azurerm_linux_virtual_machine" "compute" { count = var.provider == "azure" ? var.instance_count : 0 admin_username = var.admin_username size = var.azure_vm_size # Azure-specific config}
resource "google_compute_instance" "compute" { count = var.provider == "gcp" ? var.instance_count : 0 machine_type = var.instance_type boot_disk { initialize_params { image = var.gcp_image } } # GCP-specific config}variable "provider" { description = "Cloud provider: aws, azure, or gcp" type = string default = "aws"}
variable "instance_count" { description = "Number of instances" type = number default = 1}
variable "instance_type" { description = "Instance type" type = string default = "t3.micro"}
variable "aws_ami" { description = "AWS AMI ID" type = string default = ""}
variable "azure_vm_size" { description = "Azure VM size" type = string default = "Standard_B1s"}
variable "gcp_image" { description = "GCP image" type = string default = "debian-11"}Cross-Cloud Networking
Section titled “Cross-Cloud Networking”AWS VPC Peering
Section titled “AWS VPC Peering”# Cross-AWS VPC peeringresource "aws_vpc" "primary" { provider = aws.aws_primary cidr_block = "10.1.0.0/16"}
resource "aws_vpc" "secondary" { provider = aws.aws_secondary cidr_block = "10.2.0.0/16"}
resource "aws_vpc_peering_connection" "primary_to_secondary" { provider = aws.aws_primary vpc_id = aws_vpc.primary.id peer_vpc_id = aws_vpc.secondary.id peer_region = "us-west-2" auto_accept = true}
resource "aws_route" "primary_routes" { provider = aws.aws_primary route_table_id = aws_vpc.primary.default_route_table_id destination_cidr_block = aws_vpc.secondary.cidr_block vpc_peering_connection_id = aws_vpc_peering_connection.primary_to_secondary.id}AWS to Azure (Using Transit Gateway)
Section titled “AWS to Azure (Using Transit Gateway)”# AWS Transit Gatewayresource "aws_ec2_transit_gateway" "main" { provider = aws.aws_primary amazon_asn = 64512 description = "Main Transit Gateway" default_route_table_association = "enable" default_route_table_propagation = "enable"}
# Azure Virtual Hub (requires azurerm provider)resource "azurerm_virtual_hub" "main" { provider = azurerm.primary name = "main-hub" resource_group_name = azurerm_resource_group.network.name location = azurerm_resource_group.network.location address_prefix = "172.16.0.0/23"}
# Note: Cross-cloud connectivity typically requires:# - Cloud Exchange (Equinix, Megaport)# - AWS Direct Connect + Azure ExpressRoute# - VPN tunnelsData Sources for Multi-Cloud
Section titled “Data Sources for Multi-Cloud”AWS Data
Section titled “AWS Data”data "aws_ami" "ubuntu" { provider = aws.aws_primary most_recent = true owners = ["099720109477"] # Canonical
filter { name = "name" values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-*-amd64-server-*"] }}Azure Data
Section titled “Azure Data”data "azurerm_subscription" "primary" { provider = azurerm.primary}
data "azurerm_image" "ubuntu" { provider = azurerm.primary name = "ubuntu-2204" resource_group_name = "images-rg"}GCP Data
Section titled “GCP Data”data "google_compute_image" "ubuntu" { provider = google.primary project = "ubuntu-os-cloud" family = "ubuntu-2204-lts"}Secrets Management
Section titled “Secrets Management”AWS Secrets Manager
Section titled “AWS Secrets Manager”data "aws_secretsmanager_secret_version" "db_creds" { provider = aws.aws_primary secret_id = "prod/database/credentials"}
locals { db_creds = jsondecode(data.aws_secretsmanager_secret_version.db_creds.secret_string)}Azure Key Vault
Section titled “Azure Key Vault”data "azurerm_key_vault" "main" { provider = azurerm.primary name = "main-kv" resource_group_name = "security-rg"}
data "azurerm_key_vault_secret" "db_password" { provider = azurerm.primary name = "db-password" key_vault_id = data.azurerm_key_vault.main.id}GCP Secret Manager
Section titled “GCP Secret Manager”data "google_secret_manager_secret_version" "db_creds" { provider = google.primary secret = "prod-database-credentials"}Cost Management
Section titled “Cost Management”Cost Estimation
Section titled “Cost Estimation”# Use Infracost for cost estimation# See terraform_testing.md for details
# Or use provider cost calculatorsdata "aws_ec2_instance_type" "example" { provider = aws.aws_primary instance_type = "t3.micro"}
output "hourly_cost" { value = data.aws_ec2_instance_type.example.price_hourly}Best Practices
Section titled “Best Practices”1. Use Abstraction Layers
Section titled “1. Use Abstraction Layers”# Don't mix cloud-specific resources in main configs# Use modules that abstract cloud differences
module "compute" { source = "./modules/compute" provider = var.cloud_provider # ... provider-agnostic inputs}2. Use workspaces or environments
Section titled “2. Use workspaces or environments”environments/├── dev/│ ├── main.tf│ └── terragrunt.hcl├── staging/│ └── ...└── prod/ └── ...3. Tag consistently
Section titled “3. Tag consistently”locals { common_tags = { Environment = var.environment ManagedBy = "Terraform" Project = var.project_name CostCenter = var.cost_center }}
resource "aws_instance" "example" { # ... tags = local.common_tags}4. Use remote state for cross-cloud references
Section titled “4. Use remote state for cross-cloud references”# Store outputs in shared state bucketterraform { backend "s3" { bucket = "terraform-multi-cloud-state" key = "networking/terraform.tfstate" }}CI/CD for Multi-Cloud
Section titled “CI/CD for Multi-Cloud”# GitHub Actionsjobs: validate: runs-on: ubuntu-latest strategy: matrix: cloud: [aws, azure, gcp] steps: - uses: actions/checkout@v3 - name: Validate ${{ matrix.cloud }} run: | terraform init -backend=false terraform validateSummary
Section titled “Summary”Multi-cloud with Terraform enables:
- Vendor independence: Avoid lock-in
- Best-of-breed: Use optimal services
- Resilience: Cross-cloud redundancy
- Compliance: Data residency requirements
- Cost optimization: Leverage pricing
Key patterns:
- Abstraction: Provider-agnostic modules
- Consistent tagging: Cross-cloud resource organization
- Centralized state: Shared state management
- Secrets management: Cross-cloud secrets
- Unified networking: Cross-cloud connectivity