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
- Use provider aliases to manage multiple regions or accounts
- Abstract cloud-specific resources using modules
- Implement consistent naming conventions across clouds
- Use workspace outputs for service discovery
- Configure cross-cloud networking securely with VPN/Interconnect
- Implement cloud-agnostic DNS for global load balancing
- Use condition logic to control cloud-specific deployments
- Establish comprehensive monitoring across all clouds
- Test failover scenarios between cloud providers
- Maintain separate state files per cloud for isolation