← Back to Terraform

Multi-Cloud Orchestration with Terraform

Deploy and manage resources simultaneously across AWS, GCP, Azure with unified infrastructure code and cross-cloud networking.

Overview

Terraform's multi-cloud provider system enables deploying applications across multiple cloud platforms using a single configuration language. This provides cloud portability, cost optimization through cloud provider selection, and disaster recovery capabilities.

Multi-Provider Configuration

HCL - main.tf with AWS, GCP, Azure
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    google = {
      source  = "hashicorp/google"
      version = "~> 5.0"
    }
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.0"
    }
  }
}

provider "aws" {
  region = var.aws_region
}

provider "google" {
  project = var.gcp_project
  region  = var.gcp_region
}

provider "azurerm" {
  features {}
  subscription_id = var.azure_subscription_id
}

# Application hosted across clouds
locals {
  cloud_regions = {
    aws = {
      region        = var.aws_region
      instance_type = "t3.medium"
      count         = 2
    }
    gcp = {
      region       = var.gcp_region
      machine_type = "e2-standard-2"
      count        = 2
    }
    azure = {
      region = var.azure_region
      sku    = "Standard_B2s"
      count  = 1
    }
  }
}

AWS Compute Resources

HCL - aws-resources.tf
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name        = "multi-cloud-vpc"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

resource "aws_subnet" "main" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "${var.aws_region}a"
}

resource "aws_instance" "app" {
  count                       = local.cloud_regions.aws.count
  ami                         = data.aws_ami.ubuntu.id
  instance_type               = local.cloud_regions.aws.instance_type
  subnet_id                   = aws_subnet.main.id
  associate_public_ip_address = true

  user_data = base64encode(templatefile("${path.module}/user-data.sh", {
    environment = var.environment
    cloud       = "aws"
  }))

  tags = {
    Name  = "app-server-aws-${count.index}"
    Cloud = "aws"
  }
}

resource "aws_load_balancer" "main" {
  name            = "multi-cloud-alb"
  load_balancer_type = "application"
  subnets         = [aws_subnet.main.id]

  tags = {
    Name = "app-load-balancer"
  }
}

data "aws_ami" "ubuntu" {
  most_recent = true
  owners      = ["099720109477"]

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
  }
}

GCP Compute Resources

HCL - gcp-resources.tf
resource "google_compute_network" "main" {
  name                    = "multi-cloud-network"
  auto_create_subnetworks = false
}

resource "google_compute_subnetwork" "main" {
  name          = "multi-cloud-subnet"
  ip_cidr_range = "10.1.0.0/24"
  region        = local.cloud_regions.gcp.region
  network       = google_compute_network.main.id
}

resource "google_compute_instance" "app" {
  count        = local.cloud_regions.gcp.count
  name         = "app-server-gcp-${count.index}"
  machine_type = local.cloud_regions.gcp.machine_type
  zone         = "${local.cloud_regions.gcp.region}-a"

  boot_disk {
    initialize_params {
      image = "ubuntu-os-cloud/ubuntu-2204-lts"
      size  = 30
    }
  }

  network_interface {
    network    = google_compute_network.main.name
    subnetwork = google_compute_subnetwork.main.name
  }

  metadata_startup_script = file("${path.module}/user-data.sh")

  labels = {
    cloud       = "gcp"
    environment = var.environment
  }
}

resource "google_compute_backend_service" "main" {
  name      = "app-backend-service"
  protocol  = "HTTP"
  port_name = "http"

  health_checks = [google_compute_health_check.main.id]
}

resource "google_compute_health_check" "main" {
  name = "app-health-check"

  http_health_check {
    port = 8080
  }
}

Azure Compute Resources

HCL - azure-resources.tf
resource "azurerm_resource_group" "main" {
  name     = "multi-cloud-rg"
  location = local.cloud_regions.azure.region
}

resource "azurerm_virtual_network" "main" {
  name                = "multi-cloud-vnet"
  address_space       = ["10.2.0.0/16"]
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
}

resource "azurerm_subnet" "main" {
  name                 = "multi-cloud-subnet"
  resource_group_name  = azurerm_resource_group.main.name
  virtual_network_name = azurerm_virtual_network.main.name
  address_prefixes     = ["10.2.1.0/24"]
}

resource "azurerm_network_interface" "main" {
  count               = local.cloud_regions.azure.count
  name                = "nic-${count.index}"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name

  ip_configuration {
    name                          = "testConfiguration"
    subnet_id                     = azurerm_subnet.main.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.main[count.index].id
  }
}

resource "azurerm_virtual_machine" "main" {
  count               = local.cloud_regions.azure.count
  name                = "app-server-azure-${count.index}"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  vm_size             = local.cloud_regions.azure.sku

  network_interface_ids = [azurerm_network_interface.main[count.index].id]

  os_profile {
    computer_name  = "app-${count.index}"
    admin_username = "azureuser"
  }

  os_profile_linux_config {
    disable_password_authentication = true
    ssh_keys {
      path     = "/home/azureuser/.ssh/authorized_keys"
      key_data = file("~/.ssh/id_rsa.pub")
    }
  }

  storage_os_disk {
    name              = "disk-${count.index}"
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Premium_LRS"
  }
}

Cross-Cloud Networking with VPC Peering

HCL - network-peering.tf
# VPC Peering between GCP and AWS (via interconnect)
resource "google_compute_network_peering" "gcp_aws" {
  name         = "gcp-aws-peering"
  network      = google_compute_network.main.self_link
  peer_network = aws_vpc.main.arn

  depends_on = [
    google_compute_network.main,
    aws_vpc.main
  ]
}

# Firewall rules for multi-cloud traffic
resource "google_compute_firewall" "multi_cloud" {
  name    = "allow-multi-cloud"
  network = google_compute_network.main.name

  allow {
    protocol = "tcp"
    ports    = ["80", "443", "3306", "5432"]
  }

  source_ranges = [
    aws_vpc.main.cidr_block,
    azurerm_virtual_network.main.address_space[0]
  ]
}

# AWS Security Group for cross-cloud access
resource "aws_security_group" "multi_cloud" {
  name   = "multi-cloud-sg"
  vpc_id = aws_vpc.main.id

  ingress {
    from_port   = 0
    to_port     = 65535
    protocol    = "tcp"
    cidr_blocks = [
      google_compute_network.main.routing_config[0].bgp_asn,
      azurerm_virtual_network.main.address_space[0]
    ]
  }
}

# Azure Network Security Group
resource "azurerm_network_security_group" "multi_cloud" {
  name                = "multi-cloud-nsg"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name

  security_rule {
    name                       = "allow-multi-cloud"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "*"
    source_address_prefixes    = [
      aws_vpc.main.cidr_block,
      "10.1.0.0/16"
    ]
    destination_address_prefix = "*"
  }
}

Unified Load Balancing

HCL - load-balancing.tf
resource "google_compute_global_forwarding_rule" "multi_cloud" {
  name       = "app-global-forwarding-rule"
  ip_version = "IPV4"
  port_range = "80,443"
  target     = google_compute_target_https_proxy.main.self_link
}

resource "google_compute_backend_service" "multi_cloud" {
  name            = "app-multi-cloud-backend"
  protocol        = "HTTP"
  session_affinity = "NONE"
  timeout_sec     = 30

  # GCP backends
  backend {
    group = google_compute_instance_group_manager.main.instance_group
  }

  health_checks = [google_compute_health_check.main.id]
}

# Global load balancing config
resource "aws_route53_zone" "main" {
  name = "app.example.com"
}

resource "aws_route53_record" "multi_cloud" {
  zone_id = aws_route53_zone.main.zone_id
  name    = "app.example.com"
  type    = "A"

  set_identifier = "multi-cloud"

  failover_routing_policy {
    type = "PRIMARY"
  }

  alias {
    name                   = aws_load_balancer.main.dns_name
    zone_id                = aws_load_balancer.main.zone_id
    evaluate_target_health = true
  }
}

Outputs and Service Discovery

HCL - outputs.tf
output "multi_cloud_endpoints" {
  value = {
    aws_load_balancer_dns = aws_load_balancer.main.dns_name
    gcp_load_balancer_ip  = google_compute_global_address.main.address
    azure_app_gateway_fqdn = azurerm_application_gateway.main.fqdn
  }
  description = "Endpoints for multi-cloud application"
}

output "aws_instances" {
  value = {
    for instance in aws_instance.app :
    instance.id => instance.public_ip
  }
}

output "gcp_instances" {
  value = {
    for instance in google_compute_instance.app :
    instance.name => instance.network_interface[0].access_config[0].nat_ip
  }
}

output "azure_instances" {
  value = {
    for idx, public_ip in azurerm_public_ip.main :
    idx => public_ip.ip_address
  }
}

Best Practices